diff --git a/.gitignore b/.gitignore index 0763a1144..db39bcd3c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,8 @@ bld/ cmake-build/* !cmake-build/placeholder.txt cmake-build-*/* +rocketui/cmake-build-*/* +scaleformui/cmake-build-*/* #Ignore rebuilt static libs lib/public/linux64/*.a @@ -41,4 +43,8 @@ external/crypto++-5.61/*.o external/crypto++-5.61/libcryptopp.a #VPC makefile -csgo_partner.mak \ No newline at end of file +csgo_partner.mak + +#Thirdparty +/thirdparty/RmlUi/build/ +/thirdparty/RmlUi/Samples/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 010face54..0c0da6cb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,4 +78,5 @@ add_subdirectory(matchmaking) #Does all 4 matchmaking projects add_subdirectory(launcher_main) #The actual executable that just dlopen's launcher add_subdirectory(launcher) -add_subdirectory(scaleformui) #DUMMY cmake project so CLion can do analysis \ No newline at end of file +add_subdirectory(scaleformui) #DUMMY cmake project so CLion can do analysis +add_subdirectory(rocketui) #DUMMY cmake project so CLion can do analysis \ No newline at end of file diff --git a/appframework/sdlmgr.cpp b/appframework/sdlmgr.cpp index b654f28f1..7cddd8942 100644 --- a/appframework/sdlmgr.cpp +++ b/appframework/sdlmgr.cpp @@ -328,8 +328,8 @@ class CSDLMgr : public ILauncherMgr int m_MouseButtonDownY; #if WITH_OVERLAY_CURSOR_VISIBILITY_WORKAROUND - int m_nForceCursorVisible; - int m_nForceCursorVisiblePrev; + bool m_nForceCursorVisible; + bool m_nForceCursorVisiblePrev; SDL_Cursor* m_hSystemArrowCursor; #endif @@ -530,8 +530,8 @@ InitReturnVal_t CSDLMgr::Init() m_bRawInput = false; #if WITH_OVERLAY_CURSOR_VISIBILITY_WORKAROUND - m_nForceCursorVisible = 0; - m_nForceCursorVisiblePrev = 0; + m_nForceCursorVisible = false; + m_nForceCursorVisiblePrev = false; m_hSystemArrowCursor = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_ARROW ); #endif @@ -1013,10 +1013,10 @@ void CSDLMgr::OnFrameRendered() } #if WITH_OVERLAY_CURSOR_VISIBILITY_WORKAROUND - if ( m_nForceCursorVisible > 0 ) + if ( m_nForceCursorVisible ) { // Edge case: We were just asked to force the cursor visible, so do it now. - if ( m_nForceCursorVisiblePrev == 0 ) + if ( !m_nForceCursorVisiblePrev ) { SDL_SetCursor( m_hSystemArrowCursor ); SDL_SetWindowGrab( m_Window, SDL_FALSE ); @@ -1028,10 +1028,8 @@ void CSDLMgr::OnFrameRendered() m_nForceCursorVisiblePrev = m_nForceCursorVisible; return; } - else if ( m_nForceCursorVisiblePrev > 0 ) + else if ( m_nForceCursorVisiblePrev ) { - Assert( m_nForceCursorVisible == 0 ); - // Make sure to give the normal processing a shot at putting things // back correctly. m_bSetMouseCursorCalled = true; @@ -2034,15 +2032,13 @@ void CSDLMgr::SetGammaRamp( const uint16 *pRed, const uint16 *pGreen, const uint //=============================================================================== void CSDLMgr::ForceSystemCursorVisible() { - Assert( m_nForceCursorVisible >= 0 ); - m_nForceCursorVisible += 1; + m_nForceCursorVisible = true; } //=============================================================================== void CSDLMgr::UnforceSystemCursorVisible() { - Assert( m_nForceCursorVisible >= 1 ); - m_nForceCursorVisible -= 1; + m_nForceCursorVisible = false; } #endif diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 9e6d9b9dc..9b8f08dfe 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -44,6 +44,8 @@ if( DEDICATED ) else() if( USE_SCALEFORM ) add_definitions(-DINCLUDE_SCALEFORM) + elseif( USE_ROCKETUI ) + add_definitions(-DINCLUDE_ROCKETUI) endif() endif() remove_definitions(-DBASE) #used by cryptopp REEE diff --git a/engine/gl_screen.cpp b/engine/gl_screen.cpp index 34bc01f0e..eca79a5bf 100644 --- a/engine/gl_screen.cpp +++ b/engine/gl_screen.cpp @@ -267,6 +267,8 @@ void SCR_UpdateScreen( void ) pRenderContext.GetFrom( materials ); #if defined( INCLUDE_SCALEFORM ) pRenderContext->RenderScaleformSlot(SF_RESERVED_BEGINFRAME_SLOT); +#elif defined( INCLUDE_ROCKETUI ) + //pRenderContext->BeginRocketRender(); #endif @@ -306,6 +308,10 @@ void SCR_UpdateScreen( void ) pRenderContext.GetFrom( materials ); pRenderContext->RenderScaleformSlot(SF_RESERVED_ENDFRAME_SLOT); pRenderContext.SafeRelease(); +#elif defined( INCLUDE_ROCKETUI ) + //pRenderContext.GetFrom( materials ); + //pRenderContext->EndRocketRender(); + //pRenderContext.SafeRelease(); #endif CL_TakeSnapshotAndSwap(); diff --git a/engine/host.cpp b/engine/host.cpp index 2d2a8d63a..f00ad9f94 100644 --- a/engine/host.cpp +++ b/engine/host.cpp @@ -160,6 +160,8 @@ #include "ixboxsystem.h" #if defined( INCLUDE_SCALEFORM ) #include "scaleformui/scaleformui.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "rocketui/rocketui.h" #endif extern IXboxSystem *g_pXboxSystem; @@ -4521,6 +4523,11 @@ void _Host_RunFrame (float time) g_pScaleformUI->RunFrame( ( g_ClientGlobalVariables.realtime - flLastScaleformRunFrame ) / timeScale ); flLastScaleformRunFrame = g_ClientGlobalVariables.realtime; } +#elif defined( INCLUDE_ROCKETUI ) + if ( g_pRocketUI && shouldrender ) + { + g_pRocketUI->RunFrame( g_ClientGlobalVariables.realtime ); + } #endif g_Log.RunFrame(); diff --git a/engine/keys.cpp b/engine/keys.cpp index ae2e16455..d4836111d 100644 --- a/engine/keys.cpp +++ b/engine/keys.cpp @@ -29,6 +29,8 @@ #if defined( INCLUDE_SCALEFORM ) #include "scaleformui/scaleformui.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "rocketui/rocketui.h" #endif // memdbgon must be the last include file in a .cpp file!!! @@ -46,6 +48,7 @@ enum KeyUpTarget_t KEY_UP_GAMEUI, KEY_UP_SCALEFORM, KEY_UP_OVERLAY, + KEY_UP_ROCKETUI, KEY_UP_TARGET_COUNT }; @@ -1060,6 +1063,12 @@ static bool HandleScaleformKey( const InputEvent_t &event ) return g_pScaleformUI->HandleInputEvent( event ); } +#elif defined( INCLUDE_ROCKETUI ) +// lets RocketUI get key events +static bool HandleRocketKey( const InputEvent_t &event ) +{ + return g_pRocketUI->HandleInputEvent( event ); +} #endif //----------------------------------------------------------------------------- @@ -1317,6 +1326,10 @@ void Key_Event( const InputEvent_t &event ) // scaleform goes first if ( FilterKey( event, KEY_UP_SCALEFORM, HandleScaleformKey ) ) return; +#elif defined( INCLUDE_ROCKETUI ) + // rocketui goes first + if ( FilterKey( event, KEY_UP_ROCKETUI, HandleRocketKey ) ) + return; #endif } #if defined ( CSTRIKE15 ) @@ -1326,6 +1339,12 @@ void Key_Event( const InputEvent_t &event ) if ( FilterKey( event, KEY_UP_SCALEFORM, HandleScaleformKey ) ) return; } +#elif defined( INCLUDE_ROCKETUI ) + else if ( g_ClientDLL->IsChatRaised() || g_ClientDLL->IsBindMenuRaised() ) + { + if ( FilterKey( event, KEY_UP_ROCKETUI, HandleRocketKey ) ) + return; + } #endif #endif @@ -1355,7 +1374,9 @@ void Key_Event( const InputEvent_t &event ) if ( bAllowScaleformFilter && FilterKey( event, KEY_UP_SCALEFORM, HandleScaleformKey ) ) return; - +#elif defined( INCLUDE_ROCKETUI ) + if( FilterKey( event, KEY_UP_ROCKETUI, HandleRocketKey ) ) + return; #endif // INCLUDE_SCALEFORM // Let vgui have a whack at keys diff --git a/engine/sys_dll2.cpp b/engine/sys_dll2.cpp index 329290d30..a4e0492d7 100644 --- a/engine/sys_dll2.cpp +++ b/engine/sys_dll2.cpp @@ -86,6 +86,8 @@ #if defined( INCLUDE_SCALEFORM ) #include "scaleformui/scaleformui.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "rocketui/rocketui.h" #endif #if defined(_WIN32) @@ -134,6 +136,8 @@ IPS3SaveRestoreToUI *ps3saveuiapi = NULL; #endif #if defined( INCLUDE_SCALEFORM ) IScaleformUI* g_pScaleformUI = NULL; +#elif defined( INCLUDE_ROCKETUI ) +IRocketUI* g_pRocketUI = NULL; #endif #ifndef DEDICATED @@ -560,6 +564,8 @@ bool CEngineAPI::Connect( CreateInterfaceFn factory ) #if defined( INCLUDE_SCALEFORM ) g_pScaleformUI = ( IScaleformUI* ) factory( SCALEFORMUI_INTERFACE_VERSION, NULL ); +#elif defined( INCLUDE_ROCKETUI ) + g_pRocketUI = ( IRocketUI* ) factory( ROCKETUI_INTERFACE_VERSION, NULL ); #endif if ( IsPC() && !IsPosix() ) diff --git a/engine/sys_mainwind.cpp b/engine/sys_mainwind.cpp index d031267b8..823bc72bc 100644 --- a/engine/sys_mainwind.cpp +++ b/engine/sys_mainwind.cpp @@ -69,6 +69,8 @@ #if defined( INCLUDE_SCALEFORM ) #include "scaleformui/scaleformui.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "rocketui/rocketui.h" #endif #include @@ -435,6 +437,11 @@ void CGame::DispatchInputEvent( const InputEvent_t &event ) // handling anything underneath the console if ( !vguiActive && g_pScaleformUI && g_pScaleformUI->HandleInputEvent( event ) ) break; +#elif defined( INCLUDE_ROCKETUI ) + bool vguiActive = IsPC() && cv_vguipanel_active.GetBool(); + + if ( !vguiActive && g_pRocketUI && g_pRocketUI->HandleInputEvent( event ) ) + break; #endif // INCLUDE_SCALEFORM } @@ -479,6 +486,11 @@ void CGame::DispatchInputEvent( const InputEvent_t &event ) // handling anything underneath the console if ( !vguiActive && g_pScaleformUI && g_pScaleformUI->HandleInputEvent( event ) ) break; +#elif defined( INCLUDE_ROCKETUI ) + bool vguiActive = IsPC() && cv_vguipanel_active.GetBool(); + + if ( !vguiActive && g_pRocketUI && g_pRocketUI->HandleInputEvent( event ) ) + break; #endif // INCLUDE_SCALEFORM for ( int i=0; i < ARRAYSIZE( g_GameMessageHandlers ); i++ ) diff --git a/engine/view.cpp b/engine/view.cpp index 5f18a5629..188fd5cd6 100644 --- a/engine/view.cpp +++ b/engine/view.cpp @@ -136,6 +136,8 @@ void V_RenderVGuiOnly_NoSwap() #if defined( INCLUDE_SCALEFORM ) // Render scaleform before vgui pRenderContext->AdvanceAndRenderScaleformSlot( SF_FULL_SCREEN_SLOT ); +#elif defined( INCLUDE_ROCKETUI ) + pRenderContext->RenderRocketMenu(); #endif EngineVGui()->Paint( PAINT_UIPANELS ); @@ -156,11 +158,15 @@ void V_RenderVGuiOnly( void ) { materials->BeginFrame( host_frametime ); -#if defined( INCLUDE_SCALEFORM ) CMatRenderContextPtr pRenderContext; +#if defined( INCLUDE_SCALEFORM ) pRenderContext.GetFrom( materials ); pRenderContext->RenderScaleformSlot(SF_RESERVED_BEGINFRAME_SLOT); pRenderContext.SafeRelease(); +#elif defined( INCLUDE_ROCKETUI ) + //pRenderContext.GetFrom( materials ); + //pRenderContext->BeginRocketRender(); + //pRenderContext.SafeRelease(); #endif EngineVGui()->Simulate(); @@ -179,6 +185,10 @@ void V_RenderVGuiOnly( void ) pRenderContext.GetFrom( materials ); pRenderContext->RenderScaleformSlot(SF_RESERVED_ENDFRAME_SLOT); pRenderContext.SafeRelease(); +#elif defined( INCLUDE_ROCKETUI ) + //pRenderContext.GetFrom( materials ); + //pRenderContext->EndRocketRender(); + //pRenderContext.SafeRelease(); #endif materials->EndFrame(); diff --git a/game/client/CMakeLists.txt b/game/client/CMakeLists.txt index 20a0f1d72..12472fae2 100644 --- a/game/client/CMakeLists.txt +++ b/game/client/CMakeLists.txt @@ -16,6 +16,8 @@ set(CSGO "1") add_definitions(-DCSTRIKE_CLIENT_DLL -DCSTRIKE_DLL -DGAMEUI_EMBEDDED -DGAMEUI_EXPORTS -DVERSION_SAFE_STEAM_API_INTERFACES -DUSE_ECONOMY_FEATURES) if( USE_SCALEFORM ) add_definitions(-DINCLUDE_SCALEFORM) +elseif( USE_ROCKETUI ) + add_definitions(-DINCLUDE_ROCKETUI) endif() add_definitions(-DALLOW_TEXT_MODE=1) @@ -327,6 +329,18 @@ if( USE_SCALEFORM ) target_sources(${OUTBINNAME} PRIVATE "cstrike15/Scaleform/loadingscreen_scaleform.cpp") target_sources(${OUTBINNAME} PRIVATE "cstrike15/Scaleform/splitscreensignon.cpp") #} +elseif( USE_ROCKETUI ) + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkmenu_main.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_chat.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_pausemenu.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_teammenu.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_loadingscreen.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_infobar.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_scoreboard.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_roundtimer.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_killfeed.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_buymenu.cpp") + target_sources(${OUTBINNAME} PRIVATE "cstrike15/RocketUI/rkhud_radar.cpp") endif() #$Folder "vgui" @@ -347,6 +361,9 @@ if( WINDOWS OR POSIX ) target_link_libraries(${OUTBINNAME} ${LIBCOMMON}/jpeglib_client.a) #Link with Mysterious jpeglib. This can probably be built ourselves later. target_link_libraries(${OUTBINNAME} vpklib_client) endif() +if( USE_ROCKETUI ) + target_link_libraries(${OUTBINNAME} ${SRCDIR}/thirdparty/RmlUi/build/libRmlCore.so) +endif() target_link_libraries(${OUTBINNAME} matsys_controls_client) target_link_libraries(${OUTBINNAME} ${LIBPUBLIC}/libsteam_api.so) #proprietary steam api target_link_libraries(${OUTBINNAME} ${LIBPUBLIC}/gcsdk_client.a) #evil game coordinator voodoo diff --git a/game/client/c_playerresource.cpp b/game/client/c_playerresource.cpp index 154ee17fc..e3c994ab5 100644 --- a/game/client/c_playerresource.cpp +++ b/game/client/c_playerresource.cpp @@ -97,6 +97,8 @@ C_PlayerResource::C_PlayerResource() g_PR = this; #if defined ( INCLUDE_SCALEFORM ) g_pScaleformUI->AddDeviceDependentObject( this ); +#elif defined ( INCLUDE_ROCKETUI ) + g_pRocketUI->AddDeviceDependentObject( this ); #endif } @@ -115,6 +117,8 @@ C_PlayerResource::~C_PlayerResource() } g_pScaleformUI->RemoveDeviceDependentObject( this ); +#elif defined( INCLUDE_ROCKETUI ) + g_pRocketUI->RemoveDeviceDependentObject( this ); #endif g_PR = NULL; } diff --git a/game/client/cdll_client_int.cpp b/game/client/cdll_client_int.cpp index 58b1a82b1..4205c9d50 100644 --- a/game/client/cdll_client_int.cpp +++ b/game/client/cdll_client_int.cpp @@ -168,6 +168,9 @@ #include "Scaleform/options_scaleform.h" #include "Scaleform/loadingscreen_scaleform.h" #include "Scaleform/HUD/sfhud_deathnotice.h" + #elif defined( INCLUDE_ROCKETUI ) + #include "RocketUI/rkhud_chat.h" + #include "RocketUI/rkhud_loadingscreen.h" #endif #endif @@ -260,6 +263,8 @@ IRenderToRTHelper *g_pRenderToRTHelper = NULL; #if defined( INCLUDE_SCALEFORM ) IScaleformUI* g_pScaleformUI = NULL; +#elif defined( INCLUDE_ROCKETUI ) +IRocketUI* g_pRocketUI = NULL; #endif IUploadGameStats *gamestatsuploader = NULL; @@ -1416,6 +1421,8 @@ int CHLClient::Connect( CreateInterfaceFn appSystemFactory, CGlobalVarsBase *pGl #if defined( INCLUDE_SCALEFORM ) g_pScaleformUI = ( IScaleformUI* ) appSystemFactory( SCALEFORMUI_INTERFACE_VERSION, NULL ); +#elif defined( INCLUDE_ROCKETUI ) + g_pRocketUI = ( IRocketUI* ) appSystemFactory( ROCKETUI_INTERFACE_VERSION, NULL ); #endif #ifndef NO_STEAM @@ -4214,6 +4221,12 @@ bool CHLClient::IsChatRaised( void ) { return pChat->ChatRaised(); } +#elif defined( INCLUDE_ROCKETUI ) + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + return false; + + return pChat->ChatRaised(); #else return false; #endif @@ -4246,6 +4259,7 @@ bool CHLClient::IsBindMenuRaised( void ) return false; } +//rocketui note: This is only used in keys.cpp for scaleform bool CHLClient::IsTeamMenuRaised( void ) { if ( !GetViewPortInterface() ) @@ -4262,6 +4276,7 @@ bool CHLClient::IsTeamMenuRaised( void ) return false; } +//rocketui note: This is only used in keys.cpp for scaleform bool CHLClient::IsLoadingScreenRaised( void ) { #if defined( INCLUDE_SCALEFORM ) diff --git a/game/client/cdll_client_int.h b/game/client/cdll_client_int.h index 80b0c628d..7972045df 100644 --- a/game/client/cdll_client_int.h +++ b/game/client/cdll_client_int.h @@ -22,6 +22,8 @@ #if defined( INCLUDE_SCALEFORM ) #include "scaleformui/scaleformui.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "rocketui/rocketui.h" #endif class IVModelRender; @@ -111,6 +113,8 @@ extern IP4 *p4; #if defined( INCLUDE_SCALEFORM ) extern IScaleformUI* g_pScaleformUI; +#elif defined( INCLUDE_ROCKETUI ) +extern IRocketUI* g_pRocketUI; #endif #ifdef INFESTED_DLL diff --git a/game/client/clientmode_shared.cpp b/game/client/clientmode_shared.cpp index 8918e1c7a..e59b172c7 100644 --- a/game/client/clientmode_shared.cpp +++ b/game/client/clientmode_shared.cpp @@ -32,6 +32,8 @@ #include "Scaleform/HUD/sfhudfreezepanel.h" #include "Scaleform/HUD/sfhud_teamcounter.h" #include "Scaleform/mapoverview.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "RocketUI/rkhud_chat.h" #endif #include "hltvreplaysystem.h" #include "netmessages.h" @@ -763,6 +765,10 @@ void ClientModeShared::StartMessageMode( int iMessageModeType ) { pChat->StartMessageMode( iMessageModeType ); } +#elif defined( INCLUDE_ROCKETUI ) + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( pChat ) + pChat->StartMessageMode( iMessageModeType ); #endif } diff --git a/game/client/cstrike15/RocketUI/rkhud_buymenu.cpp b/game/client/cstrike15/RocketUI/rkhud_buymenu.cpp new file mode 100644 index 000000000..39827566e --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_buymenu.cpp @@ -0,0 +1,345 @@ +#include "rkhud_buymenu.h" + +#include "cbase.h" +#include "hud_macros.h" +#include "c_cs_player.h" + +#include // included to fix an error with min/max and rocketui +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +DECLARE_HUDELEMENT( RkHudBuyMenu ); + +struct ItemListEntry +{ + Rml::String itemName; + int itemPrice; +}; + +// struct layout for data-binding model. +struct BuyMenuData +{ + int playerCash; + int playerTeamNum; + int buyTimeLeft; // seconds + Rml::Vector gearList; + Rml::Vector grenadeList; + Rml::Vector pistolList; + Rml::Vector rifleList; + Rml::Vector smgList; + Rml::Vector heavyList; +} buyMenuData; + +class RkBuyMenuListener : public Rml::EventListener +{ +public: + void ProcessEvent(Rml::Event &keyevent) override + { + Rml::EventId eventType = keyevent.GetId(); + + RkHudBuyMenu *pBuyMenu = GET_HUDELEMENT( RkHudBuyMenu ); + if( !pBuyMenu ) + return; + + if( eventType == Rml::EventId::Keyup ) + { + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + IGameEvent *pEvent = gameeventmanager->CreateEvent( "buymenu_close" ); + if ( localPlayer && pEvent ) + { + pEvent->SetInt("userid", localPlayer->GetUserID() ); + gameeventmanager->FireEventClientSide( pEvent ); + } + } + else if( eventType == Rml::EventId::Mousedown ) + { + const Rml::Element *target = keyevent.GetTargetElement(); + if( target->IsClassSet( "item" ) ) + { + // for some reason this shit wont work with "weapon_ak47", just "ak47" + char buyBuffer[512]; + V_snprintf( buyBuffer, sizeof( buyBuffer ), "buy %s", ( V_strstr( target->GetChild(2)->GetInnerRML().c_str(), "_" ) + 1 ) ); + DevMsg("buying [%s]\n", buyBuffer ); + engine->ExecuteClientCmd( buyBuffer ); + pBuyMenu->UpdateBuyMenu(); + } + } + } +}; + +static RkBuyMenuListener buyMenuListener; + +// Updates the buy menu options via the game's weapon database. +// Called sparingly when buymenu is opened/interacted. +void RkHudBuyMenu::UpdateBuyMenu() +{ + C_CSPlayer *localPlayer = C_CSPlayer::GetLocalCSPlayer(); + if( !localPlayer ) + return; + + buyMenuData.gearList.clear(); + buyMenuData.grenadeList.clear(); + buyMenuData.pistolList.clear(); + buyMenuData.rifleList.clear(); + buyMenuData.smgList.clear(); + buyMenuData.heavyList.clear(); + + for( int i = WEAPON_FIRST ; i < WEAPON_MAX; i++ ) + { + if( localPlayer->CanAcquire( (CSWeaponID)i, AcquireMethod::Buy ) != AcquireResult::Allowed ) + continue; + + const CCSWeaponInfo* info = GetWeaponInfo( (CSWeaponID)i ); + if( !info ) + continue; + + ItemListEntry entry; + entry.itemPrice = info->GetWeaponPrice(); + entry.itemName = WeaponIdAsString( (CSWeaponID)i ); + + int weaponType = info->GetWeaponType(); + + switch( weaponType ) + { + case WEAPONTYPE_EQUIPMENT: + buyMenuData.gearList.push_back( entry ); + break; + case WEAPONTYPE_GRENADE: + buyMenuData.grenadeList.push_back( entry ); + break; + case WEAPONTYPE_PISTOL: + buyMenuData.pistolList.push_back( entry ); + break; + case WEAPONTYPE_RIFLE: + case WEAPONTYPE_SNIPER_RIFLE: + buyMenuData.rifleList.push_back( entry ); + break; + case WEAPONTYPE_SUBMACHINEGUN: + buyMenuData.smgList.push_back( entry ); + break; + case WEAPONTYPE_SHOTGUN: + case WEAPONTYPE_MACHINEGUN: + buyMenuData.heavyList.push_back( entry ); + break; + default: + { + continue; + } + } + } + + m_dataModel.DirtyVariable( "gear_list" ); + m_dataModel.DirtyVariable( "grenade_list" ); + m_dataModel.DirtyVariable( "pistol_list" ); + m_dataModel.DirtyVariable( "rifle_list" ); + m_dataModel.DirtyVariable( "smg_list" ); + m_dataModel.DirtyVariable( "heavy_list" ); + + m_dataModel.Update(); +} + +// called 1x per frame +void RkHudBuyMenu::OnNewFrameBuyMenu() +{ + float timeIntoRound = CSGameRules()->GetRoundElapsedTime(); + float buyTime = CSGameRules()->GetBuyTimeLength(); + + buyMenuData.buyTimeLeft = int(buyTime - timeIntoRound); + + C_CSPlayer *localPlayer = C_CSPlayer::GetLocalCSPlayer(); + if( localPlayer ) + { + buyMenuData.playerCash = localPlayer->GetAccount(); + buyMenuData.playerTeamNum = localPlayer->GetTeamNumber(); + m_dataModel.DirtyVariable( "player_cash" ); + m_dataModel.DirtyVariable( "player_teamnum" ); + } + + m_dataModel.DirtyVariable("buy_time_left"); + + m_dataModel.Update(); +} + +static void UnloadRkBuyMenu() +{ + RkHudBuyMenu *pBuyMenu = GET_HUDELEMENT( RkHudBuyMenu ); + if( !pBuyMenu ) + { + Warning( "Couldn't grab RkBuyMenu to unload!\n" ); + return; + } + + if( !pBuyMenu->m_pInstance ) + return; + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( hudCtx ) + { + hudCtx->RemoveDataModel( "buymenu_model" ); + pBuyMenu->m_dataModel = nullptr; + } + else + { + Warning( "Couldn't access hudctx to unload buymenu datamodel!\n" ); + } + + pBuyMenu->m_pInstance->RemoveEventListener( Rml::EventId::Mousedown, &buyMenuListener ); + pBuyMenu->m_pInstance->RemoveEventListener( Rml::EventId::Keyup, &buyMenuListener ); + pBuyMenu->m_pInstance->Close(); + pBuyMenu->m_pInstance = nullptr; + pBuyMenu->m_bVisible = false; + + if( pBuyMenu->m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( false, "BuyMenu" ); + pBuyMenu->m_bGrabbingInput = false; + } +} + +static void LoadRkBuyMenu() +{ + RkHudBuyMenu *pBuyMenu = GET_HUDELEMENT( RkHudBuyMenu ); + if( !pBuyMenu ) + { + Warning( "Couldn't grab hud buymenu to load!\n" ); + return; + } + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( !hudCtx ) + { + Error( "Couldn't access hudctx!\n" ); + /* Exit */ + } + + if( pBuyMenu->m_pInstance || pBuyMenu->m_dataModel ) + { + Warning( "RkBuyMenu already loaded! call unload first!\n" ); + return; + } + + // Create the data binding, this will sync data between rocketui and the game. + Rml::DataModelConstructor constructor = hudCtx->CreateDataModel( "buymenu_model" ); + if( !constructor ) + { + Error( "Couldn't create datamodel for buymenu!\n" ); + /* Exit */ + } + + // Register ItemListEntry struct + if( auto itemlist_handle = constructor.RegisterStruct() ) + { + itemlist_handle.RegisterMember( "item_name", &ItemListEntry::itemName ); + itemlist_handle.RegisterMember( "item_price", &ItemListEntry::itemPrice ); + } + + // Register the array type + constructor.RegisterArray>(); + + // Bind the Lists of items + constructor.Bind( "gear_list", &buyMenuData.gearList ); + constructor.Bind( "grenade_list", &buyMenuData.grenadeList ); + constructor.Bind( "pistol_list", &buyMenuData.pistolList ); + constructor.Bind( "rifle_list", &buyMenuData.rifleList ); + constructor.Bind( "smg_list", &buyMenuData.smgList ); + constructor.Bind( "heavy_list", &buyMenuData.heavyList ); + + // Bind regular data + constructor.Bind( "player_cash", &buyMenuData.playerCash ); + constructor.Bind( "player_teamnum", &buyMenuData.playerTeamNum ); + constructor.Bind( "buy_time_left", &buyMenuData.buyTimeLeft ); + + pBuyMenu->m_dataModel = constructor.GetModelHandle(); + + // Load document from file. + pBuyMenu->m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_buymenu.rml", &LoadRkBuyMenu, &UnloadRkBuyMenu ); + if( !pBuyMenu->m_pInstance ) + { + Error( "Couldn't create hud_buymenu document!\n" ); + /* Exit */ + } + + // Add event listener for input + pBuyMenu->m_pInstance->AddEventListener( Rml::EventId::Mousedown, &buyMenuListener ); + pBuyMenu->m_pInstance->AddEventListener( Rml::EventId::Keyup, &buyMenuListener ); +} + +RkHudBuyMenu::RkHudBuyMenu(const char *value) : CHudElement( value ), +m_bVisible( false ), m_bGrabbingInput( false ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +RkHudBuyMenu::~RkHudBuyMenu() noexcept +{ + StopListeningForAllEvents(); + + UnloadRkBuyMenu(); +} + +void RkHudBuyMenu::LevelInit() +{ + ListenForGameEvent( "buymenu_open" ); + ListenForGameEvent( "buymenu_close" ); + + LoadRkBuyMenu(); +} + +void RkHudBuyMenu::LevelShutdown() +{ + UnloadRkBuyMenu(); +} + +void RkHudBuyMenu::ShowPanel(bool bShow, bool force) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + if( !m_bVisible ) + { + UpdateBuyMenu(); + RocketUI()->DenyInputToGame( true, "BuyMenu" ); + m_pInstance->Show(); + } + OnNewFrameBuyMenu(); + } + else + { + if( m_bVisible ) + { + RocketUI()->DenyInputToGame( false, "BuyMenu" ); + m_pInstance->Hide(); + } + } + + m_bVisible = bShow; +} + +void RkHudBuyMenu::SetActive(bool bActive) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudBuyMenu::ShouldDraw() +{ + // This element is opened/closed by clientside events + // that we listen for and set m_bVisible manually via showpanel(true) + + return cl_drawhud.GetBool() && CSGameRules() && !CSGameRules()->IsBuyTimeElapsed() && m_bVisible && CHudElement::ShouldDraw(); +} + +void RkHudBuyMenu::FireGameEvent(IGameEvent *event) +{ + const char *type = event->GetName(); + + if( !V_strcmp( "buymenu_open", type ) ) + { + ShowPanel( true, false ); + } + else if( !V_strcmp( "buymenu_close", type ) ) + { + ShowPanel( false, false ); + } +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_buymenu.h b/game/client/cstrike15/RocketUI/rkhud_buymenu.h new file mode 100644 index 000000000..0425ed129 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_buymenu.h @@ -0,0 +1,36 @@ +#ifndef KISAKSTRIKE_RKHUD_BUYMENU_H +#define KISAKSTRIKE_RKHUD_BUYMENU_H + +#include +#include "hudelement.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h" + +extern ConVar cl_drawhud; + +class RkHudBuyMenu : public CHudElement +{ +public: + explicit RkHudBuyMenu( const char * value ); + virtual ~RkHudBuyMenu(); + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + // CGameEventListener + virtual void FireGameEvent( IGameEvent *event ); + + Rml::ElementDocument *m_pInstance; + bool m_bVisible; + bool m_bGrabbingInput; + Rml::DataModelHandle m_dataModel; + + void UpdateBuyMenu(); + void OnNewFrameBuyMenu(); +}; + +#endif //KISAKSTRIKE_RKHUD_BUYMENU_H diff --git a/game/client/cstrike15/RocketUI/rkhud_chat.cpp b/game/client/cstrike15/RocketUI/rkhud_chat.cpp new file mode 100644 index 000000000..13e5b5edf --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_chat.cpp @@ -0,0 +1,491 @@ +#include "rkhud_chat.h" + +#include "cbase.h" +#include "cs_gamerules.h" +#include "hud_macros.h" +#include "text_message.h" +#include "c_cs_playerresource.h" + +#include // included to fix an error with min/max and rocketui + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +DECLARE_HUDELEMENT( RkHudChat ); + +ConVar rocket_hud_chat_idle_opacity( "rocket_hud_chat_idle_opacity", "0.2", 0, "The Opacity of the Chat while it is not active" ); +ConVar rocket_hud_chat_active_opacity( "rocket_hud_chat_active_opacity", "0.7", 0, "The Opacity of the Chat while typing/new message" ); +ConVar rocket_hud_chat_max_entries( "rocket_hud_chat_max_entries", "1000", 0, "Chat History Length" ); + +CON_COMMAND_F( rocket_hud_chat_clear, "Clears the Chat History", FCVAR_NONE ) +{ + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + return; + pChat->ClearChatHistory(); +} + +static bool __MsgFunc_SayText2( const CCSUsrMsg_SayText2 &msg ) +{ + int paramSize = msg.params_size(); + int entID = msg.ent_idx(); + + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + + if( !pChat ) + return true; + + // from server + if( entID == 0 && paramSize > 1 ) + { + pChat->AddChatString( nullptr, msg.params(1).c_str(), RkHudChat::SERVER ); + return true; + } + + CBasePlayer *speaker = UTIL_PlayerByIndex( entID ); + CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer( ); + + if( !speaker || !localPlayer ) + return true; + + // params(0) = Name of player + // params(1) = Message + if( paramSize > 1 ) + { + if( (speaker->GetTeamNumber() == localPlayer->GetTeamNumber()) ) + pChat->AddChatString( msg.params(0).c_str(), msg.params(1).c_str(),RkHudChat::FRIEND); + else + pChat->AddChatString( msg.params(0).c_str(), msg.params(1).c_str(),RkHudChat::FOE); + } + + return true; +} +// converts all '\r' characters to '\n', so that the engine can deal with the properly +// returns a pointer to str +static char* ConvertCRtoNL( char *str ) +{ + for ( char *ch = str; *ch != 0; ch++ ) + if ( *ch == '\r' ) + *ch = '\n'; + return str; +} + +static void NullLastNewlineFromString( char *str ) +{ + int s = strlen( str ) - 1; + if ( s >= 0 ) + { + if ( str[s] == '\n' || str[s] == '\r' ) + str[s] = 0; + } +} + +//----------------------------------------------------------------------------- +// Message handler for text messages +// displays a string, looking them up from the titles.txt file, which can be localised +// parameters: +// byte: message destination ( HUD_PRINTCONSOLE, HUD_PRINTNOTIFY, HUD_PRINTCENTER, HUD_PRINTTALK ) +// string: message +// optional parameters: +// string: message parameter 1 +// string: message parameter 2 +// string: message parameter 3 +// string: message parameter 4 +// any string that starts with the character '#' is a message name, and is used to look up the real message in titles.txt +// the next ( optional) one to four strings are parameters for that string ( which can also be message names if they begin with '#') +//----------------------------------------------------------------------------- +static bool __MsgFunc_TextMsg( const CCSUsrMsg_TextMsg &msg ) +{ + char szString[2048] = {0}; + int dest = msg.msg_dst(); + + wchar_t szBuf[5][256] = {}; + wchar_t outputBuf[256] = {}; + + if( !cl_showtextmsg.GetBool() ) + return true; + + for( int i = 0; i < 4; i++ ) + { + // Allow localizing player names + if ( const char *pszEntIndex = StringAfterPrefix( msg.params(i).c_str(), "#ENTNAME[" ) ) + { + int iEntIndex = V_atoi( pszEntIndex ); + wchar_t wszPlayerName[MAX_DECORATED_PLAYER_NAME_LENGTH] = {}; + if ( C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* ) GameResources() ) + { + pCSPR->GetDecoratedPlayerName( iEntIndex, wszPlayerName, sizeof( wszPlayerName ), ( EDecoratedPlayerNameFlag_t ) ( k_EDecoratedPlayerNameFlag_DontUseNameOfControllingPlayer | k_EDecoratedPlayerNameFlag_DontUseAssassinationTargetName ) ); + } + if ( wszPlayerName[0] ) + { + szString[0] = 0; + V_wcscpy_safe( szBuf[ i ], wszPlayerName ); + } + else if ( const char *pszEndBracket = V_strnchr( pszEntIndex, ']', 64 ) ) + { + V_strcpy_safe( szString, pszEndBracket + 1 ); + } + else + { + V_strcpy_safe( szString, msg.params(i).c_str() ); + } + } + else + { + V_strcpy_safe( szString, msg.params(i).c_str() ); + } + + if( szString[0] ) + { + char *tmpStr = hudtextmessage->LookupString( szString, &dest ); + bool bTranslated = false; + if( tmpStr[0] == '#' ) // only translate parameters intended as localization tokens + { + const wchar_t *pBuf = g_pVGuiLocalize->Find( tmpStr ); + if( pBuf ) + { + // copy pBuf into szBuf[i] + int nMaxChars = sizeof( szBuf[ i ] ) / sizeof( wchar_t ); + wcsncpy( szBuf[ i ], pBuf, nMaxChars ); + szBuf[ i ][ nMaxChars - 1 ] = 0; + bTranslated = true; + } + } + + if( !bTranslated ) + { + if( i > 0 ) + { + NullLastNewlineFromString( tmpStr ); // these strings are meant for substitution into the main strings, so cull the automatic end newlines + } + g_pVGuiLocalize->ConvertANSIToUnicode( tmpStr, szBuf[ i ], sizeof( szBuf[ i ] ) ); + } + } + } + + //TODO: right now this is just ascii + int len; + RkHudChat* pChat; + g_pVGuiLocalize->ConstructString( outputBuf, sizeof( outputBuf), szBuf[0], 4, szBuf[1], szBuf[2], szBuf[3], szBuf[4] ); + g_pVGuiLocalize->ConvertUnicodeToANSI( outputBuf, szString, sizeof( szString) ); + len = strlen( szString ); + if ( len && szString[len-1] != '\n' && szString[len-1] != '\r' ) + { + Q_strncat( szString, "\n", sizeof( szString), 1 ); + } + + switch( dest ) + { + case HUD_PRINTCENTER: + // TODO: center popup + Msg( "[center popup](%s)", ConvertCRtoNL( szString ) ); + break; + case HUD_PRINTTALK: + pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + return true; + + pChat->AddChatString( nullptr, ConvertCRtoNL( szString ), RkHudChat::SERVER ); + break; + case HUD_PRINTNOTIFY: + case HUD_PRINTCONSOLE: + Msg( "%s", ConvertCRtoNL( szString ) ); + break; + } + + return true; +} + +class RkHudChatEventListener : public Rml::EventListener +{ +public: + void ProcessEvent(Rml::Event& keyevent) override + { + char sayBuffer[1024]; + switch (keyevent.GetId()) + { + case Rml::EventId::Keydown: + { + const Rml::Dictionary& params = keyevent.GetParameters(); + Rml::Input::KeyIdentifier key_identifier = (Rml::Input::KeyIdentifier) keyevent.GetParameter< int >("key_identifier", 0); + if (key_identifier == Rml::Input::KI_ESCAPE) + { + // Close the chat. + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + break; + + pChat->StopMessageMode(); + } + else if (key_identifier == Rml::Input::KI_RETURN) + { + // Submit the Chat + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + break; + + Rml::ElementFormControl *input = static_cast(pChat->m_elemChatInput); + + V_snprintf( sayBuffer, sizeof( sayBuffer ), "%s \"%s\"", pChat->GetMessageMode() == MM_SAY ? "say" : "say_team", input->GetValue().c_str() ); + + engine->ClientCmd_Unrestricted( sayBuffer ); + input->SetValue(""); + + pChat->StopMessageMode(); + } + } + break; + + default: + break; + } + } +}; + +static RkHudChatEventListener chatEventListener; + +static void UnloadRkChat() +{ + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + { + Warning("Couldn't grab RkHudChat element to Unload\n"); + return; + } + + // Not loaded + if( !pChat->m_pInstance ) + return; + + pChat->m_pInstance->Close(); + pChat->m_pInstance = nullptr; +} + +static void LoadRkChat() +{ + RkHudChat* pChat = GET_HUDELEMENT( RkHudChat ); + if( !pChat ) + { + Warning("Couldn't grab RkHudChat element to load\n"); + return; + } + + pChat->m_pInstance = RocketUI()->LoadDocumentFileIntoHud("body", "GAME", "rocketui/hud_chat.rml", LoadRkChat, UnloadRkChat ); + + if( !pChat->m_pInstance ) + { + Error("Couldn't create hud_chat document!\n"); + /* Exit */ + } + + pChat->m_elemChatLines = pChat->m_pInstance->GetElementById( "chat_lines" ); + if( !pChat->m_elemChatLines ) + { + Error( "Couldn't find required element id: 'chat_lines' in hud_chat\n" ); + /* Exit */ + } + + pChat->m_elemChatInput = pChat->m_pInstance->GetElementById( "chat_input" ); + if( !pChat->m_elemChatInput ) + { + Error( "Couldn't find required element id: 'chat_input' in hud_chat\n" ); + /* Exit */ + } + + // Add a listener to both the Chat panel and the text-input element in case it changes focus. + pChat->m_pInstance->AddEventListener( Rml::EventId::Keydown, &chatEventListener ); + pChat->m_elemChatInput->AddEventListener( Rml::EventId::Keydown, &chatEventListener ); + + pChat->m_pInstance->Show(); +} + +// Called on program startup by a Macro with the HUD UI system +// HudElementHelper::CreateAllElements +RkHudChat::RkHudChat(const char *value) : CHudElement( value ), + m_bVisible( false ), + m_iMode( MM_NONE ), + m_bGrabbingInput( false ), + m_iNumEntries( 0 ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +RkHudChat::~RkHudChat() noexcept +{ + UnloadRkChat(); +} + +void RkHudChat::LevelInit( void ) +{ + HOOK_MESSAGE( SayText2 ); + HOOK_MESSAGE( TextMsg ); + + LoadRkChat(); +} + +void RkHudChat::LevelShutdown( void ) +{ + m_iMode = MM_NONE; + + if( m_bGrabbingInput ) + RocketUI()->DenyInputToGame( false, "Hud_Chat" ); + + UnloadRkChat(); +} + +// this is called every frame, keep that in mind. +void RkHudChat::ShowPanel(bool bShow, bool force) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + if( !m_bVisible ) + { + m_bVisible = true; + m_bGrabbingInput = true; + RocketUI()->DenyInputToGame( true, "Hud_Chat" ); + } + + m_pInstance->SetProperty( "opacity", std::to_string(rocket_hud_chat_active_opacity.GetFloat()) ); + } + else + { + if( m_bVisible ) + { + m_bVisible = false; + m_bGrabbingInput = false; + RocketUI()->DenyInputToGame( false, "Hud_Chat" ); + } + + // Do a fade out to the idle opacity level. + float currentOpacity = m_pInstance->GetProperty("opacity")->Get(); + if( currentOpacity > rocket_hud_chat_idle_opacity.GetFloat() ) + m_pInstance->SetProperty("opacity", std::to_string(currentOpacity - 0.0075f) ); + } +} + +// Called every Frame by the hudsystem if ShouldDraw() +void RkHudChat::SetActive( bool bActive ) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudChat::ShouldDraw( void ) +{ + if ( //IsTakingAFreezecamScreenshot() || + (CSGameRules() && CSGameRules()->IsPlayingTraining()) ) + return false; + + return cl_drawhud.GetBool() && (m_iMode != MM_NONE ) && CHudElement::ShouldDraw(); +} + +void RkHudChat::StartMessageMode( int mode ) +{ + // Already in chat mode. + if( ChatRaised() ) + return; + + if( GetHud().HudDisabled() ) + return; + + m_iMode = mode; + + m_elemChatInput->Focus(); +} + +void RkHudChat::StopMessageMode() +{ + m_iMode = MM_NONE; + + m_elemChatInput->Blur(); +} + +bool RkHudChat::ChatRaised() +{ + return m_iMode != MM_NONE; +} + +void RkHudChat::ClearChatHistory() +{ + if( !m_pInstance ) + return; + + Rml::ElementList chatEntries; + m_pInstance->GetElementsByClassName( chatEntries, "chat_line" ); + for( Rml::Element *elem : chatEntries ) + { + elem->GetParentNode()->RemoveChild( elem ); + } + m_iNumEntries = 0; +} + +void RkHudChat::AddChatString( const char *username, const char *message, MessageSender sender ) +{ + // Max Number of Entries, delete old ones if needed. + m_iNumEntries++; + if( m_iNumEntries > rocket_hud_chat_max_entries.GetInt() ) + { + ClearChatHistory(); + } + + Rml::ElementPtr chatLine = m_pInstance->CreateElement("#text"); + Rml::ElementPtr br = m_pInstance->CreateElement("br"); + + if( !chatLine || !br ) + return; + + chatLine->SetClass("chat_line", true); + chatLine->AppendChild( std::move(br) ); + + if( username ) + { + Rml::ElementPtr chatUsername = m_pInstance->CreateElement("#text"); + Rml::String usernameText = username + Rml::String(": "); + + if( !chatUsername ) + return; + + Rml::ElementText *chatUsernameElement = static_cast< Rml::ElementText* >( chatUsername.get() ); + switch( sender ) + { + case RkHudChat::SERVER: + chatUsernameElement->SetClass("chat_username_server", true); + break; + case RkHudChat::FRIEND: + chatUsernameElement->SetClass("chat_username_friend", true); + break; + case RkHudChat::FOE: + chatUsernameElement->SetClass("chat_username_foe", true); + break; + } + chatUsernameElement->SetText( usernameText ); + chatLine->AppendChild( std::move(chatUsername) ); + } + + if( message ) + { + Rml::ElementPtr chatMessage = m_pInstance->CreateElement("#text"); + if( !chatMessage ) + return; + + Rml::ElementText *chatMessageElement = static_cast< Rml::ElementText* >( chatMessage.get() ); + chatMessageElement->SetClass("chat_message", true); + chatMessageElement->SetText( message ); + chatLine->AppendChild( std::move( chatMessage ) ); + + m_elemChatLines->AppendChild( std::move(chatLine) ); + } + + + // Update the document so the scrollbar will take the new elements into account. + m_pInstance->UpdateDocument(); + // Scroll to the bottom (1.0) + m_pInstance->SetScrollTop( 1.0f * ( m_pInstance->GetScrollHeight() ) - m_pInstance->GetClientHeight() ); +} + +void RkHudChat::AddChatString( const wchar_t *username, const wchar_t *message, MessageSender sender ) +{ + //TODO: wide strings. +} diff --git a/game/client/cstrike15/RocketUI/rkhud_chat.h b/game/client/cstrike15/RocketUI/rkhud_chat.h new file mode 100644 index 000000000..ffb27c851 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_chat.h @@ -0,0 +1,82 @@ +#ifndef KISAKSTRIKE_HUD_CHAT_H +#define KISAKSTRIKE_HUD_CHAT_H + +#include "hudelement.h" +#include "iclientmode.h" // message mode enum + +#include + +extern ConVar cl_drawhud; +extern ConVar cl_showtextmsg; + +class RkHudChat : public CHudElement { +public: + enum MessageSender + { + SERVER, + FRIEND, + FOE, + }; + explicit RkHudChat(const char *value); + virtual ~RkHudChat(); + + bool ChatRaised(); + + void AddChatString( const char *username, const char *message, MessageSender sender ); + void AddChatString( const wchar_t *username, const wchar_t *message, MessageSender sender ); + void ClearChatHistory(); + + // Starts the typing sequence. + void StartMessageMode(int mode); + void StopMessageMode(); + int GetMessageMode() + { + return m_iMode; + } + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + Rml::ElementDocument *m_pInstance; + // Some precached elements from the instance. + Rml::Element *m_elemChatLines; + Rml::Element *m_elemChatInput; + + bool m_bVisible; + bool m_bGrabbingInput; + int m_iMode; + int m_iNumEntries; + + CUserMessageBinder m_UMCMsgSayText2; + CUserMessageBinder m_UMCMsgTextMsg; +}; + + + + + + + + + + + + + + + + + + + + + + + + + +#endif //KISAKSTRIKE_HUD_CHAT_H diff --git a/game/client/cstrike15/RocketUI/rkhud_infobar.cpp b/game/client/cstrike15/RocketUI/rkhud_infobar.cpp new file mode 100644 index 000000000..043f72663 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_infobar.cpp @@ -0,0 +1,307 @@ +#include "rkhud_infobar.h" + +#include "cbase.h" +#include "hud_macros.h" +#include "c_cs_player.h" + +#include // included to fix an error with min/max and rocketui + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +DECLARE_HUDELEMENT( RkHudInfoBar ); + +// Struct layout for data-binding model. +struct InfoBarData +{ + int hp; + int armor; + bool hasHelmet; + int ammo; + int ammoReserve; + Rml::String fireModeString; + Rml::String primaryString; + Rml::String secondaryString; + Rml::String knifeString; + bool hasGrenade; + bool hasFlash; + bool hasFlashPair; + bool hasSmoke; + bool hasFire; + bool hasC4; +} infoBarData; + +static void UpdateInfoFromPlayer( const C_CSPlayer &pPlayer ) +{ + infoBarData.hp = pPlayer.GetHealth(); + infoBarData.armor = pPlayer.ArmorValue(); + infoBarData.hasHelmet = false; + if( pPlayer.HasHelmet() ) + infoBarData.hasHelmet = true; + + infoBarData.fireModeString = " "; + infoBarData.primaryString = " "; + infoBarData.secondaryString = " "; + infoBarData.knifeString = " "; + infoBarData.hasGrenade = false; + //infoBarData.hasFlash = false; + //infoBarData.hasFlashPair = false; + infoBarData.hasSmoke = false; + infoBarData.hasFire = false; + infoBarData.hasC4 = false; + + int flashbangAmount = 0; + for( int i = 0; i < MAX_WEAPONS; i++ ) + { + CWeaponCSBase *weapon = (CWeaponCSBase*)pPlayer.GetWeapon(i); + if( !weapon ) + continue; + + int slot = weapon->GetSlot(); + const char *name; + + switch( slot ) + { + case WEAPON_SLOT_RIFLE: + name = V_strstr(weapon->GetName(), "_"); + if( name && name[0] ) + infoBarData.primaryString = name+1; + break; + case WEAPON_SLOT_PISTOL: + name = V_strstr(weapon->GetName(), "_"); + if( name && name[0] ) + infoBarData.secondaryString = name+1; + break; + case WEAPON_SLOT_KNIFE: + name = V_strstr(weapon->GetName(), "_"); + if( name && name[0] ) + infoBarData.knifeString = name+1; + break; + case WEAPON_SLOT_GRENADES: + { + int weaponID = weapon->GetCSWeaponID(); + switch( weaponID ) + { + case WEAPON_HEGRENADE: + infoBarData.hasGrenade = true; + break; + case WEAPON_FLASHBANG: + flashbangAmount++; + break; + case WEAPON_SMOKEGRENADE: + infoBarData.hasSmoke = true; + break; + case WEAPON_MOLOTOV: + infoBarData.hasFire = true; + break; + case WEAPON_INCGRENADE: + infoBarData.hasFire = true; + break; + default: + break; + } + break; + } + case WEAPON_SLOT_C4: + infoBarData.hasC4 = true; + break; + default: + break; + } + } + infoBarData.hasFlash = ( flashbangAmount == 1 ); + infoBarData.hasFlashPair = ( flashbangAmount == 2 ); + + CWeaponCSBase *activeWeapon = pPlayer.GetActiveCSWeapon(); + if( activeWeapon ) + { + infoBarData.ammo = activeWeapon->Clip1(); + infoBarData.ammoReserve = activeWeapon->GetReserveAmmoCount( AMMO_POSITION_PRIMARY ); + if( activeWeapon->IsFullAuto() ) + infoBarData.fireModeString = "AUTO"; + else if( activeWeapon->IsInBurstMode() ) + infoBarData.fireModeString = "BURST"; + else + infoBarData.fireModeString = "SINGLE"; + } +} + +static void UnloadRkInfoBar() +{ + RkHudInfoBar *pInfoBar = GET_HUDELEMENT( RkHudInfoBar ); + if( !pInfoBar ) + { + Warning( "Couldn't grab RkHudInfoBar element to unload!\n"); + return; + } + + // Not loaded + if( !pInfoBar->m_pInstance ) + return; + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( hudCtx ) + { + hudCtx->RemoveDataModel("infobar_model"); + pInfoBar->m_dataModel = nullptr; + } + else + { + Warning("Couldn't access hudCtx to unload infobar datamodel\n"); + } + + pInfoBar->m_pInstance->Close(); + pInfoBar->m_pInstance = nullptr; +} + +static void LoadRkInfoBar() +{ + RkHudInfoBar *pInfoBar = GET_HUDELEMENT( RkHudInfoBar ); + if( !pInfoBar ) + { + Warning( "Couldn't grab hud infobar to load!\n"); + return; + } + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( !hudCtx ) + { + Error("Couldn't access hudctx!\n"); + /* Exit */ + } + + if( pInfoBar->m_pInstance || pInfoBar->m_dataModel ) + { + Warning("RkInfoBar already loaded, call unload first!\n"); + return; + } + + // Create the data binding, this will sync data between rocketui and the game. + Rml::DataModelConstructor constructor = hudCtx->CreateDataModel("infobar_model"); + if( !constructor ) + { + Error( "Couldn't create datamodel for infobar!\n"); + /* Exit */ + } + + constructor.Bind("hp", &infoBarData.hp); + constructor.Bind("armor", &infoBarData.armor); + constructor.Bind("ammo", &infoBarData.ammo); + constructor.Bind("ammo_reserve", &infoBarData.ammoReserve); + constructor.Bind("fire_mode_string", &infoBarData.fireModeString); + constructor.Bind("has_helmet", &infoBarData.hasHelmet); + constructor.Bind("primary_string", &infoBarData.primaryString); + constructor.Bind("secondary_string", &infoBarData.secondaryString); + constructor.Bind("knife_string", &infoBarData.knifeString); + constructor.Bind("has_grenade", &infoBarData.hasGrenade); + constructor.Bind("has_flash", &infoBarData.hasFlash); + constructor.Bind("has_flash_pair", &infoBarData.hasFlashPair); + constructor.Bind("has_smoke", &infoBarData.hasSmoke); + constructor.Bind("has_fire", &infoBarData.hasFire); + constructor.Bind("has_c4", &infoBarData.hasC4); + + pInfoBar->m_dataModel = constructor.GetModelHandle(); + + pInfoBar->m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_infobar.rml", LoadRkInfoBar, UnloadRkInfoBar ); + + if( !pInfoBar->m_pInstance ) + { + Error("Couldn't create hud_infobar document!\n"); + /* Exit */ + } + + //pInfoBar->m_pInstance->Show(); + pInfoBar->ShowPanel( false, false ); +} + +RkHudInfoBar::RkHudInfoBar(const char *value) : CHudElement( value ), + m_bVisible( false ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +RkHudInfoBar::~RkHudInfoBar() noexcept +{ + UnloadRkInfoBar(); +} + +void RkHudInfoBar::LevelInit() +{ + LoadRkInfoBar(); +} + +void RkHudInfoBar::LevelShutdown() +{ + UnloadRkInfoBar(); +} + +// this is called every frame, keep that in mind. +void RkHudInfoBar::ShowPanel(bool bShow, bool force) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + if( !m_bVisible ) + { + m_pInstance->Show(); + } + C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer(); + + if( !pPlayer ) + goto end; + + // observing someone? switch to that player. + if( pPlayer->IsObserver() && (pPlayer->GetObserverMode() == OBS_MODE_IN_EYE || pPlayer->GetObserverMode() == OBS_MODE_CHASE) ) + pPlayer = ToCSPlayer(pPlayer->GetObserverTarget()); + + if( !pPlayer ) + goto end; + + UpdateInfoFromPlayer( *pPlayer ); + + m_dataModel.DirtyVariable( "hp" ); + m_dataModel.DirtyVariable( "ammo" ); + m_dataModel.DirtyVariable( "ammo_reserve" ); + m_dataModel.DirtyVariable( "fire_mode_string" ); + m_dataModel.DirtyVariable( "armor" ); + m_dataModel.DirtyVariable( "has_helmet" ); + m_dataModel.DirtyVariable( "primary_string" ); + m_dataModel.DirtyVariable( "secondary_string" ); + m_dataModel.DirtyVariable( "knife_string" ); + m_dataModel.DirtyVariable( "has_grenade" ); + m_dataModel.DirtyVariable( "has_flash" ); + m_dataModel.DirtyVariable( "has_flash_pair" ); + m_dataModel.DirtyVariable( "has_smoke" ); + m_dataModel.DirtyVariable( "has_fire" ); + m_dataModel.DirtyVariable( "has_c4" ); + + m_dataModel.Update(); + } + else + { + if( m_bVisible ) + { + m_pInstance->Hide(); + } + } + +end: + m_bVisible = bShow; +} + +void RkHudInfoBar::SetActive(bool bActive) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudInfoBar::ShouldDraw() +{ + C_CSPlayer *localPlayer = C_CSPlayer::GetLocalCSPlayer(); + + return localPlayer && + cl_drawhud.GetBool() && + ( localPlayer->IsAlive() || ( localPlayer->IsObserver() && localPlayer->GetObserverMode() == OBS_MODE_IN_EYE || localPlayer->GetObserverMode() == OBS_MODE_CHASE ) ) && + CHudElement::ShouldDraw(); +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_infobar.h b/game/client/cstrike15/RocketUI/rkhud_infobar.h new file mode 100644 index 000000000..450066703 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_infobar.h @@ -0,0 +1,30 @@ +#ifndef KISAKSTRIKE_RKHUD_INFOBAR_H +#define KISAKSTRIKE_RKHUD_INFOBAR_H + +#include +#include "hudelement.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h" + +extern ConVar cl_drawhud; + +class RkHudInfoBar : public CHudElement { +public: + explicit RkHudInfoBar(const char *value); + virtual ~RkHudInfoBar(); + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + Rml::ElementDocument *m_pInstance; + bool m_bVisible; + Rml::DataModelHandle m_dataModel; + +}; + + +#endif //KISAKSTRIKE_RKHUD_INFOBAR_H \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_killfeed.cpp b/game/client/cstrike15/RocketUI/rkhud_killfeed.cpp new file mode 100644 index 000000000..498d027c9 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_killfeed.cpp @@ -0,0 +1,226 @@ +#include "rkhud_killfeed.h" + +#include "cbase.h" +#include "hud_macros.h" +#include "c_cs_player.h" + +#include // included to fix an error with min/max and rocketui + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" +#include + +DECLARE_HUDELEMENT( RkHudKillfeed ); + +ConVar rocket_hud_killfeed_linger_time( "rocket_hud_killfeed_linger_time", "5", 0, "How long in seconds to keep each killfeed entry on screen." ); + +struct KillfeedEntry +{ + Rml::String attackerName; + Rml::String gunName; + Rml::String victimName; + bool headshot; + bool wallbang; + float noticeSpawnTime; +}; + +// Struct layout for data-binding model. +struct KillFeedData +{ + std::deque entries; +} killFeedData; + +void RkHudKillfeed::OnPlayerDeath( IGameEvent *event ) +{ + KillfeedEntry entry; + int nAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + int nVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + + CCSPlayer* attacker = ToCSPlayer( ClientEntityList().GetBaseEntity( nAttacker ) ); + CCSPlayer* victim = ToCSPlayer( ClientEntityList().GetBaseEntity( nVictim ) ); + + if( !attacker || !victim ) + return; + + entry.victimName = victim->GetPlayerName(); + entry.attackerName = attacker->GetPlayerName(); + entry.gunName = event->GetString( "weapon" ); + entry.headshot = ( event->GetInt( "headshot" ) > 0 ); + entry.wallbang = ( event->GetInt( "penetrated" ) > 0 ); + + entry.noticeSpawnTime = gpGlobals->curtime; + + killFeedData.entries.push_back( entry ); + + m_dataModel.DirtyVariable( "killfeed_entries"); + m_dataModel.Update(); +} + +// called every frame +void RkHudKillfeed::CheckForOldEntries() +{ + if( killFeedData.entries.empty() ) + return; + + // pop off the first guy, then we're done. This gets called often enough to not matter about the rest. + if( (gpGlobals->curtime - killFeedData.entries.front().noticeSpawnTime) > rocket_hud_killfeed_linger_time.GetFloat() ) + { + killFeedData.entries.pop_front(); + m_dataModel.DirtyVariable( "killfeed_entries"); + m_dataModel.Update(); + } +} + +static void UnloadRkKillFeed() +{ + RkHudKillfeed *pKillFeed = GET_HUDELEMENT( RkHudKillfeed ); + if( !pKillFeed ) + { + Warning( "Couldn't grab hud killfeed to load!\n" ); + return; + } + + // Not loaded. + if( !pKillFeed->m_pInstance ) + return; + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( hudCtx ) + { + hudCtx->RemoveDataModel( "killfeed_model" ); + pKillFeed ->m_dataModel = nullptr; + } + else + { + Warning( "couldn't access hudctx to unload killfeed datamodel!\n" ); + } + + pKillFeed->m_pInstance->Close(); + pKillFeed->m_pInstance = nullptr; + pKillFeed->m_bVisible = false; +} + +static void LoadRkKillFeed() +{ + RkHudKillfeed *pKillFeed = GET_HUDELEMENT( RkHudKillfeed ); + if( !pKillFeed ) + { + Warning( "Couldn't grab hud killfeed to load!\n" ); + return; + } + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( !hudCtx ) + { + Error( "Couldn't access hudctx!\n" ); + /* Exit */ + } + + if( pKillFeed->m_pInstance || pKillFeed->m_dataModel ) + { + Warning( "RkKillFeed already loaded, call unload first!\n" ); + return; + } + + // Create the data binding, this will sync data between rocketui and the game. + Rml::DataModelConstructor constructor = hudCtx->CreateDataModel( "killfeed_model" ); + if( !constructor ) + { + Error( "Couldn't create datamodel for killfeed!\n" ); + /* Exit */ + } + + // Register KillfeedEntry struct definition + if( auto killfeedentry_handle = constructor.RegisterStruct() ) + { + killfeedentry_handle.RegisterMember( "attacker_name", &KillfeedEntry::attackerName ); + killfeedentry_handle.RegisterMember( "gun_name", &KillfeedEntry::gunName ); + killfeedentry_handle.RegisterMember( "victim_name", &KillfeedEntry::victimName ); + killfeedentry_handle.RegisterMember( "headshot", &KillfeedEntry::headshot ); + killfeedentry_handle.RegisterMember( "wallbang", &KillfeedEntry::wallbang ); + } + + // Register array-type of KillfeedEntry + constructor.RegisterArray>(); + + // Bind the killfeed entry array + constructor.Bind( "killfeed_entries", &killFeedData.entries ); + + pKillFeed->m_dataModel = constructor.GetModelHandle(); + + // Load document from file. + pKillFeed->m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_killfeed.rml", &LoadRkKillFeed, &UnloadRkKillFeed ); + if( !pKillFeed->m_pInstance ) + { + Error( "Couldn't create hud_killfeed document!\n" ); + /* Exit */ + } + + pKillFeed->ShowPanel( true, false ); +} + +RkHudKillfeed::RkHudKillfeed(const char *value) : CHudElement( value ), m_bVisible( false ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +RkHudKillfeed::~RkHudKillfeed() noexcept +{ + StopListeningForAllEvents(); + + UnloadRkKillFeed(); +} + +void RkHudKillfeed::LevelInit() +{ + ListenForGameEvent( "player_death" ); + + LoadRkKillFeed(); +} + +void RkHudKillfeed::LevelShutdown() +{ + killFeedData.entries.clear(); + + UnloadRkKillFeed(); +} + +void RkHudKillfeed::ShowPanel(bool bShow, bool force) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + if( !m_bVisible ) + { + m_pInstance->Show(); + } + CheckForOldEntries(); + } + else + { + if( m_bVisible ) + { + m_pInstance->Hide(); + } + } + + m_bVisible = bShow; +} + +void RkHudKillfeed::SetActive(bool bActive) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudKillfeed::ShouldDraw() +{ + return cl_drawhud.GetBool() && CHudElement::ShouldDraw(); +} + +void RkHudKillfeed::FireGameEvent(IGameEvent *event) +{ + // We only listen for "player_death" + OnPlayerDeath( event ); +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_killfeed.h b/game/client/cstrike15/RocketUI/rkhud_killfeed.h new file mode 100644 index 000000000..09a68b847 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_killfeed.h @@ -0,0 +1,37 @@ +#ifndef KISAKSTRIKE_RKHUD_KILLFEED_H +#define KISAKSTRIKE_RKHUD_KILLFEED_H + +#include +#include "hudelement.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h" + +extern ConVar cl_drawhud; + +class RkHudKillfeed : public CHudElement +{ +public: + explicit RkHudKillfeed( const char *value ); + virtual ~RkHudKillfeed(); + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + // CGameEventListener + virtual void FireGameEvent( IGameEvent *event ); + + + Rml::ElementDocument *m_pInstance; + bool m_bVisible; + Rml::DataModelHandle m_dataModel; + +private: + void CheckForOldEntries(); + void OnPlayerDeath( IGameEvent *event ); +}; + +#endif //KISAKSTRIKE_RKHUD_KILLFEED_H diff --git a/game/client/cstrike15/RocketUI/rkhud_loadingscreen.cpp b/game/client/cstrike15/RocketUI/rkhud_loadingscreen.cpp new file mode 100644 index 000000000..390b4ecec --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_loadingscreen.cpp @@ -0,0 +1,98 @@ +#include "rkhud_loadingscreen.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +#include "cbase.h" +#include "cdll_client_int.h" // extern globals to interfaces like engineclient +#include "rkhud_teammenu.h" +#include "c_cs_player.h" + +Rml::ElementDocument *RocketLoadingScreenDocument::m_pInstance = nullptr; +bool RocketLoadingScreenDocument::m_bVisible = false; +bool RocketLoadingScreenDocument::m_bGrabbingInput = false; + +/* Event Listener added to continue button */ +class RkLoadingScreenClick : public Rml::EventListener +{ +public: + void ProcessEvent(Rml::Event& keyevent) override + { + // On any mousedown + RocketLoadingScreenDocument::ShowPanel( false ); + } +}; + +static RkLoadingScreenClick loadingScreenClickListener; + +RocketLoadingScreenDocument::RocketLoadingScreenDocument() +{ +} + +void RocketLoadingScreenDocument::LoadDialog() +{ + if( !m_pInstance ) + { + m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_loadingscreen.rml", RocketLoadingScreenDocument::LoadDialog, RocketLoadingScreenDocument::UnloadDialog ); + + if( !m_pInstance ) + { + Error( "Couldn't create rocketui loadingscreen!\n"); + /* Exit */ + } + m_pInstance->AddEventListener( Rml::EventId::Mousedown, &loadingScreenClickListener ); + } +} + +void RocketLoadingScreenDocument::UnloadDialog() +{ + if( m_pInstance ) + { + m_pInstance->Close(); + m_pInstance = nullptr; + } + if( m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( false, "LoadingScreen" ); + } +} + +void RocketLoadingScreenDocument::ShowPanel(bool bShow, bool immediate) +{ + // oh yeah buddy this'll get called before the loading sometimes + // so if it does, load it for the caller. + if( bShow ) + { + if( !m_pInstance ) + LoadDialog(); + + m_pInstance->Show(); + + if( !m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( true, "LoadingScreen" ); + m_bGrabbingInput = true; + } + } + else + { + if( m_pInstance ){ + //UnloadDialog(); + m_pInstance->Hide(); + } + + if( m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( false, "LoadingScreen" ); + m_bGrabbingInput = false; + } + + // if we were visible, we need to join the game most likely and show the team select. + if( m_bVisible ) + { + engine->ClientCmd_Unrestricted( "joingame" ); + RocketTeamMenuDocument::ShowPanel( true ); + } + } + + m_bVisible = bShow; +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_loadingscreen.h b/game/client/cstrike15/RocketUI/rkhud_loadingscreen.h new file mode 100644 index 000000000..5e2bbb7e9 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_loadingscreen.h @@ -0,0 +1,25 @@ +#ifndef KISAKSTRIKE_RKHUD_LOADINGSCREEN_H +#define KISAKSTRIKE_RKHUD_LOADINGSCREEN_H + +#include + +class RocketLoadingScreenDocument +{ +protected: + static Rml::ElementDocument *m_pInstance; + + RocketLoadingScreenDocument( ); +public: + static void LoadDialog( void ); + static void UnloadDialog( void ); + static void ShowPanel( bool bShow, bool immediate = false ); + static bool IsActive() { return m_pInstance != nullptr; } + static bool IsVisible() { return m_bVisible; } + static Rml::ElementDocument *GetInstance() { return m_pInstance; } +private: + static bool m_bVisible; + static bool m_bGrabbingInput; +}; + + +#endif //KISAKSTRIKE_RKHUD_LOADINGSCREEN_H diff --git a/game/client/cstrike15/RocketUI/rkhud_pausemenu.cpp b/game/client/cstrike15/RocketUI/rkhud_pausemenu.cpp new file mode 100644 index 000000000..bf5f35f55 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_pausemenu.cpp @@ -0,0 +1,148 @@ +#include "rkhud_pausemenu.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +#include "cdll_client_int.h" // extern globals to interfaces like engineclient + +#include "rkhud_chat.h" +#include "rkhud_teammenu.h" +#include "rkhud_buymenu.h" + +Rml::ElementDocument *RocketPauseMenuDocument::m_pInstance = nullptr; +bool RocketPauseMenuDocument::m_bVisible = false; +bool RocketPauseMenuDocument::m_bGrabbingInput = false; + +/* Event Listener added to each button */ +class RkPauseMenuButtons : public Rml::EventListener +{ +public: + void ProcessEvent(Rml::Event& mousedownevent) override + { + // Currently, only mousedown events. + Rml::Element *elem = mousedownevent.GetTargetElement(); + if( !elem ) + return; + + Rml::String id = elem->GetId(); + if( id == "pm_resume" ) + { + RocketPauseMenuDocument::ShowPanel( false ); + } + else if( id == "pm_choose" ) + { + RocketTeamMenuDocument::ShowPanel( true ); + RocketPauseMenuDocument::ShowPanel( false ); + } + else if( id == "pm_callvote" ) + { + + } + else if( id == "pm_options" ) + { + + } + else if( id == "pm_disconnect" ) + { + engine->ClientCmd_Unrestricted("disconnect"); + } + } +}; + +static RkPauseMenuButtons pauseMenuButtonsListener; + +RocketPauseMenuDocument::RocketPauseMenuDocument() +{ +} + +void RocketPauseMenuDocument::LoadDialog() +{ + if( !m_pInstance ) + { + m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_pausemenu.rml", RocketPauseMenuDocument::LoadDialog, RocketPauseMenuDocument::UnloadDialog ); + if( !m_pInstance ) + { + Error( "Couldn't create rocketui pause menu!\n"); + /* Exit */ + } + RocketUI()->RegisterPauseMenu( RocketPauseMenuDocument::TogglePanel ); + + // Add a listener to each button, this seems better than custom events for these + Rml::ElementList menuButtons; + m_pInstance->GetElementsByTagName( menuButtons, "button" ); + for( Rml::Element *elem : menuButtons ) + { + elem->AddEventListener( Rml::EventId::Mousedown, &pauseMenuButtonsListener ); + } + } +} + +void RocketPauseMenuDocument::UnloadDialog() +{ + if( m_pInstance ) + { + RocketUI()->RegisterPauseMenu( nullptr ); + m_pInstance->Close(); + m_pInstance = nullptr; + if( m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( false, "PauseMenu" ); + m_bGrabbingInput = false; + } + } +} + +void RocketPauseMenuDocument::UpdateDialog() +{ +} + +void RocketPauseMenuDocument::TogglePanel() +{ + ShowPanel( !m_bVisible ); +} + +void RocketPauseMenuDocument::ShowPanel(bool bShow, bool immediate) +{ + // oh yeah buddy this'll get called before the loading sometimes + // so if it does, load it for the caller. + if( bShow ) + { + if( !m_pInstance ) + LoadDialog(); + + RkHudChat *pChat = GET_HUDELEMENT( RkHudChat ); + RkHudBuyMenu *pBuyMenu = GET_HUDELEMENT( RkHudBuyMenu ); + + if( !pChat || !pBuyMenu ) + return; + + if( pChat->ChatRaised() ) + { + return; + } + if( pBuyMenu->m_bVisible || !pBuyMenu->m_pInstance ) + { + return; + } + + m_pInstance->Show(); + + if( !m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( true, "PauseMenu" ); + m_bGrabbingInput = true; + } + } + else + { + if( m_pInstance ) + m_pInstance->Hide(); + + if( m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( false, "PauseMenu" ); + m_bGrabbingInput = false; + } + } + + m_bVisible = bShow; +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_pausemenu.h b/game/client/cstrike15/RocketUI/rkhud_pausemenu.h new file mode 100644 index 000000000..40fd12bbf --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_pausemenu.h @@ -0,0 +1,28 @@ +#ifndef KISAKSTRIKE_RKHUD_PAUSEMENU_H +#define KISAKSTRIKE_RKHUD_PAUSEMENU_H + +#include + +class RocketPauseMenuDocument +{ +protected: + static Rml::ElementDocument *m_pInstance; + + RocketPauseMenuDocument( ); +public: + static void LoadDialog( void ); + static void UnloadDialog( void ); + static void RestorePanel( void ); + static void TogglePanel( void ); + static void ShowPanel( bool bShow, bool immediate = false ); + static bool IsActive() { return m_pInstance != nullptr; } + static bool IsVisible() { return m_bVisible; } + static void UpdateDialog( void ); + static Rml::ElementDocument *GetInstance() { return m_pInstance; } +private: + static bool m_bVisible; + static bool m_bGrabbingInput; +}; + + +#endif diff --git a/game/client/cstrike15/RocketUI/rkhud_radar.cpp b/game/client/cstrike15/RocketUI/rkhud_radar.cpp new file mode 100644 index 000000000..b5cb8609f --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_radar.cpp @@ -0,0 +1,357 @@ +#include "rkhud_radar.h" + +#include "cbase.h" +#include "hud_macros.h" +#include "c_cs_player.h" + +#include // included to fix an error with min/max and rocketui +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +DECLARE_HUDELEMENT( RkHudRadar ); +DECLARE_HUD_MESSAGE( RkHudRadar, ProcessSpottedEntityUpdate ); + +ConVar rocket_hud_radar_info_linger_time( "rocket_hud_radar_info_linger_time", "3", 0, "How long in seconds does the data stay visible after an update" ); +ConVar rocket_hud_radar_scale( "rocket_hud_radar_scale", "0.15", 0, "scale for radar" ); + +static void RadarSizeChanged( IConVar *pConvar, const char *szOldValue, float fOldValue ) +{ + RkHudRadar *pRadar = GET_HUDELEMENT( RkHudRadar ); + if( !pRadar ) + { + Warning( "Couldn't grab hud radar to update size!\n" ); + return; + } + pRadar->UpdateRadarSize(); +} +ConVar rocket_hud_radar_height( "rocket_hud_radar_height", "400", 0, "height in pixels for the radar", RadarSizeChanged ); +ConVar rocket_hud_radar_width( "rocket_hud_radar_width", "400", 0, "width in pixels for the radar", RadarSizeChanged ); + + +bool RkHudRadar::MsgFunc_ProcessSpottedEntityUpdate(const CCSUsrMsg_ProcessSpottedEntityUpdate &msg) +{ + if( msg.new_update() ) + { + // Clear everything. + //for( int i = 0; i < MAX_PLAYERS; i++ ) + // m_spottedPlayers[i].timelastSpotted = 0.0f; + } + + for( int i = 0; i < msg.entity_updates_size(); i++ ) + { + const auto &update = msg.entity_updates(i); + + int entID = update.entity_idx(); + // make sure this is a valid id for any type of entity. + if( entID < 1 || entID >= MAX_EDICTS ) + continue; + + // these are sent from the server as /4 + int x = update.origin_x() * 4; + int y = update.origin_y() * 4; + int z = update.origin_z() * 4; + int yaw = update.angle_y(); + + const char *szEntClassName; + int classID = update.class_id(); + for ( ClientClass *pCur = g_pClientClassHead; pCur; pCur = pCur->m_pNext ) + { + if( pCur->m_ClassID == classID ) + { + szEntClassName = pCur->GetName(); + break; + } + } + + if( !szEntClassName ) + { + Warning( "Unknown entity class received in ProcessSpottedEntityUpdate.\n" ); + } + + // Clients are unaware of the defuser class type, so we need to flag defuse entities manually + if( update.defuser() ) + { + // TODO: this is the defuser! + } + else if( !V_strcmp( "CCSPlayer", szEntClassName ) ) + { + // out of bounds! + if( entID < 1 || entID > MAX_PLAYERS ) + return true; + + // subtract 1 to convert 1-64 to 0-63 + SpottedInfo &playerInfo = m_spottedPlayers[ (entID-1) ]; + playerInfo.entId = update.entity_idx(); + playerInfo.originX = x; + playerInfo.originY = y; + playerInfo.originZ = z; + playerInfo.angleYaw = yaw; + if( update.has_player_has_defuser() ) + { + playerInfo.playerWithDefuser = true; + // TODO: set defuser pos + } + if( update.player_has_c4() ) + { + playerInfo.playerWithC4 = true; + // TODO: set bomb pos + } + playerInfo.timelastSpotted = gpGlobals->curtime; + } + else if( !V_strcmp( "CC4", szEntClassName ) || !V_strcmp( "CPlantedC4", szEntClassName ) ) + { + // TODO: set bomb pos + } + else if( !V_strcmp( "CHostage", szEntClassName ) ) + { + // TODO: set hostage pos + } + } + + return true; +} + +// https://www.unknowncheats.me/forum/general-programming-and-reversing/135529-implement-simple-radar.html +static inline void RotatePoint( float x, float y, float centerX, float centerY, float angle, float *outX, float *outY ) +{ + angle = DEG2RAD( angle ); + + float cosTheta = cosf( angle ); + float sinTheta = sinf( angle ); + + *outX = (cosTheta * ( x - centerX )) - (sinTheta * ( y - centerY )); + *outY = (sinTheta * ( x - centerX )) + (cosTheta * ( y - centerY )); + *outX += centerX; + *outY += centerY; +} + +void RkHudRadar::UpdateRadarSize() +{ + if( !m_pInstance ) + return; + + // Bounds of radar + m_elemBody->SetProperty("width", Rml::String(rocket_hud_radar_width.GetString()) + "px"); + m_elemBody->SetProperty("height", Rml::String(rocket_hud_radar_height.GetString()) + "px"); + m_radarWidth = rocket_hud_radar_width.GetFloat(); + m_radarHeight = rocket_hud_radar_height.GetFloat(); + m_radarX = m_elemBody->GetAbsoluteLeft(); + m_radarY = m_elemBody->GetAbsoluteTop(); + // these are children so we dont need the x+ or y+ + m_radarCenterX = ( m_radarWidth / 2.0f ); + m_radarCenterY = ( m_radarHeight / 2.0f ); + ConMsg( "radarXY(%f/%f) - width/height(%f/%f) - centerX/Y(%f/%f)\n", m_radarX, m_radarY, m_radarWidth, m_radarHeight, m_radarCenterX, m_radarCenterY ); + +} + +void RkHudRadar::UpdateRadarFrame() +{ + C_CSPlayer *activePlayer = C_CSPlayer::GetLocalCSPlayer(); + if( !activePlayer ) + return; + + // observing someone? switch to that player. + if( activePlayer->IsObserver() && (activePlayer->GetObserverMode() == OBS_MODE_IN_EYE || activePlayer->GetObserverMode() == OBS_MODE_CHASE) ) + activePlayer = ToCSPlayer(activePlayer->GetObserverTarget()); + + float currTime = gpGlobals->curtime; + + // The Radar packets are designed to supplement an existing regular radar. + // We will do a regular radar, but with the dormant check, see if we have some recent maphack data from server. + for( int i = 1; i <= MAX_PLAYERS; i++ ) + { + if( i == engine->GetLocalPlayer() ) + continue; + + // array index for the player elements + int index = i - 1; + CBasePlayer *player = UTIL_PlayerByIndex( i ); + const SpottedInfo &playerInfo = m_spottedPlayers[index]; + + if( !player || !player->IsAlive() ) + { + m_playerElements[index]->SetProperty("opacity", "0"); + continue; + } + + // if dormant and we dont have any recent information from the server + if( player->IsDormant() && ( ( currTime - playerInfo.timelastSpotted ) > rocket_hud_radar_info_linger_time.GetFloat() ) ) + { + m_playerElements[index]->SetProperty("opacity", "0"); + continue; + } + + // At this point we either have a visible player or recent server radar data + m_playerElements[index]->SetProperty("opacity", "1"); + + float originDiffX; + float originDiffY; + + if( player->IsDormant() ) + { + originDiffX = activePlayer->GetAbsOrigin().x - playerInfo.originX; + originDiffY = activePlayer->GetAbsOrigin().y - playerInfo.originY; + } + else + { + originDiffX = activePlayer->GetAbsOrigin().x - player->GetAbsOrigin().x; + originDiffY = activePlayer->GetAbsOrigin().y - player->GetAbsOrigin().y; + } + + originDiffX *= rocket_hud_radar_scale.GetFloat(); + originDiffY *= rocket_hud_radar_scale.GetFloat(); + originDiffX *= -1; // x goes other way + + // add the center of the radar. + originDiffX += m_radarCenterX; + originDiffY += m_radarCenterY; + + float rotatedX; + float rotatedY; + RotatePoint( originDiffX, originDiffY, m_radarCenterX, m_radarCenterY, activePlayer->EyeAngles().y - 90.0f, &rotatedX, &rotatedY ); + + // these guys are off the radar. Go ahead and hide them. + if( rotatedX > m_radarWidth || rotatedX < 0 || rotatedY > m_radarHeight || rotatedY < 0 ) + { + m_playerElements[index]->SetProperty("opacity", "0"); + continue; + } + + m_playerElements[index]->SetProperty("left", std::to_string(int(rotatedX)) + "px"); + m_playerElements[index]->SetProperty("top", std::to_string(int(rotatedY)) + "px"); + } +} + +static void UnloadRkRadar() +{ + RkHudRadar *pRadar = GET_HUDELEMENT( RkHudRadar ); + if( !pRadar ) + { + Warning( "Couldn't grab hud radar to unload!\n" ); + return; + } + + if( !pRadar->m_pInstance ) + return; + + pRadar->m_pInstance->Close(); + pRadar->m_pInstance = nullptr; + pRadar->m_bVisible = false; +} +static void LoadRkRadar() +{ + RkHudRadar *pRadar = GET_HUDELEMENT( RkHudRadar ); + if( !pRadar ) + { + Warning( "Couldn't grab hud radar to load!\n" ); + return; + } + + if( pRadar->m_pInstance ) + { + Warning( "RkRadar already loaded! call unload first!\n" ); + return; + } + + pRadar->m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_radar.rml", &LoadRkRadar, UnloadRkRadar ); + if( !pRadar->m_pInstance ) + { + Error( "Couldn't create hud_radar document!\n" ); + /* Exit */ + } + + pRadar->m_elemBody = pRadar->m_pInstance->GetElementById( "body" ); + if( !pRadar->m_elemBody ) + { + Error("Couldn't find required element id 'body' in hud_radar\n" ); + /* Exit */ + } + + pRadar->m_elemContainer = pRadar->m_pInstance->GetElementById( "container" ); + if( !pRadar->m_elemContainer ) + { + Error("Couldn't find required element id 'container' in hud_radar\n" ); + /* Exit */ + } + + // Create all the player elements. These will be moved around, hidden and shown as the radar updates + for( int i = 0; i < MAX_PLAYERS; i++ ) + { + Rml::ElementPtr ptr = pRadar->m_pInstance->CreateElement("div"); + pRadar->m_playerElements[i] = ptr.get(); + if( !pRadar->m_playerElements[i] ) + { + Error("Couldn't create player element(%d) for radar!", i); + /* Exit */ + } + pRadar->m_playerElements[i]->SetClass("player", true); + pRadar->m_playerElements[i]->SetProperty("opacity", "0"); + + pRadar->m_elemContainer->AppendChild( std::move(ptr) ); + } + + pRadar->UpdateRadarSize(); +} + +RkHudRadar::RkHudRadar(const char *value) : CHudElement( value ), + m_bVisible( false ), + m_pInstance( nullptr ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +RkHudRadar::~RkHudRadar() noexcept +{ + UnloadRkRadar(); +} + +void RkHudRadar::LevelInit() +{ + LoadRkRadar(); + + HOOK_HUD_MESSAGE( RkHudRadar, ProcessSpottedEntityUpdate ); +} + +void RkHudRadar::LevelShutdown() +{ + UnloadRkRadar(); +} + +void RkHudRadar::ShowPanel(bool bShow, bool force) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + if( !m_bVisible ) + { + m_pInstance->Show(); + } + UpdateRadarFrame(); + } + else + { + if( m_bVisible ) + { + m_pInstance->Hide(); + } + } + + m_bVisible = bShow; +} + +void RkHudRadar::SetActive(bool bActive) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudRadar::ShouldDraw() +{ + C_CSPlayer *localPlayer = C_CSPlayer::GetLocalCSPlayer(); + + return localPlayer && + cl_drawhud.GetBool() && + ( localPlayer->IsAlive() || ( localPlayer->IsObserver() && localPlayer->GetObserverMode() == OBS_MODE_IN_EYE || localPlayer->GetObserverMode() == OBS_MODE_CHASE ) ) && + CHudElement::ShouldDraw(); +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_radar.h b/game/client/cstrike15/RocketUI/rkhud_radar.h new file mode 100644 index 000000000..d7992d89a --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_radar.h @@ -0,0 +1,68 @@ +#ifndef KISAKSTRIKE_RKHUD_RADAR_H +#define KISAKSTRIKE_RKHUD_RADAR_H + +#include +#include "hudelement.h" + +extern ConVar cl_drawhud; + +struct SpottedInfo +{ + // info from ProcessSpottedEntityUpdate + int entId; + int classId; + int originX; + int originY; + int originZ; + int angleYaw; + bool defuser; + bool playerWithDefuser; + bool playerWithC4; + + float timelastSpotted; +}; + +class RkHudRadar : public CHudElement +{ +public: + explicit RkHudRadar( const char *value ); + virtual ~RkHudRadar(); + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + // Hooked msg + bool MsgFunc_ProcessSpottedEntityUpdate( const CCSUsrMsg_ProcessSpottedEntityUpdate &msg ); + + void UpdateRadarFrame(); + void UpdateRadarSize(); + + Rml::ElementDocument *m_pInstance; + bool m_bVisible; + + float m_radarX; + float m_radarY; + float m_radarWidth; + float m_radarHeight; + float m_radarCenterX; + float m_radarCenterY; + Rml::Element *m_playerElements[MAX_PLAYERS]; + SpottedInfo m_spottedPlayers[MAX_PLAYERS]; + Rml::Element *m_defuserElement; + SpottedInfo m_spottedDefuser; + Rml::Element *m_c4Element; + SpottedInfo m_spottedC4; + + // Cached elements from instance. + Rml::Element *m_elemBody; + Rml::Element *m_elemContainer; + + CUserMessageBinder m_UMCMsgProcessSpottedEntityUpdate; +}; + + +#endif //KISAKSTRIKE_RKHUD_RADAR_H diff --git a/game/client/cstrike15/RocketUI/rkhud_roundtimer.cpp b/game/client/cstrike15/RocketUI/rkhud_roundtimer.cpp new file mode 100644 index 000000000..59055cc9b --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_roundtimer.cpp @@ -0,0 +1,183 @@ +#include "rkhud_roundtimer.h" + +#include "cbase.h" +#include "hud_macros.h" +#include "c_cs_player.h" +#include "c_playerresource.h" + +#include // included to fix an error with min/max and rocketui +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +DECLARE_HUDELEMENT( RkHudRoundTimer ); + +// Struct layout for data-binding model. +struct RoundTimerData +{ + int MinutesLeft; + int SecondsLeft; + bool bombPlanted; + int ctScore; + int tScore; +} roundTimerData; + +RkHudRoundTimer::RkHudRoundTimer(const char *value) : CHudElement( value ), + m_bVisible( false ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +static void UnloadRkRoundTimer() +{ + RkHudRoundTimer *pRoundTimer = GET_HUDELEMENT(RkHudRoundTimer); + if (!pRoundTimer) + { + Warning("Couldn't grab hud roundtimer to load!\n"); + return; + } + + // Not loaded + if( !pRoundTimer->m_pInstance ) + return; + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( hudCtx ) + { + hudCtx->RemoveDataModel( "roundtimer_model" ); + pRoundTimer->m_dataModel = nullptr; + } + else + { + Warning("Couldn't access hudctx to unload scoreboard datamodel!\n"); + } + + pRoundTimer->m_pInstance->Close(); + pRoundTimer->m_pInstance = nullptr; +} + +static void LoadRkRoundTimer() +{ + RkHudRoundTimer *pRoundTimer = GET_HUDELEMENT(RkHudRoundTimer); + if (!pRoundTimer) + { + Warning("Couldn't grab hud roundtimer to load!\n"); + return; + } + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if (!hudCtx) + { + Error("Couldn't access hudctx!\n"); + /* Exit */ + } + + if( pRoundTimer->m_pInstance || pRoundTimer->m_dataModel ) + { + Warning( "RkRoundTimer already loaded, call unload first!\n"); + return; + } + + // Create the data binding, this will sync data between rocketui and the game. + Rml::DataModelConstructor constructor = hudCtx->CreateDataModel("roundtimer_model" ); + if( !constructor ) + { + Error( "Couldn't create datamodel for roundtimer!\n" ); + /* Exit */ + } + + constructor.Bind( "minutes_left", &roundTimerData.MinutesLeft ); + constructor.Bind( "seconds_left", &roundTimerData.SecondsLeft ); + constructor.Bind( "bomb_planted", &roundTimerData.bombPlanted ); + constructor.Bind( "ct_score", &roundTimerData.ctScore ); + constructor.Bind( "t_score", &roundTimerData.tScore ); + + pRoundTimer->m_dataModel = constructor.GetModelHandle(); + + pRoundTimer->m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_roundtimer.rml", &LoadRkRoundTimer, &UnloadRkRoundTimer ); + + if( !pRoundTimer->m_pInstance ) + { + Error( "Couldn't create hud_roundtimer document!\n" ); + /* Exit */ + } + + pRoundTimer->ShowPanel( false, false ); +} + +RkHudRoundTimer::~RkHudRoundTimer() noexcept +{ + UnloadRkRoundTimer(); +} + +void RkHudRoundTimer::LevelInit() +{ + LoadRkRoundTimer(); +} + +void RkHudRoundTimer::LevelShutdown() +{ + UnloadRkRoundTimer(); +} + +void RkHudRoundTimer::ShowPanel(bool bShow, bool force) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + if( !m_bVisible ) + { + m_pInstance->Show(); + } + + int remainingTime; + if ( CSGameRules()->IsFreezePeriod() ) + { + // countdown to the start of the round while we're in freeze period + remainingTime = (int)ceil( CSGameRules()->GetRoundStartTime() - gpGlobals->curtime ); + } + else + { + remainingTime = (int)ceil( CSGameRules()->GetRoundRemainingTime() ); + } + roundTimerData.SecondsLeft = remainingTime % 60; + roundTimerData.MinutesLeft = remainingTime / 60; + roundTimerData.ctScore = g_PR->GetTeamScore( TEAM_CT ); + roundTimerData.tScore = g_PR->GetTeamScore( TEAM_TERRORIST ); + roundTimerData.bombPlanted = CSGameRules()->m_bBombPlanted; + + + m_dataModel.DirtyVariable( "minutes_left" ); + m_dataModel.DirtyVariable( "seconds_left" ); + m_dataModel.DirtyVariable( "bomb_planted" ); + m_dataModel.DirtyVariable( "ct_score" ); + m_dataModel.DirtyVariable( "t_score" ); + + m_dataModel.Update(); + } + else + { + if( m_bVisible ) + { + m_pInstance->Hide(); + } + } + + m_bVisible = bShow; +} + +void RkHudRoundTimer::SetActive(bool bActive) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudRoundTimer::ShouldDraw() +{ + C_CSPlayer *localPlayer = C_CSPlayer::GetLocalCSPlayer(); + + if( !localPlayer || localPlayer->GetTeamNumber() == TEAM_UNASSIGNED ) + return false; + + return cl_drawhud.GetBool() && CHudElement::ShouldDraw(); +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_roundtimer.h b/game/client/cstrike15/RocketUI/rkhud_roundtimer.h new file mode 100644 index 000000000..d40458931 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_roundtimer.h @@ -0,0 +1,27 @@ +#ifndef KISAKSTRIKE_RKHUD_ROUNDTIMER_H +#define KISAKSTRIKE_RKHUD_ROUNDTIMER_H + +#include +#include "hudelement.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h" + +extern ConVar cl_drawhud; + +class RkHudRoundTimer : public CHudElement { +public: + explicit RkHudRoundTimer( const char *value ); + virtual ~RkHudRoundTimer(); + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + Rml::ElementDocument *m_pInstance; + Rml::DataModelHandle m_dataModel; + bool m_bVisible; +}; +#endif //KISAKSTRIKE_RKHUD_ROUNDTIMER_H diff --git a/game/client/cstrike15/RocketUI/rkhud_scoreboard.cpp b/game/client/cstrike15/RocketUI/rkhud_scoreboard.cpp new file mode 100644 index 000000000..4e823f117 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_scoreboard.cpp @@ -0,0 +1,329 @@ +#include "rkhud_scoreboard.h" + +#include "cbase.h" +#include "hud_macros.h" +#include "c_cs_player.h" +#include "in_buttons.h" +#include "c_playerresource.h" + +#include // included to fix an error with min/max and rocketui +#include + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +DECLARE_HUDELEMENT( RkHudScoreboard ); + +// Struct layout for data-binding model. +struct PlayerEntry +{ + int entid; + Rml::String name; + int teamnum; + + int cash; + int kills; + int deaths; + int assists; + int ping; +}; +struct ScoreboardData +{ + int tScore; + int ctScore; + int numSpecs; + Rml::Vector ctPlayers; + Rml::Vector tPlayers; +} scoreboardData; + +static void UnloadRkScoreboard() +{ + RkHudScoreboard *pScoreboard = GET_HUDELEMENT( RkHudScoreboard ); + if( !pScoreboard ) + { + Warning( "Couldn't grab RkHudScoreboard element to unload!\n"); + return; + } + + // Not loaded + if( !pScoreboard->m_pInstance ) + return; + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( hudCtx ) + { + hudCtx->RemoveDataModel( "scoreboard_model" ); + pScoreboard->m_dataModel = nullptr; + } + else + { + Warning("Couldn't access hudctx to unload scoreboard datamodel!\n"); + } + + pScoreboard->m_pInstance->Close(); + pScoreboard->m_pInstance = nullptr; +} + +static void LoadRkScoreboard() +{ + RkHudScoreboard *pScoreboard = GET_HUDELEMENT( RkHudScoreboard ); + if( !pScoreboard ) + { + Warning( "Couldn't grab hud RkHudScoreboard to load!\n"); + return; + } + + Rml::Context *hudCtx = RocketUI()->AccessHudContext(); + if( !hudCtx ) + { + Error("Couldn't access hudctx!\n"); + /* Exit */ + } + + // Create the data-binding to sync data between rocketui and the game. + Rml::DataModelConstructor constructor = hudCtx->CreateDataModel( "scoreboard_model" ); + if( !constructor ) + { + Error( "Couldn't create datamodel for scoreboard!\n"); + /* Exit */ + } + + // Register the PlayerEntry struct definition + if( auto playerentry_handle = constructor.RegisterStruct()) + { + playerentry_handle.RegisterMember("entid", &PlayerEntry::entid); + playerentry_handle.RegisterMember("name", &PlayerEntry::name); + playerentry_handle.RegisterMember("teamnum", &PlayerEntry::teamnum); + playerentry_handle.RegisterMember("cash", &PlayerEntry::cash); + playerentry_handle.RegisterMember("kills", &PlayerEntry::kills); + playerentry_handle.RegisterMember("deaths", &PlayerEntry::deaths); + playerentry_handle.RegisterMember("assists", &PlayerEntry::assists); + playerentry_handle.RegisterMember("ping", &PlayerEntry::ping); + } + + // Register Array-type of PlayerEntry + constructor.RegisterArray>(); + + // Bind the two PlayerEntry arrays of players + constructor.Bind("ctplayers", &scoreboardData.ctPlayers); + constructor.Bind("tplayers", &scoreboardData.tPlayers); + + // Bind the plain data + constructor.Bind("ct_score", &scoreboardData.ctScore); + constructor.Bind("t_score", &scoreboardData.tScore); + constructor.Bind("num_specs", &scoreboardData.numSpecs); + + pScoreboard->m_dataModel = constructor.GetModelHandle(); + + // Load document from file. + pScoreboard->m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_scoreboard.rml", LoadRkScoreboard, UnloadRkScoreboard ); + if( !pScoreboard->m_pInstance ) + { + Error("Couldn't create hud_scoreboard document!\n"); + /* Exit */ + } + + // Cache some elements from the document for use later. + pScoreboard->m_elemCtSection = pScoreboard->m_pInstance->GetElementById( "ct" ); + if( !pScoreboard->m_elemCtSection ) + { + Error( "Couldn't find required element in hud_scoreboard!\n"); + /* Exit */ + } + + pScoreboard->m_elemTSection = pScoreboard->m_pInstance->GetElementById( "t" ); + if( !pScoreboard->m_elemTSection ) + { + Error( "Couldn't find required element in hud_scoreboard!\n"); + /* Exit */ + } +} + +RkHudScoreboard::RkHudScoreboard(const char *value) : CHudElement( value ), m_bVisible( false ) +{ + SetHiddenBits( /* HIDEHUD_MISCSTATUS */ 0 ); +} + +RkHudScoreboard::~RkHudScoreboard() noexcept +{ + UnloadRkScoreboard(); +} + +void RkHudScoreboard::LevelInit() +{ + LoadRkScoreboard(); +} + +void RkHudScoreboard::LevelShutdown() +{ + UnloadRkScoreboard(); +} + +void RkHudScoreboard::Update() +{ + IGameResources *gr = GameResources(); + if( !gr ) + return; + + for( int i = 1; i < gpGlobals->maxClients; i++ ) + { + PlayerEntry *playerEntry = nullptr; + int foundIndex = 0; + + int playerTeam = gr->GetTeam(i); + + // look for existing entry in these arrays + for( int index = 0; index < scoreboardData.ctPlayers.size(); index++ ) + { + if( scoreboardData.ctPlayers[index].entid == i ) + { + // delete this entry if team has changed since. + if( playerTeam != scoreboardData.ctPlayers[index].teamnum ) + { + scoreboardData.ctPlayers.erase( scoreboardData.ctPlayers.begin() + index ); + if( index > 0 ) + index--; + continue; + } + playerEntry = &scoreboardData.ctPlayers[index]; + foundIndex = index; + break; + } + } + for( int index = 0; index < scoreboardData.tPlayers.size(); index++ ) + { + if( scoreboardData.tPlayers[index].entid == i ) + { + // delete this entry if team has changed since. + if( playerTeam != scoreboardData.tPlayers[index].teamnum ) + { + scoreboardData.tPlayers.erase( scoreboardData.tPlayers.begin() + index ); + if( index > 0 ) + index--; + continue; + } + playerEntry = &scoreboardData.tPlayers[index]; + foundIndex = index; + break; + } + } + + if( gr->IsConnected( i ) ) + { + // Create a new entry for this player. + if( !playerEntry ) + { + PlayerEntry entry = {0}; + entry.entid = i; + if( playerTeam == TEAM_TERRORIST ) + { + entry.teamnum = TEAM_TERRORIST; + scoreboardData.tPlayers.push_back( entry ); + playerEntry = &scoreboardData.tPlayers[scoreboardData.tPlayers.size() - 1]; + } + else if( playerTeam == TEAM_CT ) + { + entry.teamnum = TEAM_CT; + scoreboardData.ctPlayers.push_back( entry ); + playerEntry = &scoreboardData.ctPlayers[scoreboardData.ctPlayers.size() - 1]; + } + else + { + //spectators dont get an entry + continue; + } + } + + C_CSPlayer *player = ToCSPlayer( UTIL_PlayerByIndex( i ) ); + if( !player ) + continue; + + // Update the data in the player's entry. *playerEntry will be set at this point. + if( player->IsBot() ) + { + playerEntry->name = ( Rml::String("BOT ") + gr->GetPlayerName( i ) ); + } + else + { + playerEntry->name = gr->GetPlayerName( i ); + } + playerEntry->cash = player->GetAccount(); + playerEntry->kills = gr->GetKills( i ); + playerEntry->deaths = gr->GetDeaths( i ); + playerEntry->assists = g_PR->GetAssists( i ); + playerEntry->ping = gr->GetPing( i ); + } + else + { + if( playerEntry ) + { + // Player has disconnected, need to remove his row. + if( playerEntry->teamnum == TEAM_TERRORIST ) + { + scoreboardData.tPlayers.erase( scoreboardData.tPlayers.begin() + foundIndex ); + } + else if( playerEntry->teamnum == TEAM_CT ) + { + scoreboardData.ctPlayers.erase( scoreboardData.ctPlayers.begin() + foundIndex ); + } + } + } + } + + + scoreboardData.numSpecs = GetGlobalTeam( TEAM_SPECTATOR )->GetNumPlayers(); + scoreboardData.ctScore = gr->GetTeamScore( TEAM_CT ); + scoreboardData.tScore = gr->GetTeamScore( TEAM_TERRORIST ); + + // Dirty the variables to note change. + m_dataModel.DirtyVariable( "ct_score" ); + m_dataModel.DirtyVariable( "t_score" ); + m_dataModel.DirtyVariable( "num_specs" ); + + m_dataModel.DirtyVariable( "ctplayers"); + m_dataModel.DirtyVariable( "tplayers"); + + m_dataModel.Update(); +} + +// this is called every frame, keep that in mind. +void RkHudScoreboard::ShowPanel( bool bShow, bool force ) +{ + if( !m_pInstance ) + return; + + if( bShow ) + { + // Update the information every frame while the scoreboard is open. + Update(); + + if( !m_bVisible ) + { + m_pInstance->Show(); + } + } + else + { + if( m_bVisible ) + { + m_pInstance->Hide(); + } + } + + m_bVisible = bShow; +} + +void RkHudScoreboard::SetActive(bool bActive) +{ + ShowPanel( bActive, false ); + CHudElement::SetActive( bActive ); +} + +bool RkHudScoreboard::ShouldDraw() +{ + int buttons = input->GetButtonBits( false ); + + if( !(buttons & IN_SCORE) ) + return false; + + return cl_drawhud.GetBool() && CHudElement::ShouldDraw(); +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkhud_scoreboard.h b/game/client/cstrike15/RocketUI/rkhud_scoreboard.h new file mode 100644 index 000000000..19e32c23a --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_scoreboard.h @@ -0,0 +1,34 @@ +#ifndef KISAKSTRIKE_RKHUD_SCOREBOARD_H +#define KISAKSTRIKE_RKHUD_SCOREBOARD_H + +#include +#include "hudelement.h" +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h" + +extern ConVar cl_drawhud; + +class RkHudScoreboard : public CHudElement { +public: + explicit RkHudScoreboard(const char *value); + virtual ~RkHudScoreboard(); + + // Overrides from CHudElement + void LevelInit(void); + virtual void LevelShutdown(void); + virtual void SetActive(bool bActive); + virtual bool ShouldDraw(void); + void ShowPanel(bool bShow, bool force); + + Rml::ElementDocument *m_pInstance; + // Some precached elements from the instance. + Rml::Element *m_elemCtSection; + Rml::Element *m_elemTSection; + Rml::DataModelHandle m_dataModel; + + bool m_bVisible; + +private: + void Update(); +}; + +#endif //KISAKSTRIKE_RKHUD_SCOREBOARD_H diff --git a/game/client/cstrike15/RocketUI/rkhud_teammenu.cpp b/game/client/cstrike15/RocketUI/rkhud_teammenu.cpp new file mode 100644 index 000000000..62a501d35 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_teammenu.cpp @@ -0,0 +1,166 @@ +#include "rkhud_teammenu.h" + +#include "cbase.h" +#include "cdll_client_int.h" // extern globals to interfaces like engineclient + +#include // included to fix an error with min/max and rocketui + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +Rml::ElementDocument *RocketTeamMenuDocument::m_pInstance = nullptr; +bool RocketTeamMenuDocument::m_bVisible = false; +bool RocketTeamMenuDocument::m_bGrabbingInput = false; +RocketTeamMenuEventListener* RocketTeamMenuDocument::m_pEventListener = nullptr; + +/* Event Listener added to each team-button */ +class RkTeamMenuButtons : public Rml::EventListener +{ +public: + void ProcessEvent(Rml::Event& keyevent) override + { + // Currently, only mousedown events. + Rml::Element *elem = keyevent.GetTargetElement(); + if( !elem ) + return; + + Rml::String id = elem->GetId(); + if( id == "team_ct" ) + { + RocketTeamMenuDocument::ShowPanel( false ); + engine->ClientCmd_Unrestricted("jointeam 3"); + } + else if( id == "team_t" ) + { + RocketTeamMenuDocument::ShowPanel( false ); + engine->ClientCmd_Unrestricted("jointeam 2"); + } + else if( id == "team_spec" ) + { + RocketTeamMenuDocument::ShowPanel( false ); + engine->ClientCmd_Unrestricted( "jointeam 1"); + } + } +}; + +static RkTeamMenuButtons teamMenuButtonsListener; + +RocketTeamMenuEventListener::~RocketTeamMenuEventListener() +{ +} + +void RocketTeamMenuEventListener::StartAlwaysListenEvents() +{ + ListenForGameEvent( "jointeam_failed" ); + ListenForGameEvent( "player_spawned" ); + ListenForGameEvent( "teamchange_pending" ); +} + +void RocketTeamMenuEventListener::StopAlwaysListenEvents() +{ + StopListeningForAllEvents(); +} + +//listen for a few events related to joining teams. +void RocketTeamMenuEventListener::FireGameEvent(IGameEvent *event) +{ + const char *type = event->GetName(); + + if( !V_strcmp( type, "jointeam_failed" ) ) + { + ConMsg("oy vey the jointeam failed\n"); + } + else if( !V_strcmp( type, "player_spawned" ) ) + { + C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer(); + // If this was us. + if( localPlayer && localPlayer->GetUserID() == event->GetInt( "userid" ) ) + { + RocketTeamMenuDocument::ShowPanel( false, false ); + } + } + else if( !V_strcmp( type, "teamchange_pending" ) ) + { + RocketTeamMenuDocument::ShowPanel( false, false ); + } +} + +RocketTeamMenuDocument::RocketTeamMenuDocument() +{ + +} + +RocketTeamMenuDocument::~RocketTeamMenuDocument() noexcept +{ +} + +void RocketTeamMenuDocument::LoadDialog() +{ + if( !m_pInstance ) + { + m_pInstance = RocketUI()->LoadDocumentFileIntoHud( "body", "GAME", "rocketui/hud_teammenu.rml", RocketTeamMenuDocument::LoadDialog, RocketTeamMenuDocument::UnloadDialog ); + + if( !m_pInstance ) + { + Error( "Couldn't create rocketui team-menu!\n"); + /* Exit */ + } + + // Add a listener to each button, this seems better than custom events for these + Rml::ElementList teamButtons; + m_pInstance->GetElementsByTagName( teamButtons, "button" ); + for( Rml::Element *elem : teamButtons ) + { + elem->AddEventListener( Rml::EventId::Mousedown, &teamMenuButtonsListener ); + } + + m_pEventListener = new RocketTeamMenuEventListener; + m_pEventListener->StartAlwaysListenEvents(); + } +} + +void RocketTeamMenuDocument::UnloadDialog() +{ + if( m_pInstance ) + { + m_pInstance->Close(); + m_pInstance = nullptr; + if( m_pEventListener ) + { + m_pEventListener->StopListeningForAllEvents(); + delete m_pEventListener; + m_pEventListener = nullptr; + } + } +} + +void RocketTeamMenuDocument::ShowPanel(bool bShow, bool immediate) +{ + // oh yeah buddy this'll get called before the loading sometimes + // so if it does, load it for the caller. + if( bShow ) + { + if( !m_pInstance ) + LoadDialog(); + + m_pInstance->Show(); + + if( !m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( true, "TeamMenu" ); + m_bGrabbingInput = true; + } + } + else + { + if( m_pInstance ) + m_pInstance->Hide(); + + if( m_bGrabbingInput ) + { + RocketUI()->DenyInputToGame( false, "TeamMenu" ); + m_bGrabbingInput = false; + } + } + + m_bVisible = bShow; +} diff --git a/game/client/cstrike15/RocketUI/rkhud_teammenu.h b/game/client/cstrike15/RocketUI/rkhud_teammenu.h new file mode 100644 index 000000000..78228e7e1 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkhud_teammenu.h @@ -0,0 +1,37 @@ +#ifndef KISAKSTRIKE_RKHUD_TEAMMENU_H +#define KISAKSTRIKE_RKHUD_TEAMMENU_H + +#include +#include "GameEventListener.h" + +class RocketTeamMenuEventListener : public CGameEventListener +{ +public: + virtual ~RocketTeamMenuEventListener(); + void StartAlwaysListenEvents(); + void StopAlwaysListenEvents(); + virtual void FireGameEvent( IGameEvent *event ); +}; + +class RocketTeamMenuDocument +{ +protected: + static Rml::ElementDocument *m_pInstance; + + RocketTeamMenuDocument( ); + virtual ~RocketTeamMenuDocument(); +public: + static void LoadDialog( void ); + static void UnloadDialog( void ); + static void ShowPanel( bool bShow, bool immediate = false ); + static bool IsActive() { return m_pInstance != nullptr; } + static bool IsVisible() { return m_bVisible; } + static Rml::ElementDocument *GetInstance() { return m_pInstance; } + +private: + static bool m_bVisible; + static bool m_bGrabbingInput; + static RocketTeamMenuEventListener *m_pEventListener; +}; + +#endif //KISAKSTRIKE_RKHUD_TEAMMENU_H diff --git a/game/client/cstrike15/RocketUI/rkmenu_main.cpp b/game/client/cstrike15/RocketUI/rkmenu_main.cpp new file mode 100644 index 000000000..15aeb5646 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkmenu_main.cpp @@ -0,0 +1,77 @@ +#include "rkmenu_main.h" + +#include "../../../../thirdparty/RmlUi/Include/RmlUi/Core.h" + +Rml::ElementDocument *RocketMainMenuDocument::m_pInstance = nullptr; +bool RocketMainMenuDocument::showing = false; +bool RocketMainMenuDocument::grabbingInput = false; + +RocketMainMenuDocument::RocketMainMenuDocument() +{ +} + +void RocketMainMenuDocument::LoadDialog() +{ + if( !m_pInstance ) + { + m_pInstance = RocketUI()->LoadDocumentFileIntoMenu("body", "GAME", "rocketui/menu.rml", RocketMainMenuDocument::LoadDialog, RocketMainMenuDocument::UnloadDialog ); + if( !m_pInstance ) + { + Error("Couldn't create rocketui menu!\n"); + /* Exit */ + } + } +} + +void RocketMainMenuDocument::UnloadDialog() +{ + if( m_pInstance ) + { + m_pInstance->Close(); + m_pInstance = nullptr; + if( grabbingInput ) + { + RocketUI()->DenyInputToGame( false, "MainMenu" ); + grabbingInput = false; + } + } +} + +void RocketMainMenuDocument::UpdateDialog() +{ + // I dont think this is needed here.. + //if( m_pInstance ) + // m_pInstance->UpdateDocument() +} + +void RocketMainMenuDocument::ShowPanel(bool bShow, bool immediate) +{ + // oh yeah buddy this'll get called before the loading sometimes + // so if it does, load it for the caller. + if( bShow ) + { + if( !m_pInstance ) + LoadDialog(); + + m_pInstance->Show(); + + if( !grabbingInput ) + { + RocketUI()->DenyInputToGame( true, "MainMenu" ); + grabbingInput = true; + } + } + else + { + if( m_pInstance ) + m_pInstance->Hide(); + + if( grabbingInput ) + { + RocketUI()->DenyInputToGame( false, "MainMenu" ); + grabbingInput = false; + } + } + + showing = bShow; +} \ No newline at end of file diff --git a/game/client/cstrike15/RocketUI/rkmenu_main.h b/game/client/cstrike15/RocketUI/rkmenu_main.h new file mode 100644 index 000000000..4f24a9a92 --- /dev/null +++ b/game/client/cstrike15/RocketUI/rkmenu_main.h @@ -0,0 +1,26 @@ +#ifndef KISAKSTRIKE_RKMENU_MAIN_H +#define KISAKSTRIKE_RKMENU_MAIN_H + +#include + +class RocketMainMenuDocument +{ +protected: + static Rml::ElementDocument *m_pInstance; + + RocketMainMenuDocument( ); +public: + static void LoadDialog( void ); + static void UnloadDialog( void ); + static void RestorePanel( void ); + static void ShowPanel( bool bShow, bool immediate = false ); + static bool IsActive() { return m_pInstance != nullptr; } + static bool IsVisible() { return showing; } + static void UpdateDialog( void ); + static Rml::ElementDocument *GetInstance() { return m_pInstance; } +private: + static bool showing; + static bool grabbingInput; +}; + +#endif //KISAKSTRIKE_RKMENU_MAIN_H \ No newline at end of file diff --git a/game/client/cstrike15/gameui/BasePanel.cpp b/game/client/cstrike15/gameui/BasePanel.cpp index cccd6d148..50fac5f0f 100644 --- a/game/client/cstrike15/gameui/BasePanel.cpp +++ b/game/client/cstrike15/gameui/BasePanel.cpp @@ -75,6 +75,8 @@ using namespace vgui; #if defined( INCLUDE_SCALEFORM ) #include "loadingscreen_scaleform.h" #include "itempickup_scaleform.h" +#elif defined( INCLUDE_ROCKETUI ) +#include "RocketUI/rkhud_loadingscreen.h" #endif // dgoodenough - limit this to X360 only // PS3_BUILDFIX @@ -578,8 +580,13 @@ CBaseModPanel::CBaseModPanel( const char *panelName ) : Panel(NULL, panelName ) // [jason] Flags to enable/disable scaleform screens during the startup sequence (start screen, mainmenu) m_bForceStartScreen = false; m_bShowStartScreen = true; - m_bScaleformMainMenuEnabled = true; - m_bScaleformPauseMenuEnabled = true; +#if defined( INCLUDE_SCALEFORM ) + m_bScaleformMainMenuEnabled = true; + m_bScaleformPauseMenuEnabled = true; +#elif defined( INCLUDE_ROCKETUI ) + m_bRocketMainMenuEnabled = true; + m_bRocketPauseMenuEnabled = true; +#endif m_bBypassStartScreen = false; m_iIntroMovieButtonPressed = -1; @@ -861,6 +868,12 @@ CON_COMMAND_F( quit_prompt, "Exit the engine.", FCVAR_NONE ) { BasePanel()->OnCommand( "quittodesktop" ); } +//lwss: add server browser console command +CON_COMMAND_F( openserverbrowser, "Opens server browser", 0 ) +{ + BasePanel()->PostMessage( BasePanel(), new KeyValues( "RunMenuCommand", "command", "OpenServerBrowser" ) ); +} +//lwss end //----------------------------------------------------------------------------- // Purpose: paints the main background image @@ -1077,13 +1090,14 @@ void CBaseModPanel::SetBackgroundRenderState(EBackgroundState state) // [jason] Restore the Scaleform main menu when we return to Front End if ( m_eBackgroundState == BACKGROUND_LEVEL || m_eBackgroundState == BACKGROUND_LOADING ) { - if ( IsScaleformMainMenuEnabled() ) + if ( IsScaleformMainMenuEnabled() || IsRocketMainMenuEnabled() ) { // Do not bring main menu up if we're planning to show the start screen as well! if ( !IsStartScreenEnabled() ) { ShowMainMenu( false ); ShowScaleformMainMenu( true ); + ShowRocketMainMenu( true ); } } else @@ -1205,6 +1219,16 @@ void CBaseModPanel::OnLevelLoadingStarted( const char *levelName, bool bShowProg CLoadingScreenScaleform::LoadDialog( ); } } +#elif defined( INCLUDE_ROCKETUI ) + // kick off the rocketui screen load if it hasn't been opened yet + if( !RocketLoadingScreenDocument::IsVisible() ) + { + if( levelName ) + { + // TODO: some fancy stuff with the rocketui loading screen. + } + RocketLoadingScreenDocument::ShowPanel( true ); + } #endif } @@ -1214,7 +1238,7 @@ void CBaseModPanel::OnLevelLoadingStarted( const char *levelName, bool bShowProg void CBaseModPanel::OnLevelLoadingFinished() { // [jason] $FIXME: Switch back to Scaleform, unless we are still using vgui for Pause Menu - if ( m_bScaleformPauseMenuEnabled ) + if ( m_bScaleformPauseMenuEnabled || m_bRocketPauseMenuEnabled ) { ShowMainMenu( false ); } @@ -1551,7 +1575,7 @@ void CBaseModPanel::CompleteStartScreenSignIn( void ) } #endif // _GAMECONSOLE - if ( IsScaleformMainMenuEnabled() ) + if ( IsScaleformMainMenuEnabled() || IsRocketMainMenuEnabled() ) { // Display the scaleform main menu now OnOpenCreateMainMenuScreen( ); @@ -2197,7 +2221,7 @@ void CBaseModPanel::OnGameUIActivated() static ConVarRef cv_console_window_open( "console_window_open" ); if ( !IsPC() || !cv_console_window_open.GetBool() ) { - if (m_bScaleformPauseMenuEnabled) + if (m_bScaleformPauseMenuEnabled || m_bRocketPauseMenuEnabled) { OnOpenPauseMenu(); } @@ -2221,7 +2245,7 @@ void CBaseModPanel::OnGameUIActivated() else // not the pause menu, update presence { // [jason] Safety check: If we're not in level, be sure that the pause menu is hidden - if ( IsScaleformPauseMenuActive() ) + if ( IsScaleformPauseMenuActive() || IsRocketPauseMenuActive() ) { DismissPauseMenu(); } @@ -2229,10 +2253,11 @@ void CBaseModPanel::OnGameUIActivated() // [jason] If we are bringing the main menu UI up again (not start screen or loading) then ensure we have raised the main menu if ( !m_bLevelLoading && !IsScaleformIntroMovieEnabled() && !IsStartScreenActive() && - IsScaleformMainMenuEnabled() && !IsScaleformMainMenuActive() ) + (IsScaleformMainMenuEnabled() && !IsScaleformMainMenuActive()) || (IsRocketMainMenuEnabled() && !IsRocketMainMenuActive()) ) { ShowMainMenu( false ); ShowScaleformMainMenu( true ); + ShowRocketMainMenu( true ); } if ( IsGameConsole() ) @@ -4063,6 +4088,22 @@ bool CBaseModPanel::IsScaleformMainMenuActive( void ) return false; } +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBaseModPanel::ShowRocketMainMenu( bool bShow ) +{ + /** Does nothing by default **/ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CBaseModPanel::IsRocketMainMenuActive( void ) +{ + return false; +} + //----------------------------------------------------------------------------- // Purpose: Overridden if you want to use Scaleform to create the menu //----------------------------------------------------------------------------- @@ -4111,6 +4152,30 @@ bool CBaseModPanel::IsScaleformPauseMenuVisible( void ) return false; } +//----------------------------------------------------------------------------- +// Purpose: To be overridden by RocketUI +//----------------------------------------------------------------------------- +void CBaseModPanel::ShowRocketPauseMenu( bool bShow ) +{ + /** Does nothing by default */ +} + +//----------------------------------------------------------------------------- +// Purpose: To be overridden by RocketUI +//----------------------------------------------------------------------------- +bool CBaseModPanel::IsRocketPauseMenuActive( void ) +{ + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: To be overridden by RocketUI +//----------------------------------------------------------------------------- +bool CBaseModPanel::IsRocketPauseMenuVisible( void ) +{ + return false; +} + //----------------------------------------------------------------------------- // Purpose: Change a private/friends match to a public one //----------------------------------------------------------------------------- @@ -4509,7 +4574,8 @@ void CBaseModPanel::OnCreditsFinished( void ) void CBaseModPanel::OnGameUIHidden() { // [jason] Dismiss Pause menu if we close it via ESC key, etc - if ( IsScaleformPauseMenuEnabled() && IsScaleformPauseMenuActive() ) + if ( (IsScaleformPauseMenuEnabled() && IsScaleformPauseMenuActive()) || + (IsRocketPauseMenuEnabled() && IsRocketPauseMenuActive()) ) { DismissPauseMenu(); } diff --git a/game/client/cstrike15/gameui/basepanel.h b/game/client/cstrike15/gameui/basepanel.h index 3097e5e37..a050527a0 100644 --- a/game/client/cstrike15/gameui/basepanel.h +++ b/game/client/cstrike15/gameui/basepanel.h @@ -287,6 +287,9 @@ class CBaseModPanel : public vgui::Panel void EnableScaleformMainMenu( bool bEnable ) { m_bScaleformMainMenuEnabled = bEnable; } bool IsScaleformMainMenuEnabled( void ) { return m_bScaleformMainMenuEnabled; } + void EnableRocketMainMenu( bool bEnable ) { m_bRocketMainMenuEnabled = bEnable; } + bool IsRocketMainMenuEnabled( void ) { return m_bRocketMainMenuEnabled; } + // [jason] Notification that a vgui dialog has completed, in case we need to restore Scaleform menu void NotifyVguiDialogClosed( void ); @@ -301,9 +304,13 @@ class CBaseModPanel : public vgui::Panel virtual void ShowScaleformPauseMenu( bool bShow ); virtual bool IsScaleformPauseMenuActive( void ); virtual bool IsScaleformPauseMenuVisible( void ); - bool IsScaleformPauseMenuEnabled( void ) { return m_bScaleformPauseMenuEnabled; } + virtual void ShowRocketPauseMenu( bool bShow ); + virtual bool IsRocketPauseMenuActive( void ); + virtual bool IsRocketPauseMenuVisible( void ); + bool IsRocketPauseMenuEnabled( void ) { return m_bRocketPauseMenuEnabled; } + KeyValues *GetConsoleControlSettings( void ); // forces any changed options dialog settings to be applied immediately, if it's open @@ -341,9 +348,11 @@ class CBaseModPanel : public vgui::Panel // [jason] Allow toggle of the new scaleform version of the main menu virtual void ShowScaleformMainMenu( bool bShow ); - virtual bool IsScaleformMainMenuActive( void ); + virtual void ShowRocketMainMenu( bool bShow ); + virtual bool IsRocketMainMenuActive( void ); + virtual bool IsScaleformIntroMovieEnabled( void ) { return false; } virtual void CreateScaleformIntroMovie( void ) {} virtual void DismissScaleformIntroMovie( void ) {} @@ -531,6 +540,10 @@ class CBaseModPanel : public vgui::Panel // [jason] Should we use the Scaleform main menu, or the old vgui one? bool m_bScaleformMainMenuEnabled; bool m_bScaleformPauseMenuEnabled; + // lwss- like the above bools but for rocketui + bool m_bRocketMainMenuEnabled; + bool m_bRocketPauseMenuEnabled; + // lwss end // [jason] Last value that ShowMainMenu was called with: is the old vgui active or not? bool m_bMainMenuShown; diff --git a/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.cpp b/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.cpp index cc16a040c..bc3d50488 100644 --- a/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.cpp +++ b/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.cpp @@ -34,6 +34,9 @@ #include "splitscreensignon.h" #include "messagebox_scaleform.h" #include "itempickup_scaleform.h" +#elif defined(INCLUDE_ROCKETUI) +#include "../RocketUI/rkmenu_main.h" +#include "../RocketUI/rkhud_pausemenu.h" #endif #if defined ( _PS3 ) @@ -154,6 +157,8 @@ CCStrike15BasePanel::~CCStrike15BasePanel() // [jason] Release any screens that may still be active on shutdown so we don't leak memory #if defined(INCLUDE_SCALEFORM) DismissAllMainMenuScreens(); +#elif defined(INCLUDE_ROCKETUI) + DismissAllMainMenuScreens(); #endif } @@ -398,7 +403,7 @@ CON_COMMAND_F( cl_avatar_convert_rgb, "Converts all png avatars in the avatars d g_pFullFileSystem->FindClose( hFind ); } - +// lwss- Overrides for the basepanel if either of these systems are enabled. #if defined(INCLUDE_SCALEFORM) void CCStrike15BasePanel::OnOpenCreateStartScreen( void ) @@ -554,7 +559,7 @@ void CCStrike15BasePanel::OnOpenCreateMultiplayerGameCommunity( void ) m_bCommunityQuickPlayWarningRaised = true; if ( !m_bCommunityServerWarningIssued && player_nevershow_communityservermessage.GetBool() == 0 ) { - OnOpenMessageBoxThreeway( "#SFUI_MainMenu_ServerBrowserWarning_Title", "#SFUI_MainMenu_ServerBrowserWarning_Text2", "#SFUI_MainMenu_ServerBrowserWarning_Legend", "#SFUI_MainMenu_ServerBrowserWarning_NeverShow", ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_TERTIARY ), this ); + OnOpenMessageBoxThreeway( "#SFUI_MainMenu_ServerBrowserWarning_Title", "#SFUI_MainMenu_ServerBrowserWarning_Text2", "#SFUI_MainMenu_ServerBrowserWarning_Legend", "#SFUI_MainMenu_ServerBrowserWarning_NeverShow", ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_TERTIARY ), this ); m_bCommunityQuickPlayWarningRaised = true; } else @@ -575,7 +580,7 @@ void CCStrike15BasePanel::OnOpenServerBrowser() #if !defined(_GAMECONSOLE) if ( !m_bCommunityServerWarningIssued && player_nevershow_communityservermessage.GetBool() == 0 ) { - OnOpenMessageBoxThreeway( "#SFUI_MainMenu_ServerBrowserWarning_Title", "#SFUI_MainMenu_ServerBrowserWarning_Text2", "#SFUI_MainMenu_ServerBrowserWarning_Legend", "#SFUI_MainMenu_ServerBrowserWarning_NeverShow", ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_TERTIARY ), this ); + OnOpenMessageBoxThreeway( "#SFUI_MainMenu_ServerBrowserWarning_Title", "#SFUI_MainMenu_ServerBrowserWarning_Text2", "#SFUI_MainMenu_ServerBrowserWarning_Legend", "#SFUI_MainMenu_ServerBrowserWarning_NeverShow", ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_TERTIARY ), this ); m_bServerBrowserWarningRaised = true; } else @@ -652,7 +657,7 @@ bool CCStrike15BasePanel::ShowLockInput( void ) if ( devCheatSkipInputLocking.GetBool() ) return false; -#if defined( WIN32 ) +#if defined( WIN32 ) if ( g_pScaleformUI ) { g_pScaleformUI->LockMostRecentInputDevice( SF_FULL_SCREEN_SLOT ); @@ -697,13 +702,13 @@ bool CCStrike15BasePanel::ShowLockInput( void ) if( var.IsValid( ) ) var.SetValue( 0 ); } -#endif +#endif + - InputDevice_t currentInputDevice = g_pInputSystem->GetCurrentInputDevice(); - bool hasLockedIntoMotionController = currentInputDevice == INPUT_DEVICE_PLAYSTATION_MOVE || + bool hasLockedIntoMotionController = currentInputDevice == INPUT_DEVICE_PLAYSTATION_MOVE || currentInputDevice == INPUT_DEVICE_SHARPSHOOTER; if ( hasLockedIntoMotionController ) @@ -723,139 +728,139 @@ bool CCStrike15BasePanel::ShowLockInput( void ) return true; } - - return false; + + return false; } void CCStrike15BasePanel::OnOpenPauseMenu( void ) { - CBaseModPanel::OnOpenPauseMenu(); + CBaseModPanel::OnOpenPauseMenu(); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenMouseDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOUSE ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOUSE ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenKeyboardDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_KEYBOARD ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_KEYBOARD ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenControllerDialog( void ) { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_CONTROLLER ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_CONTROLLER ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenMotionControllerMoveDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOTION_CONTROLLER_MOVE ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOTION_CONTROLLER_MOVE ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenMotionControllerSharpshooterDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOTION_CONTROLLER_SHARPSHOOTER ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOTION_CONTROLLER_SHARPSHOOTER ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenMotionControllerDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOTION_CONTROLLER ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_MOTION_CONTROLLER ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenMotionCalibrationDialog() { - CMotionCalibrationScaleform::LoadDialog(); + CMotionCalibrationScaleform::LoadDialog(); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenVideoSettingsDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_VIDEO ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_VIDEO ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenOptionsQueued() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_NONE ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_NONE ); } //----------------------------------------------------------------------------- -// Purpose: +// Purpose: //----------------------------------------------------------------------------- void CCStrike15BasePanel::OnOpenAudioSettingsDialog() { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_AUDIO ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_AUDIO ); } void CCStrike15BasePanel::OnOpenSettingsDialog( void ) { - COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_SETTINGS ); + COptionsScaleform::ShowMenu( true, COptionsScaleform::DIALOG_TYPE_SETTINGS ); } void CCStrike15BasePanel::OnOpenHowToPlayDialog( void ) { - CHowToPlayDialogScaleform::LoadDialog(); + CHowToPlayDialogScaleform::LoadDialog(); } void CCStrike15BasePanel::DismissPauseMenu( void ) { - /* Removed for partner depot */ + /* Removed for partner depot */ } void CCStrike15BasePanel::RestorePauseMenu( void ) { - /* Removed for partner depot */ + /* Removed for partner depot */ } void CCStrike15BasePanel::ShowScaleformPauseMenu( bool bShow ) { - /* Removed for partner depot */ + /* Removed for partner depot */ } bool CCStrike15BasePanel::IsScaleformPauseMenuActive( void ) { - /* Removed for partner depot */ - return false; + /* Removed for partner depot */ + return false; } bool CCStrike15BasePanel::IsScaleformPauseMenuVisible( void ) { - /* Removed for partner depot */ - return false; + /* Removed for partner depot */ + return false; } void CCStrike15BasePanel::OnOpenDisconnectConfirmationDialog( void ) -{ +{ #if defined( INCLUDE_SCALEFORM ) - char const *szTitle = "#SFUI_PauseMenu_ExitGameConfirmation_Title"; + char const *szTitle = "#SFUI_PauseMenu_ExitGameConfirmation_Title"; char const *szMessageDefault = "#SFUI_PauseMenu_ExitGameConfirmation_Message"; char const *szMessage = szMessageDefault; if ( engine->IsHLTV() || engine->IsPlayingDemo() ) @@ -873,7 +878,7 @@ void CCStrike15BasePanel::OnOpenDisconnectConfirmationDialog( void ) { szTitle = "#SFUI_PauseMenu_ExitGameConfirmation_TitleQueuedMatchmaking"; szMessage = "#SFUI_PauseMenu_ExitGameConfirmation_MessageQueuedMatchmaking"; - + if ( CSGameRules()->IsPlayingCooperativeGametype() ) { szTitle = "#SFUI_PauseMenu_ExitGameConfirmation_TitleQueuedGuardian"; @@ -920,247 +925,247 @@ void CCStrike15BasePanel::OnOpenDisconnectConfirmationDialog( void ) OnOpenMessageBox( szTitle, szMessage, "#SFUI_PauseMenu_ExitGameConfirmation_Navigation", ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_BOX_CLOSED | MESSAGEBOX_FLAG_AUTO_CLOSE_ON_DISCONNECT ), this ); #else - BaseClass::OnOpenDisconnectConfirmationDialog(); + BaseClass::OnOpenDisconnectConfirmationDialog(); #endif } void CCStrike15BasePanel::OnOpenQuitConfirmationDialog( bool bForceToDesktop ) -{ +{ #if defined( INCLUDE_SCALEFORM ) - m_bForceQuitToDesktopOnDisconnect = bForceToDesktop; + m_bForceQuitToDesktopOnDisconnect = bForceToDesktop; OnOpenMessageBox( "#SFUI_MainMenu_ExitGameConfirmation_Title", "#SFUI_MainMenu_ExitGameConfirmation_Message", "#SFUI_MainMenu_ExitGameConfirmation_Navigation", ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_BOX_CLOSED ), this ); #else - BaseClass::OnOpenDisconnectConfirmationDialog(); + BaseClass::OnOpenDisconnectConfirmationDialog(); #endif } bool CCStrike15BasePanel::OnMessageBoxEvent( MessageBoxFlags_t buttonPressed ) { - //Special handling for the Server Browser prompt. if we go through here, we return early and never hit the rest of the code - if ( m_bServerBrowserWarningRaised ) - { - if ( (buttonPressed & MESSAGEBOX_FLAG_OK) || (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) ) - { - if (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) - { - player_nevershow_communityservermessage.SetValue( true ); - } + //Special handling for the Server Browser prompt. if we go through here, we return early and never hit the rest of the code + if ( m_bServerBrowserWarningRaised ) + { + if ( (buttonPressed & MESSAGEBOX_FLAG_OK) || (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) ) + { + if (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) + { + player_nevershow_communityservermessage.SetValue( true ); + } - m_bCommunityServerWarningIssued = true; - g_VModuleLoader.ActivateModule("Servers"); - } + m_bCommunityServerWarningIssued = true; + g_VModuleLoader.ActivateModule("Servers"); + } - if ( buttonPressed & MESSAGEBOX_FLAG_CANCEL ) - { - if ( GameUI().IsInLevel() ) - { - RestorePauseMenu(); - } - else - { - RestoreMainMenuScreen(); - } - } - - m_bServerBrowserWarningRaised = false; - return true; - } + if ( buttonPressed & MESSAGEBOX_FLAG_CANCEL ) + { + if ( GameUI().IsInLevel() ) + { + RestorePauseMenu(); + } + else + { + RestoreMainMenuScreen(); + } + } - /* - ( ( CCStrike15BasePanel* )BasePanel() )->OnOpenMessageBoxThreeway( "#SFUI_LobbyGameSettings_Title", - "#SFUI_LobbyGameSettings_Text", - "#SFUI_LobbyGameSettings_Help", - "#SFUI_LobbyGameSettings_QMButton", - ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_TERTIARY ), - this, &m_pConfirmDialog ); - */ + m_bServerBrowserWarningRaised = false; + return true; + } - if ( m_bCommunityQuickPlayWarningRaised ) - { - if ( (buttonPressed & MESSAGEBOX_FLAG_OK) || (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) ) - { - if (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) - { - player_nevershow_communityservermessage.SetValue( true ); - } + /* + ( ( CCStrike15BasePanel* )BasePanel() )->OnOpenMessageBoxThreeway( "#SFUI_LobbyGameSettings_Title", + "#SFUI_LobbyGameSettings_Text", + "#SFUI_LobbyGameSettings_Help", + "#SFUI_LobbyGameSettings_QMButton", + ( MESSAGEBOX_FLAG_OK | MESSAGEBOX_FLAG_CANCEL | MESSAGEBOX_FLAG_TERTIARY ), + this, &m_pConfirmDialog ); + */ - m_bCommunityServerWarningIssued = true; - DoCommunityQuickPlay(); - } + if ( m_bCommunityQuickPlayWarningRaised ) + { + if ( (buttonPressed & MESSAGEBOX_FLAG_OK) || (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) ) + { + if (buttonPressed & MESSAGEBOX_FLAG_TERTIARY) + { + player_nevershow_communityservermessage.SetValue( true ); + } - if ( buttonPressed & MESSAGEBOX_FLAG_CANCEL ) - { - if ( GameUI().IsInLevel() ) - { - RestorePauseMenu(); - } - else - { - RestoreMainMenuScreen(); - } - } + m_bCommunityServerWarningIssued = true; + DoCommunityQuickPlay(); + } - m_bCommunityQuickPlayWarningRaised = false; - return true; - } + if ( buttonPressed & MESSAGEBOX_FLAG_CANCEL ) + { + if ( GameUI().IsInLevel() ) + { + RestorePauseMenu(); + } + else + { + RestoreMainMenuScreen(); + } + } + m_bCommunityQuickPlayWarningRaised = false; + return true; + } - if ( buttonPressed & MESSAGEBOX_FLAG_OK ) - { - if ( GameUI().IsInLevel() && !m_bForceQuitToDesktopOnDisconnect ) - { - // "Exit Game" prompt (disconnect) from within the level - if ( m_bReturnToMPGameMenuOnDisconnect ) - m_OnClosedCommand = ON_CLOSED_DISCONNECT_TO_MP_GAME_MENU; - else - m_OnClosedCommand = ON_CLOSED_DISCONNECT; - } - else - { - // "Quit game" prompt from main menu - m_OnClosedCommand = ON_CLOSED_QUIT; - } - } - else if ( buttonPressed & MESSAGEBOX_FLAG_CANCEL ) - { - // Clear the migrating status, so we can open main menu - if ( IsX360() && m_bMigratingActive ) - { - // Close the multiplayer session to abort the server starting - g_pMatchFramework->CloseSession(); + if ( buttonPressed & MESSAGEBOX_FLAG_OK ) + { + if ( GameUI().IsInLevel() && !m_bForceQuitToDesktopOnDisconnect ) + { + // "Exit Game" prompt (disconnect) from within the level + if ( m_bReturnToMPGameMenuOnDisconnect ) + m_OnClosedCommand = ON_CLOSED_DISCONNECT_TO_MP_GAME_MENU; + else + m_OnClosedCommand = ON_CLOSED_DISCONNECT; + } + else + { + // "Quit game" prompt from main menu + m_OnClosedCommand = ON_CLOSED_QUIT; + } + } - m_bMigratingActive = false; + else if ( buttonPressed & MESSAGEBOX_FLAG_CANCEL ) + { + // Clear the migrating status, so we can open main menu + if ( IsX360() && m_bMigratingActive ) + { + // Close the multiplayer session to abort the server starting + g_pMatchFramework->CloseSession(); - m_OnClosedCommand = ON_CLOSED_RESTORE_MAIN_MENU; - } - else if ( GameUI().IsInLevel() ) - { - m_OnClosedCommand = ON_CLOSED_RESTORE_PAUSE_MENU; - } - else - { - m_OnClosedCommand = ON_CLOSED_RESTORE_MAIN_MENU; - } + m_bMigratingActive = false; - m_bReturnToMPGameMenuOnDisconnect = false; - m_bForceQuitToDesktopOnDisconnect = false; - } + m_OnClosedCommand = ON_CLOSED_RESTORE_MAIN_MENU; + } + else if ( GameUI().IsInLevel() ) + { + m_OnClosedCommand = ON_CLOSED_RESTORE_PAUSE_MENU; + } + else + { + m_OnClosedCommand = ON_CLOSED_RESTORE_MAIN_MENU; + } - else if ( buttonPressed & MESSAGEBOX_FLAG_BOX_CLOSED ) - { - switch ( m_OnClosedCommand ) - { - case ON_CLOSED_DISCONNECT: - { + m_bReturnToMPGameMenuOnDisconnect = false; + m_bForceQuitToDesktopOnDisconnect = false; + } + + else if ( buttonPressed & MESSAGEBOX_FLAG_BOX_CLOSED ) + { + switch ( m_OnClosedCommand ) + { + case ON_CLOSED_DISCONNECT: + { #if defined( _X360 ) - for ( int i=0; iClientCmd_Unrestricted( cmdLine ); } #endif - // Dismiss the pause menu first, so it doesn't restore itself when this dialog goes away - DismissPauseMenu(); - engine->ClientCmd_Unrestricted( "disconnect" ); - break; - } - case ON_CLOSED_QUIT: - { - ConVarRef xbox_arcade_title_unlocked( "xbox_arcade_title_unlocked" ); - bool bResult = xbox_arcade_title_unlocked.GetBool(); + // Dismiss the pause menu first, so it doesn't restore itself when this dialog goes away + DismissPauseMenu(); + engine->ClientCmd_Unrestricted( "disconnect" ); + break; + } + case ON_CLOSED_QUIT: + { + ConVarRef xbox_arcade_title_unlocked( "xbox_arcade_title_unlocked" ); + bool bResult = xbox_arcade_title_unlocked.GetBool(); #if defined( _X360 ) - bResult = xboxsystem && xboxsystem->IsArcadeTitleUnlocked(); + bResult = xboxsystem && xboxsystem->IsArcadeTitleUnlocked(); #elif defined ( _PS3 ) - //$TODO: Hook up PS3 trial mode check + //$TODO: Hook up PS3 trial mode check #endif - if ( bResult ) - { - RunMenuCommand( "QuitNoConfirm" ); - } - else - { - // In trial mode. Show UpSell - RunMenuCommand( "OpenUpsellDialog" ); - } - } - - break; - - case ON_CLOSED_RESTORE_PAUSE_MENU: - RestorePauseMenu(); - break; - - case ON_CLOSED_RESTORE_MAIN_MENU: - RestoreMainMenuScreen(); - break; - - case ON_CLOSED_DISCONNECT_TO_MP_GAME_MENU: - RestoreMPGameMenu(); - break; - - default: - if ( GameUI().IsInLevel() ) - { - RestorePauseMenu(); - } - else - { - RestoreMainMenuScreen(); - } - break; - } + if ( bResult ) + { + RunMenuCommand( "QuitNoConfirm" ); + } + else + { + // In trial mode. Show UpSell + RunMenuCommand( "OpenUpsellDialog" ); + } + } + + break; + + case ON_CLOSED_RESTORE_PAUSE_MENU: + RestorePauseMenu(); + break; + + case ON_CLOSED_RESTORE_MAIN_MENU: + RestoreMainMenuScreen(); + break; + + case ON_CLOSED_DISCONNECT_TO_MP_GAME_MENU: + RestoreMPGameMenu(); + break; + + default: + if ( GameUI().IsInLevel() ) + { + RestorePauseMenu(); + } + else + { + RestoreMainMenuScreen(); + } + break; + } - m_OnClosedCommand = ON_CLOSED_NULL; - } + m_OnClosedCommand = ON_CLOSED_NULL; + } - return true; + return true; } void CCStrike15BasePanel::OnOpenMedalsDialog( ) { #if defined( INCLUDE_SCALEFORM ) - CCreateMedalStatsDialogScaleform::LoadDialog( CCreateMedalStatsDialogScaleform::eDialogType_Medals ); + CCreateMedalStatsDialogScaleform::LoadDialog( CCreateMedalStatsDialogScaleform::eDialogType_Medals ); #endif } void CCStrike15BasePanel::OnOpenStatsDialog( ) { #if defined( INCLUDE_SCALEFORM ) - CCreateMedalStatsDialogScaleform::LoadDialog( CCreateMedalStatsDialogScaleform::eDialogType_Stats_Last_Match ); + CCreateMedalStatsDialogScaleform::LoadDialog( CCreateMedalStatsDialogScaleform::eDialogType_Stats_Last_Match ); #endif } void CCStrike15BasePanel::CloseMedalsStatsDialog( ) { #if defined( INCLUDE_SCALEFORM ) - CCreateMedalStatsDialogScaleform::UnloadDialog( ); + CCreateMedalStatsDialogScaleform::UnloadDialog( ); #endif } void CCStrike15BasePanel::OnOpenLeaderboardsDialog( ) { #if defined( INCLUDE_SCALEFORM ) - CCreateLeaderboardsDialogScaleform::LoadDialog( ); + CCreateLeaderboardsDialogScaleform::LoadDialog( ); #endif } void CCStrike15BasePanel::OnOpenCallVoteDialog( ) { #if defined( INCLUDE_SCALEFORM ) - SFHudCallVotePanel::LoadDialog(); + SFHudCallVotePanel::LoadDialog(); #endif } void CCStrike15BasePanel::OnOpenMarketplace( ) { #ifdef _X360 - // $TODO Replace placeholder offer ID with real one + // $TODO Replace placeholder offer ID with real one engine->ClientCmd( VarArgs("x360_marketplace_offer %d 0x1111111 dl", XSHOWMARKETPLACEDOWNLOADITEMS_ENTRYPOINT_PAIDITEMS ) ); #endif // _X360 @@ -1169,40 +1174,40 @@ void CCStrike15BasePanel::OnOpenMarketplace( ) void CCStrike15BasePanel::UpdateLeaderboardsDialog( ) { #if defined( INCLUDE_SCALEFORM ) - CCreateLeaderboardsDialogScaleform::UpdateDialog( ); + CCreateLeaderboardsDialogScaleform::UpdateDialog( ); #endif } void CCStrike15BasePanel::CloseLeaderboardsDialog( ) { #if defined( INCLUDE_SCALEFORM ) - CCreateLeaderboardsDialogScaleform::UnloadDialog( ); + CCreateLeaderboardsDialogScaleform::UnloadDialog( ); #endif } void CCStrike15BasePanel::OnOpenUpsellDialog( void ) { #if defined( INCLUDE_SCALEFORM ) - CUpsellScaleform::ShowMenu( true ); + CUpsellScaleform::ShowMenu( true ); #endif } void CCStrike15BasePanel::StartExitingProcess( void ) { - if (m_pSplitScreenSignon) - { - m_pSplitScreenSignon->RemoveFlashElement(); - m_pSplitScreenSignon = NULL; - } + if (m_pSplitScreenSignon) + { + m_pSplitScreenSignon->RemoveFlashElement(); + m_pSplitScreenSignon = NULL; + } - CBaseModPanel::StartExitingProcess(); + CBaseModPanel::StartExitingProcess(); } void CCStrike15BasePanel::RunFrame( void ) { #if defined( _X360 ) - - // We have a pending game voice channel check to perform - either prompt user to switch back, or if they failed to + + // We have a pending game voice channel check to perform - either prompt user to switch back, or if they failed to // OK switching back to game voice then quit the game - so run that here: if ( !IsLevelLoading() && m_GameVoiceChannelRecheckTimer.HasStarted() && m_GameVoiceChannelRecheckTimer.IsElapsed() ) { @@ -1222,7 +1227,7 @@ void CCStrike15BasePanel::RunFrame( void ) } else { - // Most likely, we tried to prompt to switch to Game Chat while the guide was open + // Most likely, we tried to prompt to switch to Game Chat while the guide was open // It's closed now, so prompt the user to switch again Xbox_PromptSwitchToGameVoiceChannel(); } @@ -1233,7 +1238,7 @@ void CCStrike15BasePanel::RunFrame( void ) #ifdef _PS3 -#ifndef NO_STEAM + #ifndef NO_STEAM if ( ( s_ePS3SaveInitState == SIS_INIT_REQUESTED ) && s_PS3SaveAsyncStatus.JobDone() ) { @@ -1245,91 +1250,91 @@ void CCStrike15BasePanel::RunFrame( void ) #endif - if ( m_pSplitScreenSignon ) - { - m_pSplitScreenSignon->Update(); - } + if ( m_pSplitScreenSignon ) + { + m_pSplitScreenSignon->Update(); + } - // Handles making sure pupups get the proper updates. Usually just dealing with showing and hiding. - PopupManager::Update(); + // Handles making sure pupups get the proper updates. Usually just dealing with showing and hiding. + PopupManager::Update(); - CBaseModPanel::RunFrame(); + CBaseModPanel::RunFrame(); - // Make sure stats are loaded before showing the start logo. - if ( IsStartScreenEnabled() && GetStatsLoaded() && !m_bStartLogoIsShowing ) - { - // If on PS3, we now show the start menu option. This is only hidden on PS3 in the scaleform so we can - // delay showing it until stats are loaded. + // Make sure stats are loaded before showing the start logo. + if ( IsStartScreenEnabled() && GetStatsLoaded() && !m_bStartLogoIsShowing ) + { + // If on PS3, we now show the start menu option. This is only hidden on PS3 in the scaleform so we can + // delay showing it until stats are loaded. #if defined( INCLUDE_SCALEFORM ) - m_bStartLogoIsShowing = CCreateStartScreenScaleform::ShowStartLogo(); + m_bStartLogoIsShowing = CCreateStartScreenScaleform::ShowStartLogo(); #endif - } + } #ifndef NO_STEAM - if ( s_bSteamOverlayPositionNeedsToBeSet ) - { - s_bSteamOverlayPositionNeedsToBeSet = false; - - ENotificationPosition ePos = k_EPositionTopLeft; - if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "topright" ) ) - ePos = k_EPositionTopRight; - else if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "bottomright" ) ) - ePos = k_EPositionBottomRight; - else if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "bottomleft" ) ) - ePos = k_EPositionBottomLeft; - else if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "topleft" ) ) - ePos = k_EPositionTopLeft; - steamapicontext->SteamUtils()->SetOverlayNotificationPosition( ePos ); - } + if ( s_bSteamOverlayPositionNeedsToBeSet ) + { + s_bSteamOverlayPositionNeedsToBeSet = false; + + ENotificationPosition ePos = k_EPositionTopLeft; + if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "topright" ) ) + ePos = k_EPositionTopRight; + else if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "bottomright" ) ) + ePos = k_EPositionBottomRight; + else if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "bottomleft" ) ) + ePos = k_EPositionBottomLeft; + else if ( !V_stricmp( ui_steam_overlay_notification_position.GetString(), "topleft" ) ) + ePos = k_EPositionTopLeft; + steamapicontext->SteamUtils()->SetOverlayNotificationPosition( ePos ); + } #endif - static bool s_bConnectLobbyChecked = false; - if ( IsPC() && !s_bConnectLobbyChecked && g_flReadyToCheckForPCBootInvite && ( ( Plat_FloatTime() - g_flReadyToCheckForPCBootInvite ) > 2.5f ) ) - { - s_bConnectLobbyChecked = true; + static bool s_bConnectLobbyChecked = false; + if ( IsPC() && !s_bConnectLobbyChecked && g_flReadyToCheckForPCBootInvite && ( ( Plat_FloatTime() - g_flReadyToCheckForPCBootInvite ) > 2.5f ) ) + { + s_bConnectLobbyChecked = true; - // push initial rich presence string - ( void ) clientdll->GetRichPresenceStatusString(); + // push initial rich presence string + ( void ) clientdll->GetRichPresenceStatusString(); - // if we were launched with "+connect_lobby " on the command line, join that lobby immediately - uint64 nLobbyID = 0ull; - sscanf( CommandLine()->ParmValue( "+connect_lobby", "" ), "%llu", &nLobbyID ); - if ( nLobbyID != 0 ) - { - Msg( "Connecting to lobby: 0x%llX\n", nLobbyID ); - KeyValues *kvEvent = new KeyValues( "OnSteamOverlayCall::LobbyJoin" ); - kvEvent->SetUint64( "sessionid", nLobbyID ); - g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvEvent ); - } - // Check if we were launched with +connect command and connect to that server - else if ( char const *szConnectAdr = CommandLine()->ParmValue( "+connect" ) ) - { - Msg( "Executing deferred connect command: %s\n", szConnectAdr ); - engine->ExecuteClientCmd( CFmtStr( "connect %s -%s\n", szConnectAdr, "ConnectStringOnCommandline" ) ); - } - // Check if we were launched with +playcast command and connect to that server - else if ( char const *szPlaycastUrl = CommandLine()->ParmValue( "+playcast" ) ) - { - Msg( "Executing deferred playcast command: %s\n", szPlaycastUrl ); - engine->ExecuteClientCmd( CFmtStr( "playcast %s%s%s\n", ((szPlaycastUrl[0]=='"') ? "" : "\""), szPlaycastUrl, ((szPlaycastUrl[0]=='"') ? "" : "\"" )) ); - } - else if ( char const *szEconActionPreview = CommandLine()->ParmValue( "+csgo_econ_action_preview" ) ) - { - Msg( "Executing deferred econ action preview: %s\n", szEconActionPreview ); - engine->ExecuteClientCmd( CFmtStr( "csgo_econ_action_preview %s\n", szEconActionPreview ) ); - } - else if ( char const *szDownloadMatch = CommandLine()->ParmValue( "+csgo_download_match" ) ) - { - Msg( "Executing deferred download match: %s\n", szDownloadMatch ); - engine->ExecuteClientCmd( CFmtStr( "csgo_download_match %s\n", szDownloadMatch ) ); - } - else if ( char const *szPlayDemoFirstArgumentParm = CommandLine()->ParmValue( "+playdemo" ) ) - { - // need to handle more than one parameter on +playdemo commands - if ( int nPlayDemoParm = CommandLine()->FindParm( "+playdemo" ) ) - { - CUtlBuffer build( 0, 0, CUtlBuffer::TEXT_BUFFER ); - build.PutString( szPlayDemoFirstArgumentParm ); + // if we were launched with "+connect_lobby " on the command line, join that lobby immediately + uint64 nLobbyID = 0ull; + sscanf( CommandLine()->ParmValue( "+connect_lobby", "" ), "%llu", &nLobbyID ); + if ( nLobbyID != 0 ) + { + Msg( "Connecting to lobby: 0x%llX\n", nLobbyID ); + KeyValues *kvEvent = new KeyValues( "OnSteamOverlayCall::LobbyJoin" ); + kvEvent->SetUint64( "sessionid", nLobbyID ); + g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvEvent ); + } + // Check if we were launched with +connect command and connect to that server + else if ( char const *szConnectAdr = CommandLine()->ParmValue( "+connect" ) ) + { + Msg( "Executing deferred connect command: %s\n", szConnectAdr ); + engine->ExecuteClientCmd( CFmtStr( "connect %s -%s\n", szConnectAdr, "ConnectStringOnCommandline" ) ); + } + // Check if we were launched with +playcast command and connect to that server + else if ( char const *szPlaycastUrl = CommandLine()->ParmValue( "+playcast" ) ) + { + Msg( "Executing deferred playcast command: %s\n", szPlaycastUrl ); + engine->ExecuteClientCmd( CFmtStr( "playcast %s%s%s\n", ((szPlaycastUrl[0]=='"') ? "" : "\""), szPlaycastUrl, ((szPlaycastUrl[0]=='"') ? "" : "\"" )) ); + } + else if ( char const *szEconActionPreview = CommandLine()->ParmValue( "+csgo_econ_action_preview" ) ) + { + Msg( "Executing deferred econ action preview: %s\n", szEconActionPreview ); + engine->ExecuteClientCmd( CFmtStr( "csgo_econ_action_preview %s\n", szEconActionPreview ) ); + } + else if ( char const *szDownloadMatch = CommandLine()->ParmValue( "+csgo_download_match" ) ) + { + Msg( "Executing deferred download match: %s\n", szDownloadMatch ); + engine->ExecuteClientCmd( CFmtStr( "csgo_download_match %s\n", szDownloadMatch ) ); + } + else if ( char const *szPlayDemoFirstArgumentParm = CommandLine()->ParmValue( "+playdemo" ) ) + { + // need to handle more than one parameter on +playdemo commands + if ( int nPlayDemoParm = CommandLine()->FindParm( "+playdemo" ) ) + { + CUtlBuffer build( 0, 0, CUtlBuffer::TEXT_BUFFER ); + build.PutString( szPlayDemoFirstArgumentParm ); // append all the stuff upafter the first argument (which is handled above) until the next command line argument (starting with a + or -) // this handles paths with spaces as well as the optional 2 extra parameters for playdemo @@ -1347,16 +1352,16 @@ void CCStrike15BasePanel::RunFrame( void ) } build.PutChar( '\0' ); - Msg( "Executing deferred playdemo: %s\n", (char *)build.Base() ); - engine->ExecuteClientCmd( CFmtStr( "playdemo %s\n", (char *)build.Base() ) ); - } - } - else if ( char const *gcconnect = strstr( CommandLine()->GetCmdLine(), "+gcconnect" ) ) - { - Msg( "Executing deferred gcconnect: %s\n", gcconnect ); - /* Removed for partner depot */ - } - } + Msg( "Executing deferred playdemo: %s\n", (char *)build.Base() ); + engine->ExecuteClientCmd( CFmtStr( "playdemo %s\n", (char *)build.Base() ) ); + } + } + else if ( char const *gcconnect = strstr( CommandLine()->GetCmdLine(), "+gcconnect" ) ) + { + Msg( "Executing deferred gcconnect: %s\n", gcconnect ); + /* Removed for partner depot */ + } + } } void CCStrike15BasePanel::LockInput( void ) @@ -1366,17 +1371,17 @@ void CCStrike15BasePanel::LockInput( void ) m_pSplitScreenSignon->RevertUIToOnePlayerMode(); } - CBaseModPanel::LockInput(); + CBaseModPanel::LockInput(); } void CCStrike15BasePanel::UnlockInput( void ) { - if ( m_pSplitScreenSignon ) - { - m_pSplitScreenSignon->RevertUIToOnePlayerMode(); - } + if ( m_pSplitScreenSignon ) + { + m_pSplitScreenSignon->RevertUIToOnePlayerMode(); + } - CBaseModPanel::UnlockInput(); + CBaseModPanel::UnlockInput(); } void CCStrike15BasePanel::CheckIntroMovieStaticDependencies( void ) @@ -1384,7 +1389,7 @@ void CCStrike15BasePanel::CheckIntroMovieStaticDependencies( void ) m_bTestedStaticIntroMovieDependencies = true; #if defined( _X360 ) - if ( ( XboxLaunch()->GetLaunchFlags() & LF_WARMRESTART ) ) + if ( ( XboxLaunch()->GetLaunchFlags() & LF_WARMRESTART ) ) { // xbox does not play intro startup videos if it restarted itself m_bNeedToStartIntroMovie = false; @@ -1392,18 +1397,18 @@ void CCStrike15BasePanel::CheckIntroMovieStaticDependencies( void ) } #endif - if ( Plat_IsInBenchmarkMode() ) + if ( Plat_IsInBenchmarkMode() ) { m_bNeedToStartIntroMovie = false; - return; + return; } if ( engine->IsInEditMode() || - CommandLine()->CheckParm( "-dev" ) || - CommandLine()->CheckParm( "-novid" ) || - CommandLine()->CheckParm( "-allowdebug" ) || - CommandLine()->CheckParm( "-console" ) || - CommandLine()->CheckParm( "-toconsole" ) ) + CommandLine()->CheckParm( "-dev" ) || + CommandLine()->CheckParm( "-novid" ) || + CommandLine()->CheckParm( "-allowdebug" ) || + CommandLine()->CheckParm( "-console" ) || + CommandLine()->CheckParm( "-toconsole" ) ) { m_bNeedToStartIntroMovie = false; return; @@ -1501,7 +1506,7 @@ void CCStrike15BasePanel::ShowFatalError( uint32 unSize ) Q_wcsncpy( wszBuffer, szNoSpacePart1, 2 * ( nLen1 + nLen2 + 100 ) ); Q_snwprintf( wszBuffer + Q_wcslen( wszBuffer ), 2*100, L"%u", nMbRequired ); Q_wcsncpy( wszBuffer + Q_wcslen( wszBuffer ), szNoSpacePart2, 2*( nLen2 + 1 ) ); - + // Set the body of the message to be the same as the title until we actually set the message. OnOpenMessageBox( "#SFUI_MsgBx_AttractDeviceFullC", "#SFUI_Boot_ErrorFatal", " ", MESSAGEBOX_FLAG_INVALID, this, NULL, wszBuffer ); @@ -1578,7 +1583,7 @@ void CCStrike15BasePanel::PerformPS3GameBootWork() // Install PS3 trophies m_CallbackOnPS3TrophiesInstalled.Register( this, &CCStrike15BasePanel::Steam_OnPS3TrophiesInstalled ); - steamapicontext->SteamUserStats()->InstallPS3Trophies(); + steamapicontext->SteamUserStats()->InstallPS3Trophies(); } void CCStrike15BasePanel::Steam_OnPS3TrophiesInstalled( PS3TrophiesInstalled_t *pParam ) @@ -1597,7 +1602,7 @@ void CCStrike15BasePanel::Steam_OnPS3TrophiesInstalled( PS3TrophiesInstalled_t * if ( eResult == k_EResultOK ) { - + CMessageBoxScaleform::UnloadAllDialogs( true ); OnOpenMessageBox("#SFUI_PS3_LOADING_TITLE", "#SFUI_PS3_LOADING_INIT_SAVE_UTILITY", "", MESSAGEBOX_FLAG_INVALID, this ); @@ -1628,5 +1633,269 @@ void CCStrike15BasePanel::Steam_OnUserStatsReceived( UserStatsReceived_t *pParam #endif // !NO_STEAM && _PS3 +#elif defined(INCLUDE_ROCKETUI) +void CCStrike15BasePanel::OnOpenCreateStartScreen( void ) +{ +} + +void CCStrike15BasePanel::DismissStartScreen() +{ +} + +bool CCStrike15BasePanel::IsStartScreenActive() +{ + return false; +} + +void CCStrike15BasePanel::OnOpenCreateMainMenuScreen( void ) +{ + ListenForGameEvent( "player_team" ); + ListenForGameEvent( "cs_game_disconnected" ); + + RocketMainMenuDocument::LoadDialog( ); +} + +void CCStrike15BasePanel::DismissMainMenuScreen( void ) +{ + RocketMainMenuDocument::UnloadDialog( ); +} + +void CCStrike15BasePanel::DismissAllMainMenuScreens( bool bHideMainMenuOnly ) +{ + // Either hide the menus, or tear them down. + if( bHideMainMenuOnly ) + { + if( CCStrike15BasePanel::IsRocketMainMenuEnabled() ) + RocketMainMenuDocument::ShowPanel( false ); + } + else + { + CCStrike15BasePanel::DismissMainMenuScreen(); + CCStrike15BasePanel::DismissPauseMenu(); + } + + // Close all menu screens that may have been opened from main or pause menu +} + +void CCStrike15BasePanel::RestoreMainMenuScreen( void ) +{ + +} + +void CCStrike15BasePanel::RestoreMPGameMenu( void ) +{ + +} + +void CCStrike15BasePanel::ShowRocketMainMenu( bool bShow ) +{ + if( bShow && !IsRocketMainMenuEnabled() ) + return; + + RocketMainMenuDocument::ShowPanel( bShow ); +} + +bool CCStrike15BasePanel::IsRocketMainMenuActive( void ) +{ + return RocketMainMenuDocument::IsActive(); +} + +void CCStrike15BasePanel::OnOpenCreateSingleplayerGameDialog( bool bMatchmakingFilter ) +{ + /* Removed for partner depot */ +} + +void CCStrike15BasePanel::OnOpenCreateMultiplayerGameDialog( void ) +{ + // Continue to support the vgui create server dialog + CBaseModPanel::OnOpenCreateMultiplayerGameDialog(); +} + +void CCStrike15BasePanel::OnOpenCreateMultiplayerGameCommunity( void ) +{ + +} + + +void CCStrike15BasePanel::DoCommunityQuickPlay( void ) +{ +} + +void CCStrike15BasePanel::OnOpenServerBrowser() +{ +#if !defined(_GAMECONSOLE) + g_VModuleLoader.ActivateModule("Servers"); +#endif +} + +void CCStrike15BasePanel::OnOpenCreateLobbyScreen( bool bIsHost ) +{ +} + +void CCStrike15BasePanel::OnOpenLobbyBrowserScreen( bool bIsHost ) +{ +} + +void CCStrike15BasePanel::UpdateLobbyScreen( ) +{ +} + +void CCStrike15BasePanel::UpdateMainMenuScreen() +{ +} + +void CCStrike15BasePanel::UpdateLobbyBrowser( ) +{ +} + +void CCStrike15BasePanel::ShowMatchmakingStatus( void ) +{ +} + +void CCStrike15BasePanel::OnOpenPauseMenu( void ) +{ + ConMsg("OnOpenPauseMenu\n"); + ShowRocketPauseMenu( true ); + //CBaseModPanel::OnOpenPauseMenu(); +} + +void CCStrike15BasePanel::OnOpenMouseDialog() +{ +} + +void CCStrike15BasePanel::OnOpenKeyboardDialog() +{ +} + +void CCStrike15BasePanel::OnOpenControllerDialog( void ) +{ +} + +void CCStrike15BasePanel::OnOpenMotionControllerMoveDialog() +{ +} + +void CCStrike15BasePanel::OnOpenMotionControllerSharpshooterDialog() +{ +} -#endif // INCLUDE_SCALEFORM +void CCStrike15BasePanel::OnOpenMotionControllerDialog() +{ +} + +void CCStrike15BasePanel::OnOpenMotionCalibrationDialog() +{ +} + +void CCStrike15BasePanel::OnOpenVideoSettingsDialog() +{ +} + + +void CCStrike15BasePanel::OnOpenOptionsQueued() +{ +} + +void CCStrike15BasePanel::OnOpenAudioSettingsDialog() +{ +} + +void CCStrike15BasePanel::OnOpenSettingsDialog( void ) +{ +} + +void CCStrike15BasePanel::OnOpenHowToPlayDialog( void ) +{ +} + +void CCStrike15BasePanel::DismissPauseMenu( void ) +{ + ShowRocketPauseMenu( false ); +} + +void CCStrike15BasePanel::RestorePauseMenu( void ) +{ + ShowRocketPauseMenu( true ); +} + +void CCStrike15BasePanel::ShowRocketPauseMenu( bool bShow ) +{ + RocketPauseMenuDocument::ShowPanel( bShow, true ); +} + +bool CCStrike15BasePanel::IsRocketPauseMenuActive( void ) +{ + return RocketPauseMenuDocument::IsActive(); +} + +bool CCStrike15BasePanel::IsRocketPauseMenuVisible( void ) +{ + return RocketPauseMenuDocument::IsVisible(); +} + +void CCStrike15BasePanel::OnOpenDisconnectConfirmationDialog( void ) +{ +} + +void CCStrike15BasePanel::OnOpenQuitConfirmationDialog( bool bForceToDesktop ) +{ +} + + +void CCStrike15BasePanel::OnOpenMedalsDialog( ) +{ +} + +void CCStrike15BasePanel::OnOpenStatsDialog( ) +{ +} + +void CCStrike15BasePanel::CloseMedalsStatsDialog( ) +{ +} + +void CCStrike15BasePanel::OnOpenLeaderboardsDialog( ) +{ +} + +void CCStrike15BasePanel::OnOpenCallVoteDialog( ) +{ +} + +void CCStrike15BasePanel::OnOpenMarketplace( ) +{ +} + +void CCStrike15BasePanel::UpdateLeaderboardsDialog( ) +{ +} + +void CCStrike15BasePanel::CloseLeaderboardsDialog( ) +{ +} + +void CCStrike15BasePanel::OnOpenUpsellDialog( void ) +{ +} + +void CCStrike15BasePanel::StartExitingProcess( void ) +{ + //TODO: rocketui shutdown here. + CBaseModPanel::StartExitingProcess(); +} + +void CCStrike15BasePanel::RunFrame( void ) +{ + CBaseModPanel::RunFrame(); +} + +void CCStrike15BasePanel::LockInput( void ) +{ + CBaseModPanel::LockInput(); +} + +void CCStrike15BasePanel::UnlockInput( void ) +{ + CBaseModPanel::UnlockInput(); +} +#endif // INCLUDE_SCALEFORM/ROCKETUI diff --git a/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.h b/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.h index 90b270202..8a2fbfc18 100644 --- a/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.h +++ b/game/client/cstrike15/gameui/cstrike15/cstrike15basepanel.h @@ -150,8 +150,79 @@ class CCStrike15BasePanel: public CBaseModPanel, public IMatchEventsSink, public virtual void OnPlayCreditsVideo( void ); void CheckIntroMovieStaticDependencies( void ); +#elif defined(INCLUDE_ROCKETUI) + virtual void OnOpenCreateStartScreen( void ); // [jason] provides the "Press Start" screen interface + virtual void DismissStartScreen( void ); + virtual bool IsStartScreenActive( void ); + + virtual void OnOpenCreateMainMenuScreen( void ); + virtual void DismissMainMenuScreen( void ); + virtual void RestoreMainMenuScreen( void ); + virtual void DismissAllMainMenuScreens( bool bHideMainMenuOnly = false ); + + void RestoreMPGameMenu( void ); + + virtual void ShowRocketMainMenu( bool bShow ); + virtual bool IsRocketMainMenuActive( void ); + + virtual void ShowRocketPauseMenu( bool bShow ); + virtual bool IsRocketPauseMenuActive( void ); + virtual bool IsRocketPauseMenuVisible( void ); + + virtual void OnOpenCreateSingleplayerGameDialog( bool bMatchmakingFilter ); + virtual void OnOpenCreateMultiplayerGameDialog( void ); + virtual void OnOpenCreateMultiplayerGameCommunity( void ); + virtual void OnOpenDisconnectConfirmationDialog( void ); + virtual void OnOpenQuitConfirmationDialog( bool bForceToDesktop = false ); + + virtual void OnOpenServerBrowser(); + virtual void OnOpenCreateLobbyScreen( bool bIsHost = false ); + virtual void OnOpenLobbyBrowserScreen( bool bIsHost = false ); + virtual void UpdateLobbyScreen( void ); + virtual void UpdateMainMenuScreen(); + virtual void UpdateLobbyBrowser( void ); + + virtual void ShowMatchmakingStatus( void ); + + virtual void OnOpenPauseMenu( void ); + virtual void DismissPauseMenu( void ); + virtual void RestorePauseMenu( void ); + virtual void OnOpenControllerDialog( void ); + virtual void OnOpenSettingsDialog( void ); + virtual void OnOpenMouseDialog(); + virtual void OnOpenKeyboardDialog(); + virtual void OnOpenMotionControllerMoveDialog(); + virtual void OnOpenMotionControllerSharpshooterDialog(); + virtual void OnOpenMotionControllerDialog(); + virtual void OnOpenMotionCalibrationDialog(); + virtual void OnOpenVideoSettingsDialog(); + virtual void OnOpenOptionsQueued(); + virtual void OnOpenAudioSettingsDialog(); + + virtual void OnOpenUpsellDialog( void ); + + virtual void OnOpenHowToPlayDialog( void ); + + virtual void OnOpenMedalsDialog(); + virtual void OnOpenStatsDialog(); + virtual void CloseMedalsStatsDialog(); -#endif// Scaleform + + virtual void OnOpenLeaderboardsDialog(); + virtual void OnOpenCallVoteDialog(); + virtual void OnOpenMarketplace(); + virtual void UpdateLeaderboardsDialog(); + virtual void CloseLeaderboardsDialog(); + virtual void StartExitingProcess( void ); + + virtual void RunFrame( void ); + + void DoCommunityQuickPlay( void ); + +protected: + virtual void LockInput( void ); + virtual void UnlockInput( void ); +#endif// Scaleform/RocketUI protected: enum CCSOnClosedCommand diff --git a/game/client/cstrike15/gameui/gameui_interface.cpp b/game/client/cstrike15/gameui/gameui_interface.cpp index 256b59f43..ee8a52381 100644 --- a/game/client/cstrike15/gameui/gameui_interface.cpp +++ b/game/client/cstrike15/gameui/gameui_interface.cpp @@ -181,6 +181,11 @@ IScaleformUI* ScaleformUI() { return g_pScaleformUI; } +#elif defined( INCLUDE_ROCKETUI ) +//IRocketUI* RocketUI() +//{ +// return g_pRocketUI; +//} #endif @@ -1112,6 +1117,7 @@ bool CGameUI::SetShowProgressText( bool show ) #if defined( INCLUDE_SCALEFORM ) return CLoadingScreenScaleform::SetShowProgressText( show ); #endif + return false; } diff --git a/game/client/hud_basechat.cpp b/game/client/hud_basechat.cpp index 9e0a08785..f9e52b2d0 100644 --- a/game/client/hud_basechat.cpp +++ b/game/client/hud_basechat.cpp @@ -85,10 +85,12 @@ static const char *gBugTokenTable[] = { inline void CS15ForwardStatusMsg( const char* text, int clientid ) { /* Removed for partner depot */ + ConMsg("[forwardstatusmsg]%s", text); } inline void CS15ForwardStatusMsg( const wchar_t* text, int clientid ) { /* Removed for partner depot */ + ConMsg("[forwardstatusmsg]%ls", text); } #endif // CSTRIKE15 diff --git a/game/client/iclientmode.h b/game/client/iclientmode.h index 9c71b55db..e992604cf 100644 --- a/game/client/iclientmode.h +++ b/game/client/iclientmode.h @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // @@ -10,11 +10,13 @@ #define ICLIENTMODE_H #include +#include class CViewSetup; class C_BaseEntity; class C_BasePlayer; class CUserCmd; +class AudioState_t; namespace vgui { diff --git a/game/client/view.cpp b/game/client/view.cpp index 304964962..b86ad1bbe 100644 --- a/game/client/view.cpp +++ b/game/client/view.cpp @@ -1210,6 +1210,16 @@ void CViewRender::Render( vrect_t *rect ) pRenderContext->Flush(); pRenderContext.SafeRelease(); } +#elif defined( INCLUDE_ROCKETUI ) +// Don't think we need this right now, needs the opengl state to be set up differently. +// { +// CMatRenderContextPtr pRenderContext( materials ); +// +// pRenderContext->DoRocketRender(); +// +// pRenderContext->Flush(); +// pRenderContext.SafeRelease(); +// } #endif { diff --git a/game/client/viewrender.cpp b/game/client/viewrender.cpp index 06995ed92..8f159ce35 100644 --- a/game/client/viewrender.cpp +++ b/game/client/viewrender.cpp @@ -3575,6 +3575,9 @@ void CViewRender::RenderView( const CViewSetup &view, const CViewSetup &hudViewS #if defined( INCLUDE_SCALEFORM ) pRenderContext->SetScaleformSlotViewport( SF_SS_SLOT( slot ), hudViewSetup.x, hudViewSetup.y, hudViewSetup.width, hudViewSetup.height ); pRenderContext->AdvanceAndRenderScaleformSlot( SF_SS_SLOT( slot ) ); +#elif defined( INCLUDE_ROCKETUI ) + //TODO: splitscreen slot rocket ui + pRenderContext->RenderRocketHUD(); #endif pRenderContext->Flush(); } diff --git a/game/shared/cstrike15/cs_gamemovement.cpp b/game/shared/cstrike15/cs_gamemovement.cpp index bc8037c86..bd6eb10f2 100644 --- a/game/shared/cstrike15/cs_gamemovement.cpp +++ b/game/shared/cstrike15/cs_gamemovement.cpp @@ -1,4 +1,4 @@ -//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// +//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // diff --git a/game/shared/econ/econ_item_schema.h b/game/shared/econ/econ_item_schema.h index 068abb85e..6cbb6c8de 100644 --- a/game/shared/econ/econ_item_schema.h +++ b/game/shared/econ/econ_item_schema.h @@ -35,6 +35,7 @@ #include "materialsystem/imaterialsystem.h" #include "mathlib/expressioncalculator.h" +#include "ai_activity.h" #if defined(CLIENT_DLL) || defined(GAME_DLL) #include "weapon_parse.h" diff --git a/interfaces/interfaces.cpp b/interfaces/interfaces.cpp index d264a6925..fc2542366 100644 --- a/interfaces/interfaces.cpp +++ b/interfaces/interfaces.cpp @@ -1,4 +1,4 @@ -//===== Copyright © 2005-2005, Valve Corporation, All rights reserved. ======// +//===== Copyright � 2005-2005, Valve Corporation, All rights reserved. ======// // // Purpose: A higher level link library for general use in the game and tools. // @@ -63,6 +63,8 @@ IGameUISystemMgr *g_pGameUISystemMgr = 0; #if defined( INCLUDE_SCALEFORM ) IScaleformUI *g_pScaleformUI = 0; +#elif defined( INCLUDE_ROCKETUI ) +IRocketUI *g_pRocketUI = 0; #endif //----------------------------------------------------------------------------- @@ -171,6 +173,8 @@ static InterfaceGlobals_t g_pInterfaceGlobals[] = #if defined( INCLUDE_SCALEFORM ) { SCALEFORMUI_INTERFACE_VERSION, &g_pScaleformUI }, +#elif defined( INCLUDE_ROCKETUI ) + { ROCKETUI_INTERFACE_VERSION, &g_pRocketUI }, #endif }; diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 14ecb60e0..aeed247d8 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -27,6 +27,8 @@ include(${CMAKE_MODULE_PATH}/source_dll_base.cmake) add_definitions(-DLAUNCHERONLY -DALLOW_TEXT_MODE=1) if( USE_SCALEFORM ) add_definitions(-DINCLUDE_SCALEFORM) +elseif( USE_ROCKETUI ) + add_definitions(-DINCLUDE_ROCKETUI) endif() if( LINUXALL ) diff --git a/launcher/launcher.cpp b/launcher/launcher.cpp index df57dee91..b54b1ff15 100644 --- a/launcher/launcher.cpp +++ b/launcher/launcher.cpp @@ -807,6 +807,16 @@ bool CSourceAppSystemGroup::Create() if ( !AddSystems( scaleformInfo ) ) return false; } +#elif defined( INCLUDE_ROCKETUI ) + // This is where the rocketui dll actually gets loaded. + AppSystemInfo_t rocketInfo[] = + { + { LAUNCHER_APPSYSTEM( "rocketui" ), ROCKETUI_INTERFACE_VERSION }, + { "", "" } + }; + + if ( !AddSystems( rocketInfo ) ) + return false; #endif // INCLUDE_SCALEFORM // Hook in datamodel and p4 control if we're running with -tools diff --git a/materialsystem/CMakeLists.txt b/materialsystem/CMakeLists.txt index 307f091b1..5ef77b65c 100644 --- a/materialsystem/CMakeLists.txt +++ b/materialsystem/CMakeLists.txt @@ -21,6 +21,8 @@ set(STDSHADERSDIR "stdshaders") add_definitions(-DDEFINE_MATERIALSYSTEM_INTERFACE -DMATERIALSYSTEM_EXPORTS -DPROTECTED_THINGS_ENABLE) if( USE_SCALEFORM ) add_definitions(-DINCLUDE_SCALEFORM) +elseif( USE_ROCKETUI ) + add_definitions(-DINCLUDE_ROCKETUI) endif() add_definitions(-DVERSION_SAFE_STEAM_API_INTERFACES) diff --git a/materialsystem/cmaterialsystem.cpp b/materialsystem/cmaterialsystem.cpp index c97977588..ca2f40cc3 100644 --- a/materialsystem/cmaterialsystem.cpp +++ b/materialsystem/cmaterialsystem.cpp @@ -104,6 +104,8 @@ IMaterialInternal *g_pErrorMaterial = NULL; #if defined( INCLUDE_SCALEFORM ) extern IScaleformUI* g_pScaleformUI; +#elif defined( INCLUDE_ROCKETUI ) +extern IRocketUI* g_pRocketUI; #endif CreateInterfaceFn g_fnMatSystemConnectCreateInterface = NULL; @@ -858,6 +860,8 @@ bool CMaterialSystem::Connect( CreateInterfaceFn factory ) #if defined( INCLUDE_SCALEFORM ) g_pScaleformUI = ( IScaleformUI* ) factory( SCALEFORMUI_INTERFACE_VERSION, 0 ); +#elif defined( INCLUDE_ROCKETUI ) + g_pRocketUI = ( IRocketUI* ) factory( ROCKETUI_INTERFACE_VERSION, 0 ); #endif return g_pShaderDeviceMgr->Connect( ShaderFactory ); @@ -885,6 +889,8 @@ void CMaterialSystem::Disconnect() #if defined( INCLUDE_SCALEFORM ) g_pScaleformUI = NULL; +#elif defined( INCLUDE_ROCKETUI ) + g_pRocketUI = NULL; #endif BaseClass::Disconnect(); diff --git a/materialsystem/cmatnullrendercontext.cpp b/materialsystem/cmatnullrendercontext.cpp index 9930b8198..fc56638cd 100644 --- a/materialsystem/cmatnullrendercontext.cpp +++ b/materialsystem/cmatnullrendercontext.cpp @@ -1,4 +1,4 @@ -//========== Copyright © 2005, Valve Corporation, All rights reserved. ======== +//========== Copyright � 2005, Valve Corporation, All rights reserved. ======== // // Purpose: // @@ -959,6 +959,9 @@ class CMatNullRenderContext : public CMatRenderContextBase virtual void RenderScaleformCursor() { Assert (0); } virtual void AdvanceAndRenderScaleformSlot( int slot ) { Assert (0); } virtual void AdvanceAndRenderScaleformCursor() { Assert (0); } +#elif defined( INCLUDE_ROCKETUI ) + virtual void RenderRocketHUD(){ Assert(0); } + virtual void RenderRocketMenu(){ Assert(0); } #endif //-------------------------------------------------------- diff --git a/materialsystem/cmatqueuedrendercontext.h b/materialsystem/cmatqueuedrendercontext.h index 725aa9b3e..52564d5f8 100644 --- a/materialsystem/cmatqueuedrendercontext.h +++ b/materialsystem/cmatqueuedrendercontext.h @@ -743,6 +743,9 @@ class CMatQueuedRenderContext : public CMatRenderContextBase // renderSlot can be queued RenderScaleformCursor(); } +#elif defined( INCLUDE_ROCKETUI ) + DEFINE_QUEUED_CALL_0( RenderRocketHUD, IMatRenderContext, m_pHardwareContext ); + DEFINE_QUEUED_CALL_0( RenderRocketMenu, IMatRenderContext, m_pHardwareContext ); #endif // INCLUDE_SCALEFORM virtual ColorCorrectionHandle_t FindLookup( const char *pName ); diff --git a/materialsystem/cmatrendercontext.h b/materialsystem/cmatrendercontext.h index 8386d5eb0..f21bcfa54 100644 --- a/materialsystem/cmatrendercontext.h +++ b/materialsystem/cmatrendercontext.h @@ -678,6 +678,15 @@ class CMatRenderContext : public CMatRenderContextBase void AdvanceAndRenderScaleformSlot( int slot ) { ScaleformUI()->AdvanceSlot( slot ); ScaleformUI()->RenderSlot( slot ); } void AdvanceAndRenderScaleformCursor() { ScaleformUI()->AdvanceCursor(); ScaleformUI()->RenderCursor(); } +#elif defined( INCLUDE_ROCKETUI ) + virtual void RenderRocketHUD() + { + RocketUI()->RenderHUDFrame(); + } + virtual void RenderRocketMenu() + { + RocketUI()->RenderMenuFrame(); + } #endif // INCLUDE_SCALEFORM DELEGATE_TO_OBJECT_1( ColorCorrectionHandle_t, FindLookup, const char *, g_pColorCorrectionSystem ); diff --git a/materialsystem/mat_stub.cpp b/materialsystem/mat_stub.cpp index 75393b12e..61500283a 100644 --- a/materialsystem/mat_stub.cpp +++ b/materialsystem/mat_stub.cpp @@ -2557,6 +2557,9 @@ class CDummyMaterialSystem : public IMaterialSystemStub, public CRefCounted1Open( rocketPath.c_str(), "r", "GAME" ); +} + +void RocketFileSystem::Close(Rml::FileHandle file) +{ + g_pFullFileSystem->Close( (FileHandle_t)file ); +} + +size_t RocketFileSystem::Read(void *buffer, size_t size, Rml::FileHandle file) +{ + return g_pFullFileSystem->Read( buffer, size, (FileHandle_t)file ); +} + +bool RocketFileSystem::Seek(Rml::FileHandle file, long offset, int origin) +{ + g_pFullFileSystem->Seek( (FileHandle_t)file, offset, (FileSystemSeek_t)origin ); + return true; +} + +size_t RocketFileSystem::Tell(Rml::FileHandle file) +{ + return g_pFullFileSystem->Tell( (FileHandle_t)file ); +} + +size_t RocketFileSystem::Length(Rml::FileHandle file) +{ + return g_pFullFileSystem->Size( (FileHandle_t)file ); +} \ No newline at end of file diff --git a/rocketui/rocketfilesystem.h b/rocketui/rocketfilesystem.h new file mode 100644 index 000000000..95dfbf414 --- /dev/null +++ b/rocketui/rocketfilesystem.h @@ -0,0 +1,45 @@ +#ifndef KISAKSTRIKE_ROCKETFILESYSTEM_H +#define KISAKSTRIKE_ROCKETFILESYSTEM_H + +#include + +class RocketFileSystem : public Rml::FileInterface +{ + /** singleton support **/ +public: + static RocketFileSystem m_Instance; + RocketFileSystem(); + + /// Opens a file. + /// @param file The file handle to write to. + /// @return A valid file handle, or nullptr on failure + virtual Rml::FileHandle Open(const Rml::String& path) override; + /// Closes a previously opened file. + /// @param file The file handle previously opened through Open(). + virtual void Close(Rml::FileHandle file) override; + + /// Reads data from a previously opened file. + /// @param buffer The buffer to be read into. + /// @param size The number of bytes to read into the buffer. + /// @param file The handle of the file. + /// @return The total number of bytes read into the buffer. + virtual size_t Read(void* buffer, size_t size, Rml::FileHandle file) override; + /// Seeks to a point in a previously opened file. + /// @param file The handle of the file to seek. + /// @param offset The number of bytes to seek. + /// @param origin One of either SEEK_SET (seek from the beginning of the file), SEEK_END (seek from the end of the file) or SEEK_CUR (seek from the current file position). + /// @return True if the operation completed successfully, false otherwise. + virtual bool Seek(Rml::FileHandle file, long offset, int origin) override; + /// Returns the current position of the file pointer. + /// @param file The handle of the file to be queried. + /// @return The number of bytes from the origin of the file. + virtual size_t Tell(Rml::FileHandle file) override; + + /// Returns the length of the file. + /// The default implementation uses Seek & Tell. + /// @param file The handle of the file to be queried. + /// @return The length of the file in bytes. + virtual size_t Length(Rml::FileHandle file) override; +}; + +#endif //KISAKSTRIKE_ROCKETFILESYSTEM_H \ No newline at end of file diff --git a/rocketui/rocketkeys.h b/rocketui/rocketkeys.h new file mode 100644 index 000000000..c8c5ff335 --- /dev/null +++ b/rocketui/rocketkeys.h @@ -0,0 +1,543 @@ +#pragma once + +#include +#include + +// Keycode converter helper. +inline const Rml::Input::KeyIdentifier ButtonToRocketKey( const ButtonCode_t button ) +{ + using namespace Rml::Input; + + switch( button ) + { + case KEY_0: + return KI_0; + case KEY_1: + return KI_1; + case KEY_2: + return KI_2; + case KEY_3: + return KI_3; + case KEY_4: + return KI_4; + case KEY_5: + return KI_5; + case KEY_6: + return KI_6; + case KEY_7: + return KI_7; + case KEY_8: + return KI_8; + case KEY_9: + return KI_9; + case KEY_A: + return KI_A; + case KEY_B: + return KI_B; + case KEY_C: + return KI_C; + case KEY_D: + return KI_D; + case KEY_E: + return KI_E; + case KEY_F: + return KI_F; + case KEY_G: + return KI_G; + case KEY_H: + return KI_H; + case KEY_I: + return KI_I; + case KEY_J: + return KI_J; + case KEY_K: + return KI_K; + case KEY_L: + return KI_L; + case KEY_M: + return KI_M; + case KEY_N: + return KI_N; + case KEY_O: + return KI_O; + case KEY_P: + return KI_P; + case KEY_Q: + return KI_Q; + case KEY_R: + return KI_R; + case KEY_S: + return KI_S; + case KEY_T: + return KI_T; + case KEY_U: + return KI_U; + case KEY_V: + return KI_V; + case KEY_W: + return KI_W; + case KEY_X: + return KI_X; + case KEY_Y: + return KI_Y; + case KEY_Z: + return KI_Z; + case KEY_PAD_0: + return KI_NUMPAD0; + case KEY_PAD_1: + return KI_NUMPAD1; + case KEY_PAD_2: + return KI_NUMPAD2; + case KEY_PAD_3: + return KI_NUMPAD3; + case KEY_PAD_4: + return KI_NUMPAD4; + case KEY_PAD_5: + return KI_NUMPAD5; + case KEY_PAD_6: + return KI_NUMPAD6; + case KEY_PAD_7: + return KI_NUMPAD7; + case KEY_PAD_8: + return KI_NUMPAD8; + case KEY_PAD_9: + return KI_NUMPAD9; + case KEY_PAD_DIVIDE: + return KI_DIVIDE; + case KEY_PAD_MULTIPLY: + return KI_MULTIPLY; + case KEY_PAD_MINUS: + return KI_SUBTRACT; + case KEY_PAD_PLUS: + return KI_ADD; + case KEY_PAD_ENTER: + return KI_NUMPADENTER; + case KEY_PAD_DECIMAL: + return KI_DECIMAL; + case KEY_LBRACKET: + return KI_OEM_4; + case KEY_RBRACKET: + return KI_OEM_6; + case KEY_SEMICOLON: + return KI_OEM_1; + case KEY_APOSTROPHE: + return KI_OEM_7; + case KEY_BACKQUOTE: + return KI_OEM_3; + case KEY_COMMA: + return KI_OEM_COMMA; + case KEY_PERIOD: + return KI_OEM_PERIOD; + case KEY_SLASH: + return KI_OEM_2; + case KEY_BACKSLASH: + return KI_OEM_5; + case KEY_MINUS: + return KI_OEM_MINUS; + case KEY_EQUAL: + return KI_OEM_PLUS; + case KEY_ENTER: + return KI_RETURN; + case KEY_SPACE: + return KI_SPACE; + case KEY_BACKSPACE: + return KI_BACK; + case KEY_TAB: + return KI_TAB; + //case KEY_CAPSLOCK: + // return KI_ + //case KEY_NUMLOCK: + // return KI_ + case KEY_ESCAPE: + return KI_ESCAPE; + //case KEY_SCROLLLOCK: + // return KI_ + case KEY_INSERT: + return KI_INSERT; + case KEY_DELETE: + return KI_DELETE; + case KEY_HOME: + return KI_HOME; + case KEY_END: + return KI_END; + case KEY_PAGEUP: + return KI_PRIOR; + case KEY_PAGEDOWN: + return KI_NEXT; + case KEY_BREAK: + return KI_PAUSE; + //case KEY_LSHIFT: + // return KI + //case KEY_RSHIFT: + // return KI_ + //case KEY_LALT: + // return KI_ + //case KEY_RALT: + // return KI_ + //case KEY_LCONTROL: + // return KI_ + //case KEY_RCONTROL: + // return KI_ + //case KEY_LWIN: + // return KI_ + //case KEY_RWIN: + // return KI_ + //case KEY_APP: + // return KI_ + case KEY_UP: + return KI_UP; + case KEY_LEFT: + return KI_LEFT; + case KEY_DOWN: + return KI_DOWN; + case KEY_RIGHT: + return KI_RIGHT; + case KEY_F1: + return KI_F1; + case KEY_F2: + return KI_F2; + case KEY_F3: + return KI_F3; + case KEY_F4: + return KI_F4; + case KEY_F5: + return KI_F5; + case KEY_F6: + return KI_F6; + case KEY_F7: + return KI_F7; + case KEY_F8: + return KI_F8; + case KEY_F9: + return KI_F9; + case KEY_F10: + return KI_F10; + case KEY_F11: + return KI_F11; + case KEY_F12: + return KI_F12; + //case KEY_CAPSLOCKTOGGLE: + // return KI_ + //case KEY_NUMLOCKTOGGLE: + // return KI_ + //case KEY_SCROLLLOCKTOGGLE: + // return KI_ + + default: + return KI_UNKNOWN; + } + return KI_UNKNOWN; +} + +/** + This map contains 4 different mappings from key identifiers to character codes. Each entry represents a different + combination of shift and capslock state. + */ + +char ascii_map[4][51] = +{ + // shift off and capslock off + { + 0, + ' ', + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + ';', + '=', + ',', + '-', + '.', + '/', + '`', + '[', + '\\', + ']', + '\'', + 0, + 0 + }, + + // shift on and capslock off + { + 0, + ' ', + ')', + '!', + '@', + '#', + '$', + '%', + '^', + '&', + '*', + '(', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + ':', + '+', + '<', + '_', + '>', + '?', + '~', + '{', + '|', + '}', + '"', + 0, + 0 + }, + + // shift on and capslock on + { + 0, + ' ', + ')', + '!', + '@', + '#', + '$', + '%', + '^', + '&', + '*', + '(', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + ':', + '+', + '<', + '_', + '>', + '?', + '~', + '{', + '|', + '}', + '"', + 0, + 0 + }, + + // shift off and capslock on + { + 0, + ' ', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'I', + 'J', + 'K', + 'L', + 'M', + 'N', + 'O', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + ';', + '=', + ',', + '-', + '.', + '/', + '`', + '[', + '\\', + ']', + '\'', + 0, + 0 + } +}; + +char keypad_map[2][18] = +{ + { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '\n', + '*', + '+', + 0, + '-', + '.', + '/', + '=' + }, + + { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + '\n', + '*', + '+', + 0, + '-', + 0, + '/', + '=' + } +}; + +inline Rml::Character GetCharacterCode(Rml::Input::KeyIdentifier key_identifier, int key_modifier_state) +{ + using Rml::Character; + + // Check if we have a keycode capable of generating characters on the main keyboard (ie, not on the numeric + // keypad; that is dealt with below). + if (key_identifier <= Rml::Input::KI_OEM_102) + { + // Get modifier states + bool shift = (key_modifier_state & Rml::Input::KM_SHIFT) > 0; + bool capslock = (key_modifier_state & Rml::Input::KM_CAPSLOCK) > 0; + + // Return character code based on identifier and modifiers + if (shift && !capslock) + return (Character)ascii_map[1][key_identifier]; + + if (shift && capslock) + return (Character)ascii_map[2][key_identifier]; + + if (!shift && capslock) + return (Character)ascii_map[3][key_identifier]; + + return (Character)ascii_map[0][key_identifier]; + } + + // Check if we have a keycode from the numeric keypad. + else if (key_identifier <= Rml::Input::KI_OEM_NEC_EQUAL) + { + if (key_modifier_state & Rml::Input::KM_NUMLOCK) + return (Character)keypad_map[0][key_identifier - Rml::Input::KI_NUMPAD0]; + else + return (Character)keypad_map[1][key_identifier - Rml::Input::KI_NUMPAD0]; + } + + else if (key_identifier == Rml::Input::KI_RETURN) + return (Character)'\n'; + + return Character::Null; +} \ No newline at end of file diff --git a/rocketui/rocketrender.h b/rocketui/rocketrender.h new file mode 100644 index 000000000..19ba07d40 --- /dev/null +++ b/rocketui/rocketrender.h @@ -0,0 +1,59 @@ +#ifndef KISAKSTRIKE_ROCKETRENDER_H +#define KISAKSTRIKE_ROCKETRENDER_H + +#include + +class RocketRender : public Rml::RenderInterface +{ +private: + void *m_glContext; + int m_width; + int m_height; + bool m_transformEnabled; + /** singleton support **/ +public: + static RocketRender m_Instance; +public: + RocketRender(); + + void PrepareGLState(); + + /// Called by RmlUi when it wants to render geometry that it does not wish to optimise. + void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture, const Rml::Vector2f& translation) override; + /// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future. + /// If supported, this should return a handle to an optimised, application-specific version of the data. If + /// not, do not override the function or return zero; the simpler RenderGeometry() will be called instead. + virtual Rml::CompiledGeometryHandle CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture) override; + /// Called by RmlUi when it wants to enable or disable scissoring to clip content. + void EnableScissorRegion(bool enable) override; + /// Called by RmlUi when it wants to change the scissor region. + void SetScissorRegion(int x, int y, int width, int height) override; + /// Called by RmlUi when a texture is required by the library. + bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override; + /// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels. + /// @param[out] texture_handle The handle to write the texture handle for the generated texture to. + /// @param[in] source The raw 8-bit texture data. Each pixel is made up of four 8-bit values, indicating red, green, blue and alpha in that order. + /// @param[in] source_dimensions The dimensions, in pixels, of the source data. + /// @return True if the texture generation succeeded and the handle is valid, false if not. + virtual bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override; + /// Called by RmlUi when a loaded texture is no longer required. + /// @param texture The texture handle to release. + virtual void ReleaseTexture(Rml::TextureHandle texture) override; + /// Called by RmlUi when it wants to set the current transform matrix to a new matrix. + virtual void SetTransform(const Rml::Matrix4f *transform) override; + + /** Local Methods **/ + inline void SetScreenSize( int width, int height ) + { + m_width = width; + m_height = height; + } + inline void SetContext( void *context ) + { + m_glContext = context; + } +}; + + + +#endif //KISAKSTRIKE_ROCKETRENDER_H diff --git a/rocketui/rocketrenderGL.cpp b/rocketui/rocketrenderGL.cpp new file mode 100644 index 000000000..02cf81a0e --- /dev/null +++ b/rocketui/rocketrenderGL.cpp @@ -0,0 +1,333 @@ +#include "rocketrender.h" + +#if defined RMLUI_PLATFORM_WIN32 +#include +#include +#include +#elif defined RMLUI_PLATFORM_MACOSX +#include +#include +#include +#include +#elif defined RMLUI_PLATFORM_UNIX +#include +#include +#include +#include +// The None define from X.h conflicts with RmlUi code base, +// use the constant 0L instead where necessary +#ifdef None +#undef None +#endif +#endif + +#include + +RocketRender RocketRender::m_Instance; + +RocketRender::RocketRender() { } + +void RocketRender::PrepareGLState() +{ + glDisable(GL_CULL_FACE); + + //make sure to set both of these to zero otherwise mesa will segfault even though it only mentions GL_ARRAY_BUFFER in the docs + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + + + //int backup0, backup1, backup2, backup3, backup4, backup5, backup6, backup7, backup8, backup9, backup10, + // backup11, backup12, backup13, backup14, backup15; + //glGetVertexAttribIiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup0 ); + //glGetVertexAttribIiv(1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup1 ); + //glGetVertexAttribIiv(2, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup2 ); + //glGetVertexAttribIiv(3, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup3 ); + //glGetVertexAttribIiv(4, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup4 ); + //glGetVertexAttribIiv(5, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup5 ); + //glGetVertexAttribIiv(6, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup6 ); + //glGetVertexAttribIiv(7, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup7 ); + //glGetVertexAttribIiv(8, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup8 ); + //glGetVertexAttribIiv(9, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup9 ); + //glGetVertexAttribIiv(10, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup10 ); + //glGetVertexAttribIiv(11, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup11 ); + //glGetVertexAttribIiv(12, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup12 ); + //glGetVertexAttribIiv(13, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup13 ); + //glGetVertexAttribIiv(14, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup14 ); + //glGetVertexAttribIiv(15, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &backup15 ); + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + glDisableVertexAttribArray(3); + glDisableVertexAttribArray(4); + glDisableVertexAttribArray(5); + glDisableVertexAttribArray(6); + glDisableVertexAttribArray(7); + glDisableVertexAttribArray(8); + glDisableVertexAttribArray(9); + glDisableVertexAttribArray(10); + glDisableVertexAttribArray(11); + glDisableVertexAttribArray(12); + glDisableVertexAttribArray(13); + glDisableVertexAttribArray(14); + glDisableVertexAttribArray(15); + + glDisable(GL_ALPHA_TEST); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + + glEnable(GL_BLEND); + glBlendColor(1, 1, 1, 1); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + //glStencilFunc( GL_GEQUAL, 253, -1 ); + //glAlphaFunc(GL_GEQUAL, 0); + +} + +void RocketRender::RenderGeometry( Rml::Vertex *vertices, int num_vertices, int *indices, int num_indices, + Rml::TextureHandle texture, const Rml::Vector2f &translation ) +{ + RMLUI_UNUSED(num_vertices); + glPushMatrix(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, m_width, 0, m_height, -10000, 10000); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + glTranslatef(translation.x, translation.y, 0); + + glVertexPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].position); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Rml::Vertex), &vertices[0].colour); + + if (!texture) + { + glDisable(GL_TEXTURE_2D); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + else + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, (GLuint) texture); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(Rml::Vertex), &vertices[0].tex_coord); + } + + glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, indices); + + glPopMatrix(); +} + + +Rml::CompiledGeometryHandle RocketRender::CompileGeometry(Rml::Vertex *vertices, int num_vertices, int *indices, int num_indices, Rml::TextureHandle texture) +{ + return 0; +} + +// Called by RmlUi when it wants to enable or disable scissoring to clip content. +void RocketRender::EnableScissorRegion(bool enable) +{ + if (enable) { + if (!m_transformEnabled) { + glEnable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + glEnable(GL_STENCIL_TEST); + } + } else { + glDisable(GL_SCISSOR_TEST); + glDisable(GL_STENCIL_TEST); + } +} + +// Called by RmlUi when it wants to change the scissor region. +void RocketRender::SetScissorRegion(int x, int y, int width, int height) +{ + if (!m_transformEnabled) { + glScissor(x, y, width, height); + } else { + // clear the stencil buffer + glStencilMask(GLuint(-1)); + glClear(GL_STENCIL_BUFFER_BIT); + + // fill the stencil buffer + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glDepthMask(GL_FALSE); + glStencilFunc(GL_NEVER, 1, GLuint(-1)); + glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); + + float fx = (float)x; + float fy = (float)y; + float fwidth = (float)width; + float fheight = (float)height; + + // draw transformed quad + GLfloat vertices[] = { + fx, fy, 0, + fx, fy + fheight, 0, + fx + fwidth, fy + fheight, 0, + fx + fwidth, fy, 0 + }; + glDisableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, vertices); + GLushort indices[] = { 1, 2, 0, 3 }; + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices); + glEnableClientState(GL_COLOR_ARRAY); + + // prepare for drawing the real thing + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glDepthMask(GL_TRUE); + glStencilMask(0); + glStencilFunc(GL_EQUAL, 1, GLuint(-1)); + } +} + +// Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file +#pragma pack(1) +struct TGAHeader +{ + char idLength; + char colourMapType; + char dataType; + short int colourMapOrigin; + short int colourMapLength; + char colourMapDepth; + short int xOrigin; + short int yOrigin; + short int width; + short int height; + char bitsPerPixel; + char imageDescriptor; +}; +// Restore packing +#pragma pack() + +bool RocketRender::LoadTexture(Rml::TextureHandle &texture_handle, Rml::Vector2i &texture_dimensions, const Rml::String &source) +{ + Rml::FileInterface* file_interface = Rml::GetFileInterface(); + Rml::FileHandle file_handle = file_interface->Open(source); + if (!file_handle) + { + return false; + } + + file_interface->Seek(file_handle, 0, SEEK_END); + size_t buffer_size = file_interface->Tell(file_handle); + file_interface->Seek(file_handle, 0, SEEK_SET); + + RMLUI_ASSERTMSG(buffer_size > sizeof(TGAHeader), "Texture file size is smaller than TGAHeader, file must be corrupt or otherwise invalid"); + if(buffer_size <= sizeof(TGAHeader)) + { + file_interface->Close(file_handle); + return false; + } + + char* buffer = new char[buffer_size]; + file_interface->Read(buffer, buffer_size, file_handle); + file_interface->Close(file_handle); + + TGAHeader header; + memcpy(&header, buffer, sizeof(TGAHeader)); + + int color_mode = header.bitsPerPixel / 8; + int image_size = header.width * header.height * 4; // We always make 32bit textures + + if (header.dataType != 2) + { + Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24/32bit uncompressed TGAs are supported."); + return false; + } + + // Ensure we have at least 3 colors + if (color_mode < 3) + { + Rml::Log::Message(Rml::Log::LT_ERROR, "Only 24 and 32bit textures are supported"); + return false; + } + + const char* image_src = buffer + sizeof(TGAHeader); + unsigned char* image_dest = new unsigned char[image_size]; + + // Targa is BGR, swap to RGB and flip Y axis + for (long y = 0; y < header.height; y++) + { + long read_index = y * header.width * color_mode; + long write_index = ((header.imageDescriptor & 32) != 0) ? read_index : (header.height - y - 1) * header.width * color_mode; + for (long x = 0; x < header.width; x++) + { + image_dest[write_index] = image_src[read_index+2]; + image_dest[write_index+1] = image_src[read_index+1]; + image_dest[write_index+2] = image_src[read_index]; + if (color_mode == 4) + image_dest[write_index+3] = image_src[read_index+3]; + else + image_dest[write_index+3] = 255; + + write_index += 4; + read_index += color_mode; + } + } + + texture_dimensions.x = header.width; + texture_dimensions.y = header.height; + + bool success = GenerateTexture(texture_handle, image_dest, texture_dimensions); + + delete [] image_dest; + delete [] buffer; + + return success; +} + +bool RocketRender::GenerateTexture(Rml::TextureHandle &texture_handle, const Rml::byte *source, const Rml::Vector2i &source_dimensions) +{ + GLuint texture_id = 0; + glGenTextures(1, &texture_id); + if (texture_id == 0) + { + fprintf(stdout,"Failed to generate textures\n"); + return false; + } + + glBindTexture(GL_TEXTURE_2D, texture_id); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, source_dimensions.x, source_dimensions.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, source); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + texture_handle = (Rml::TextureHandle) texture_id; + + return true; +} + +void RocketRender::ReleaseTexture(Rml::TextureHandle texture) +{ + glDeleteTextures(1, (GLuint*) &texture); +} + +void RocketRender::SetTransform(const Rml::Matrix4f *transform) +{ + //TODO: the OpenGL state is not setup right for transforms yet. + m_transformEnabled = (bool)transform; + + if (transform) + { + if (std::is_same::value) + glLoadMatrixf(transform->data()); + else if (std::is_same::value) + glLoadMatrixf(transform->Transpose().data()); + } + else + glLoadIdentity(); +} \ No newline at end of file diff --git a/rocketui/rocketsystem.cpp b/rocketui/rocketsystem.cpp new file mode 100644 index 000000000..ace4204f9 --- /dev/null +++ b/rocketui/rocketsystem.cpp @@ -0,0 +1,36 @@ +#include "rocketsystem.h" + +#include "rocketuiimpl.h" + +#include "vgui/ISystem.h" + +RocketSystem RocketSystem::m_Instance; + +double RocketSystem::GetElapsedTime() +{ + return (double)RocketUIImpl::m_Instance.GetTime(); +} + +bool RocketSystem::LogMessage(Rml::Log::Type type, const Rml::String &message) +{ + bool ret = false; + if( type == Rml::Log::LT_ERROR ) + ret = true; + + //FIXME: an actual logging function that shows up in the terminal. Source engine has like 20+ + fprintf( stderr, "[RocketUI]%s\n", message.c_str() ); + + return ret; +} + +void RocketSystem::SetClipboardText(const Rml::String& text) +{ + g_pVGuiSystem->SetClipboardText( text.c_str(), text.size() ); +} + +void RocketSystem::GetClipboardText(Rml::String& text) +{ + char buffer[1024]; + g_pVGuiSystem->GetClipboardText(0, buffer, sizeof(buffer) ); + text.copy(buffer, sizeof(buffer)); +} \ No newline at end of file diff --git a/rocketui/rocketsystem.h b/rocketui/rocketsystem.h new file mode 100644 index 000000000..61e98c262 --- /dev/null +++ b/rocketui/rocketsystem.h @@ -0,0 +1,36 @@ +#ifndef KISAKSTRIKE_ROCKETSYSTEM_H +#define KISAKSTRIKE_ROCKETSYSTEM_H + +#include + + +class RocketSystem : public Rml::SystemInterface +{ + /** singleton support **/ +public: + static RocketSystem m_Instance; + /// Get the number of seconds elapsed since the start of the application + /// @returns Seconds elapsed + double GetElapsedTime() override; + + /// Log the specified message. + /// @param[in] type Type of log message, ERROR, WARNING, etc. + /// @param[in] message Message to log. + /// @return True to continue execution, false to break into the debugger. + virtual bool LogMessage(Rml::Log::Type type, const Rml::String& message) override; + + /// Set mouse cursor. + /// @param[in] cursor_name Cursor name to activate. + //void SetMouseCursor(const Rml::String& cursor_name) override; + + /// Set clipboard text. + /// @param[in] text Text to apply to clipboard. + void SetClipboardText(const Rml::String& text) override; + + /// Get clipboard text. + /// @param[out] text Retrieved text from clipboard. + void GetClipboardText(Rml::String& text) override; +}; + + +#endif //KISAKSTRIKE_ROCKETSYSTEM_H diff --git a/rocketui/rocketuiimpl.cpp b/rocketui/rocketuiimpl.cpp new file mode 100644 index 000000000..d1b86200d --- /dev/null +++ b/rocketui/rocketuiimpl.cpp @@ -0,0 +1,677 @@ +#include "rocketuiimpl.h" + +#ifdef Debugger +#undef Debugger +#endif + +#include "rocketsystem.h" +#include "rocketrender.h" +#include "rocketfilesystem.h" + +#include +#include + +#include "rocketkeys.h" + +RocketUIImpl RocketUIImpl::m_Instance; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( RocketUIImpl, IRocketUI, ROCKETUI_INTERFACE_VERSION, RocketUIImpl::m_Instance ) + +ConVar rocket_enable( "rocket_enable", "1", 0, "Enables RocketUI" ); + +CON_COMMAND_F( rocket_reload, "Reloads all RocketUI Documents", FCVAR_NONE ) +{ + if( RocketUIImpl::m_Instance.ReloadDocuments() ) + { + ConMsg("[RocketUI]Documents Reloaded.\n"); + } + else + { + ConMsg("[RocketUI]Error reloading Documents!\n"); + } +} + +CON_COMMAND_F( rocket_debug, "Open/Close the RocketUI Debugger", FCVAR_NONE ) +{ + RocketUIImpl::m_Instance.ToggleDebugger(); +} + + + +RocketUIImpl::RocketUIImpl() { } + +bool RocketUIImpl::Connect(CreateInterfaceFn factory) +{ + if ( !factory ) + { + return false; + } + + if ( !BaseClass::Connect( factory ) ) + { + return false; + } + +#if defined( USE_SDL ) + m_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL); +#elif defined( OSX ) + m_pLauncherMgr = (ILauncherMgr *)factory( COCOAMGR_INTERFACE_VERSION, NULL); +#else + #error fixme +#endif + + m_pShaderDeviceMgr = ( IShaderDeviceMgr* ) factory( SHADER_DEVICE_MGR_INTERFACE_VERSION, NULL ); + m_pGameUIFuncs = ( IGameUIFuncs* ) factory( VENGINE_GAMEUIFUNCS_VERSION, NULL ); + m_pEngine = ( IVEngineClient* )factory( VENGINE_CLIENT_INTERFACE_VERSION, NULL ); + m_pGameEventManager = ( IGameEventManager2* )factory ( INTERFACEVERSION_GAMEEVENTSMANAGER2, NULL ); + m_pShaderAPI = ( IShaderAPI * )factory( SHADERAPI_INTERFACE_VERSION, NULL ); + + if ( !m_pShaderDeviceMgr || !m_pGameUIFuncs || !m_pEngine || !m_pGameEventManager || !m_pShaderAPI ) + { + Warning( "RocketUI: missing expected interface\n" ); + return false; + } + + return true; +} + +void RocketUIImpl::Disconnect() +{ + if ( m_pShaderDeviceMgr ) + { + if ( m_pDeviceCallbacks ) + { + m_pShaderDeviceMgr->RemoveDeviceDependentObject( m_pDeviceCallbacks ); + delete m_pDeviceCallbacks; + m_pDeviceCallbacks = NULL; + } + } +#if defined( USE_SDL ) + m_pLauncherMgr = NULL; +#elif defined( OSX ) + m_pLauncherMgr = NULL; +#else + #error fixme +#endif + m_pShaderDeviceMgr = NULL; + m_pGameUIFuncs = NULL; + m_pEngine = NULL; + m_pGameEventManager = NULL; + m_pShaderAPI = NULL; + + BaseClass::Disconnect(); +} + +void* RocketUIImpl::QueryInterface( const char *pInterfaceName ) +{ + if ( !Q_strncmp( pInterfaceName, ROCKETUI_INTERFACE_VERSION, Q_strlen( ROCKETUI_INTERFACE_VERSION ) + 1 ) ) + { + return ( IRocketUI* ) &RocketUIImpl::m_Instance; + } + + return BaseClass::QueryInterface( pInterfaceName ); +} + +const AppSystemInfo_t* RocketUIImpl::GetDependencies( void ) +{ + return BaseClass::GetDependencies(); +} + +Rml::Context* RocketUIImpl::AccessHudContext() +{ + return m_ctxHud; +} + +Rml::Context* RocketUIImpl::AccessMenuContext() +{ + return m_ctxMenu; +} +bool RocketUIImpl::LoadFont( const char *filepath, const char *path ) +{ + unsigned char *fontBuffer = NULL; + CUtlBuffer font; + unsigned int fontLen; + + if( !g_pFullFileSystem->ReadFile( filepath, path, font ) ) + { + fprintf(stderr, "[RocketUI]Failed to read %s font.", filepath ); + return false; + } + + fontLen = font.Size() - 1; + + if( fontLen >= ( 8 * 1024 * 1024 ) ) + { + fprintf(stderr, "[RocketUI]Font (%s) is over 8MB!(%d). Not Loading.\n", filepath, fontLen ); + return false; + } + + fprintf(stderr, "[RocketUI]Font size (%d)\n", fontLen ); + + fontBuffer = new unsigned char[ fontLen + 1 ]; + // Add to list of alloc'd fonts. Freetype will use this memory until we Shutdown. + m_fontAllocs.AddToTail( fontBuffer ); + + font.Get( fontBuffer, fontLen ); + + if( !Rml::LoadFontFace( fontBuffer, fontLen, "Lato", Rml::Style::FontStyle::Normal, Rml::Style::FontWeight::Normal, false ) ) + { + fprintf(stderr, "[RocketUI]Failed to Initialize Lato font\n" ); + return false; + } + + return true; +} + +bool RocketUIImpl::LoadFonts() +{ + bool fontsOK = true; + fontsOK &= LoadFont( "rocketui/fonts/Lato-Black.ttf", "GAME" ); + + return fontsOK; +} + +static Rml::ElementDocument *LoadDocumentFile( Rml::Context *ctx, const char *tag, const char *pPath, const char *filepath ) +{ + static char documentBuffer[ 4 * 1024 * 1024 ]; //4mb + std::string documentStr; + CUtlBuffer buffer; + Rml::ElementDocument *document; + + if( !g_pFullFileSystem->ReadFile( filepath, pPath, buffer ) ) + { + fprintf(stderr, "[RocketUI]Failed to read file (%s)\n", filepath ); + return NULL; + } + buffer.GetString( documentBuffer, sizeof( documentBuffer ) ); + documentStr = documentBuffer; + document = ctx->LoadDocumentFromMemory( documentStr ); + if( !document ) + { + fprintf(stderr, "[RocketUI]Failed to load document from memory (%s)\n", filepath); + return NULL; + } + + return document; +} + +Rml::ElementDocument *RocketUIImpl::LoadDocumentFileIntoHud( const char *tag, const char *pPath, const char *filepath, LoadDocumentFn loadDocumentFunc, UnloadDocumentFn unloadDocumentFunc ) +{ + Rml::ElementDocument *document = LoadDocumentFile( m_ctxHud, tag, pPath, filepath ); + + if( !document ) + return nullptr; + + // Need both + if( loadDocumentFunc && unloadDocumentFunc ) + { + CUtlPair documentFuncPair( loadDocumentFunc, unloadDocumentFunc ); + m_documentReloadFuncs.AddToTail( documentFuncPair ); + } + + return document; +} + +Rml::ElementDocument *RocketUIImpl::LoadDocumentFileIntoMenu( const char *tag, const char *pPath, const char *filepath, LoadDocumentFn loadDocumentFunc, UnloadDocumentFn unloadDocumentFunc ) +{ + Rml::ElementDocument *document = LoadDocumentFile( m_ctxMenu, tag, pPath, filepath ); + + if( !document ) + return nullptr; + + // Need both + if( loadDocumentFunc && unloadDocumentFunc ) + { + CUtlPair documentFuncPair( loadDocumentFunc, unloadDocumentFunc ); + m_documentReloadFuncs.AddToTail( documentFuncPair ); + } + + return document; +} + +InitReturnVal_t RocketUIImpl::Init( void ) +{ + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + { + return nRetVal; + } + + // Register a callback with the ShaderDeviceMgr + m_pDeviceCallbacks = new DeviceCallbacks(); + m_pDeviceCallbacks->m_pRocketUI = this; + m_pShaderDeviceMgr->AddDeviceDependentObject( m_pDeviceCallbacks ); + + // Create/Init the Rocket UI Library + // Default width/height, these get updated in the DeviceCallbacks + int width = 1920; + int height = 1080; + RocketRender::m_Instance.SetScreenSize( width, height ); + RocketRender::m_Instance.SetContext( m_pLauncherMgr->GetMainContext() ); + + Rml::SetFileInterface( &RocketFileSystem::m_Instance ); + Rml::SetRenderInterface( &RocketRender::m_Instance ); + Rml::SetSystemInterface( &RocketSystem::m_Instance ); + + if ( !Rml::Initialise() ) + { + Warning( "RocketUI: Initialise() failed!\n"); + return INIT_FAILED; + } + + if( !LoadFonts() ) + { + Warning( "RocketUI: Failed to load fonts.\n" ); + return INIT_FAILED; + } + + m_ctxMenu = Rml::CreateContext("menu", Rml::Vector2i(width, height)); + m_ctxHud = Rml::CreateContext("hud", Rml::Vector2i(width, height)); + + if ( !m_ctxMenu || !m_ctxHud ) + { + Warning( "RocketUI: Failed to create Hud/Menu context\n" ); + Rml::Shutdown(); + return INIT_FAILED; + } + + m_ctxMenu->SetDensityIndependentPixelRatio(1.0f ); + m_ctxHud->SetDensityIndependentPixelRatio(1.0f ); + + return INIT_OK; +} + +void RocketUIImpl::Shutdown() +{ + // Shutdown RocketUI. All contexts are destroyed on shutdown. + Rml::Shutdown(); + + // freetype FT_Done_Face has been called. Time to free fonts. + for( int i = 0; i < m_fontAllocs.Count(); i++ ) + { + unsigned char *fontAlloc = m_fontAllocs[i]; + delete[] fontAlloc; + } + + if ( m_pShaderDeviceMgr ) + { + if ( m_pDeviceCallbacks ) + { + m_pShaderDeviceMgr->RemoveDeviceDependentObject( m_pDeviceCallbacks ); + delete m_pDeviceCallbacks; + m_pDeviceCallbacks = NULL; + } + } + + m_ctxCurrent = NULL; + + BaseClass::Shutdown(); +} + +void RocketUIImpl::RunFrame(float time) +{ + // We dont have the device yet.. + if( !m_pDevice ) + return; + + m_fTime = time; + + // This is important. Update the current context 1x per frame. + // This basically needs to be called whenever elements are added/changed/removed + // I am calling it 1x per frame here instead of all over the place for simplicity and no overlap. + if( m_ctxCurrent ) + m_ctxCurrent->Update(); +} + +void RocketUIImpl::DenyInputToGame( bool value, const char *why ) +{ + if( value ) + { + m_numInputConsumers++; + m_inputConsumers.AddToTail( CUtlString( why ) ); + } + else + { + m_numInputConsumers--; + m_inputConsumers.FindAndRemove( CUtlString( why ) ); + } + + EnableCursor( (m_numInputConsumers > 0) ); + + ConMsg("input Consumers[%d]: ", m_numInputConsumers); + for( int i = 0; i < m_inputConsumers.Count(); i++ ) + { + ConMsg("(%s) ", m_inputConsumers[i].Get() ); + } + ConMsg("\n"); +} + +bool RocketUIImpl::IsConsumingInput() +{ + return ( m_numInputConsumers > 0 ); +} + +void RocketUIImpl::EnableCursor(bool state) +{ + ConVarRef cl_mouseenable( "cl_mouseenable" ); + + ConMsg("Turnin %s the mouse\n", state ? "on" : "off" ); + + cl_mouseenable.SetValue( !state ); + + if( state ) + m_pLauncherMgr->ForceSystemCursorVisible(); + else + m_pLauncherMgr->UnforceSystemCursorVisible(); + + m_bCursorVisible = state; +} + +// This function is an input hook. +// return true if we want to deny the game the input. +bool RocketUIImpl::HandleInputEvent(const InputEvent_t &event) +{ + // Haven't rendered our very first frame ever yet. + if( !m_ctxCurrent ) + return false; + + // Always get the mouse location. + if( event.m_nType == IE_AnalogValueChanged && event.m_nData == MOUSE_XY ) + { + // TODO update this with keymodifiers + m_ctxCurrent->ProcessMouseMove( event.m_nData2, event.m_nData3, 0 ); + } + + // Some edge cases + if( event.m_nType == IE_ButtonPressed ) + { + // Check for debugger. Toggle on F8. + if( event.m_nData == KEY_F8 ) + { + ToggleDebugger(); + return true; + } + // The magical ESC key for the pause menu. The game handles this in an awful way + // CSGO will open the pause menu for us the 1st time, but after that it fubars + // In order to minimize this component from reaching into the gamecode, + // The pause menu will register itself via RegisterPauseMenu while loading. + // Kinda Hacky, but it is direct from keys.cpp and prevents the VGUI code from messing with it too much. + if( event.m_nData == KEY_ESCAPE ) + { + if( m_togglePauseMenuFunc && m_pEngine->IsInGame() ) + { + m_togglePauseMenuFunc(); + } + } + } + + // Nothing wants input, skip. + if( !IsConsumingInput() ) + return false; + + // The console is open, skip + if( m_pEngine->Con_IsVisible() ) + return false; + + Rml::Input::KeyIdentifier key; + char ascii; + + switch( event.m_nType ) + { + case IE_ButtonDoubleClicked: + case IE_ButtonPressed: + //TODO add key modifiers + if( IsMouseCode( (ButtonCode_t)event.m_nData ) ) + { + switch( (ButtonCode_t)event.m_nData ) + { + case MOUSE_LEFT: + m_ctxCurrent->ProcessMouseButtonDown( 0, 0 ); + break; + case MOUSE_RIGHT: + m_ctxCurrent->ProcessMouseButtonDown( 1, 0 ); + break; + case MOUSE_MIDDLE: + m_ctxCurrent->ProcessMouseButtonDown( 2, 0 ); + break; + case MOUSE_4: + m_ctxCurrent->ProcessMouseButtonDown( 3, 0 ); + break; + case MOUSE_5: + m_ctxCurrent->ProcessMouseButtonDown( 4, 0 ); + break; + case MOUSE_WHEEL_UP: + m_ctxCurrent->ProcessMouseWheel( -1, 0 ); + break; + case MOUSE_WHEEL_DOWN: + m_ctxCurrent->ProcessMouseWheel( 1, 0 ); + break; + } + } + else + { + m_ctxCurrent->ProcessKeyDown( ButtonToRocketKey( (ButtonCode_t)event.m_nData ), 0 ); + } + break; + case IE_ButtonReleased: + //TODO add key modifiers + if( IsMouseCode( (ButtonCode_t)event.m_nData ) ) + { + switch( (ButtonCode_t)event.m_nData ) + { + case MOUSE_LEFT: + m_ctxCurrent->ProcessMouseButtonUp( 0, 0 ); + break; + case MOUSE_RIGHT: + m_ctxCurrent->ProcessMouseButtonUp( 1, 0 ); + break; + case MOUSE_MIDDLE: + m_ctxCurrent->ProcessMouseButtonUp( 2, 0 ); + break; + case MOUSE_4: + m_ctxCurrent->ProcessMouseButtonUp( 3, 0 ); + break; + case MOUSE_5: + m_ctxCurrent->ProcessMouseButtonUp( 4, 0 ); + break; + } + } + else + { + m_ctxCurrent->ProcessKeyUp( ButtonToRocketKey( (ButtonCode_t)event.m_nData ), 0 ); + } + break; + case IE_KeyTyped: + ascii = (char)((wchar_t)event.m_nData); + if( ascii != 8 ){ // Rocketui doesn't like the backspace for some reason. + m_ctxCurrent->ProcessTextInput( ascii ); + } + break; + case IE_AnalogValueChanged: + // Mouse/Joystick changes. Mouse changes are recorded above + break; + + default: + return false; + } + + return IsConsumingInput(); +} + +void RocketUIImpl::RenderHUDFrame() +{ + if( !rocket_enable.GetBool() ) + return; + + m_ctxCurrent = m_ctxHud; + +#if defined ( DX_TO_GL_ABSTRACTION ) + m_pDevice->SaveGLState(); + RocketRender::m_Instance.PrepareGLState(); +#endif + + //CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + //ShaderStencilState_t state; + + //// Setup the Matrix/Ortho + //StartDrawing(); +// + //// Clear z + stencil buffer + //pRenderContext->ClearBuffers( false, true, true ); +// + //state.m_bEnable = true; + //state.m_FailOp = SHADER_STENCILOP_KEEP; + //state.m_ZFailOp = SHADER_STENCILOP_KEEP; + //state.m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE; + //state.m_CompareFunc = SHADER_STENCILFUNC_GEQUAL; + //state.m_nReferenceValue = 0; + //state.m_nTestMask = 0xFFFFFFFF; + //state.m_nWriteMask = 0xFFFFFFFF; + //pRenderContext->SetStencilState( state ); + + //TODO: don't update here. update only after input or new elements + //m_ctxHud->Update(); + //m_ctxMenu->Update(); + + m_ctxHud->Render(); + //m_ctxMenu->Render(); + + // Reset stencil to normal + //state.m_bEnable = false; + //pRenderContext->SetStencilState( state ); +// + //FinishDrawing(); + +#if defined ( DX_TO_GL_ABSTRACTION ) + m_pDevice->RestoreGLState(); +#endif +} + +void RocketUIImpl::RenderMenuFrame() +{ + if( !rocket_enable.GetBool() ) + return; + + m_ctxCurrent = m_ctxMenu; + +#if defined ( DX_TO_GL_ABSTRACTION ) + m_pDevice->SaveGLState(); + RocketRender::m_Instance.PrepareGLState(); + glActiveTexture(GL_TEXTURE0); +#endif + + //TODO: don't update here. update only after input or new elements + //m_ctxMenu->Update(); + + m_ctxMenu->Render(); + +#if defined ( DX_TO_GL_ABSTRACTION ) + m_pDevice->RestoreGLState(); +#endif +} + +bool RocketUIImpl::ReloadDocuments() +{ + rocket_enable.SetValue( false ); + // Hacky, sleep for 100ms after disabling UI. + // I dont feel like adding a mutex check every frame for something rarely used by devs + ThreadSleep( 100 ); + + CUtlVector> copyOfPairs; + + // Copy the pairs into a local Vector( grug, copy constructor no work ) + // We want a copy because the loading functions will mess with our Vector when we call them. + for( int i = 0; i < m_documentReloadFuncs.Count(); i++ ) + { + copyOfPairs.AddToTail( m_documentReloadFuncs[i] ); + } + + // We can now empty the Main Vector since we are about to reload. + m_documentReloadFuncs.Purge(); + + // Go through the copy and reload + for( int i = 0; i < copyOfPairs.Count(); i++ ) + { + CUtlPair documentPair( copyOfPairs[i] ); + // Unload... + documentPair.second(); + // Load... + documentPair.first(); + } + + rocket_enable.SetValue( true ); + return true; +} + +void RocketUIImpl::AddDeviceDependentObject(IShaderDeviceDependentObject *pObject) +{ + if( m_pShaderDeviceMgr ) + { + m_pShaderDeviceMgr->AddDeviceDependentObject( pObject ); + } +} + +void RocketUIImpl::RemoveDeviceDependentObject(IShaderDeviceDependentObject *pObject) +{ + if( m_pShaderDeviceMgr ) + { + m_pShaderDeviceMgr->RemoveDeviceDependentObject( pObject ); + } +} + +void RocketUIImpl::SetRenderingDevice(IDirect3DDevice9 *pDevice, D3DPRESENT_PARAMETERS *pPresentParameters, HWND hWnd) +{ + // This is how pDevice gets initialized :) + if( !pDevice || m_pDevice != pDevice ) + { + m_pDevice = pDevice; + } + + //TODO: Do we need to reset rocketui here? + + D3DVIEWPORT9 viewport; + pDevice->GetViewport( &viewport ); + SetScreenSize( viewport.Width, viewport.Height ); +} + +void RocketUIImpl::ToggleDebugger() +{ + static bool open = false; + static bool firstTime = true; + + open = !open; + + if( !m_ctxCurrent ) + return; + + if( open ) + { + if( firstTime ) + { + if( Rml::Debugger::Initialise( m_ctxCurrent ) ) + { + firstTime = false; + } + else + { + ConMsg("[RocketUI]Error Initializing Debugger\n"); + return; + } + } + ConMsg("[RocketUI]Opening Debugger\n"); + if( !Rml::Debugger::SetContext( m_ctxCurrent ) ) + { + ConMsg("[RocketUI]Error setting context!\n"); + return; + } + m_isDebuggerOpen = true; + Rml::Debugger::SetVisible( true ); + DenyInputToGame( true, "RocketUI Debugger" ); + } + else + { + ConMsg("[RocketUI]Closing Debugger\n"); + Rml::Debugger::SetVisible( false ); + m_isDebuggerOpen = false; + DenyInputToGame( false, "RocketUI Debugger" ); + } +} \ No newline at end of file diff --git a/rocketui/rocketuiimpl.h b/rocketui/rocketuiimpl.h new file mode 100644 index 000000000..258b6ea47 --- /dev/null +++ b/rocketui/rocketuiimpl.h @@ -0,0 +1,188 @@ +#ifndef KISAKSTRIKE_ROCKETUI_H +#define KISAKSTRIKE_ROCKETUI_H + +#if defined( USE_SDL ) || defined( OSX ) +#include "appframework/ilaunchermgr.h" +#endif + +#if defined ( DX_TO_GL_ABSTRACTION ) +#include "togl/rendermechanism.h" +#endif + +#include "rocketui/rocketui.h" +#include "tier3/tier3.h" +#include "shaderapi/IShaderDevice.h" +#include "shaderapi/ishaderapi.h" +#include "IGameUIFuncs.h" +#include "cdll_int.h" +#include "igameevents.h" +#include "tier1/utlpair.h" + +#include "rocketrender.h" + +#include "RmlUi/Core/ElementDocument.h" + +class DeviceCallbacks; +class RocketUIImpl : public CTier3AppSystem +{ + typedef CTier3AppSystem BaseClass; + + /** singleton support **/ +public: + static RocketUIImpl m_Instance; + +protected: + IDirect3DDevice9 *m_pDevice; + DeviceCallbacks *m_pDeviceCallbacks; + +#if defined( USE_SDL ) || defined( OSX ) + ILauncherMgr *m_pLauncherMgr; +#endif + IShaderDeviceMgr *m_pShaderDeviceMgr; + IShaderAPI *m_pShaderAPI; + IGameUIFuncs *m_pGameUIFuncs; + IVEngineClient *m_pEngine; + IGameEventManager2 *m_pGameEventManager; + + // Fonts need to stay for the lifetime of the program. Used directly by freetype. Freed on shutdown. + CUtlVector m_fontAllocs; + CUtlVector m_inputConsumers; + float m_fTime; + bool m_bCursorVisible; + + // Contexts + Rml::Context *m_ctxMenu; + Rml::Context *m_ctxHud; + Rml::Context *m_ctxCurrent; //Pointer to Hud or Menu + + bool m_isDebuggerOpen; + + TogglePauseMenuFn m_togglePauseMenuFunc; + + // List of Document Reload functions for hot-reloading. + CUtlVector< CUtlPair > m_documentReloadFuncs; + + // if > 0, we are stealing input from the game. + int m_numInputConsumers; + /** IAppSystem **/ +public: + virtual bool Connect( CreateInterfaceFn factory ); + virtual void Disconnect( void ); + + // Here's where systems can access other interfaces implemented by this m_pObject + // Returns NULL if it doesn't implement the requested interface + virtual void *QueryInterface( const char *pInterfaceName ); + + // Init, shutdown + virtual InitReturnVal_t Init( void ); + virtual void Shutdown( void ); + + // Returns all dependent libraries + virtual const AppSystemInfo_t* GetDependencies( void ); + + // Returns the tier + virtual AppSystemTier_t GetTier( void ) + { + return APP_SYSTEM_TIER3; + } + + // Reconnect to a particular interface + virtual void Reconnect( CreateInterfaceFn factory, const char *pInterfaceName ) + { + BaseClass::Reconnect( factory, pInterfaceName ); + } + + /** IRocketUI Interface Methods **/ +public: + // Updates time mostly + virtual void RunFrame( float time ); + + // Reload from Disk + virtual bool ReloadDocuments(); + + // Feed input into UI + virtual bool HandleInputEvent( const InputEvent_t &event ); + // Start consuming inputs + virtual void DenyInputToGame( bool value, const char *why ); + virtual bool IsConsumingInput( void ); + + virtual void EnableCursor( bool state ); + + // Document manipulation. + virtual Rml::ElementDocument *LoadDocumentFileIntoHud( const char *tag, const char *pPath, const char *filepath, + LoadDocumentFn loadDocumentFunc = nullptr, UnloadDocumentFn unloadDocumentFunc = nullptr); + virtual Rml::ElementDocument *LoadDocumentFileIntoMenu( const char *tag, const char *pPath, const char *filepath, + LoadDocumentFn loadDocumentFunc = nullptr, UnloadDocumentFn unloadDocumentFunc = nullptr); + + // Rendering + virtual void RenderHUDFrame(); + virtual void RenderMenuFrame(); + + // Access to the actual contexts. + virtual Rml::Context* AccessHudContext(); + virtual Rml::Context* AccessMenuContext(); + + virtual void RegisterPauseMenu( TogglePauseMenuFn showPauseMenuFunc ) + { + m_togglePauseMenuFunc = showPauseMenuFunc; + } + + void AddDeviceDependentObject( IShaderDeviceDependentObject * pObject ); + void RemoveDeviceDependentObject( IShaderDeviceDependentObject * pObject ); + + /** Local Class Methods **/ + RocketUIImpl( void ); + void SetRenderingDevice( IDirect3DDevice9 *pDevice, D3DPRESENT_PARAMETERS *pPresentParameters, HWND hWnd ); + void ToggleDebugger( void ); + Rml::Context *GetCurrentContext() + { + return m_ctxCurrent; + } +private: + bool LoadFont( const char *filepath, const char *path ); + bool LoadFonts(); + +public: + inline const float GetTime() + { + return m_fTime; + } + inline void SetScreenSize( int width, int height ) + { + RocketRender::m_Instance.SetScreenSize( width, height ); + } + +}; + +class DeviceCallbacks: public IShaderDeviceDependentObject +{ +public: + int m_iRefCount; + RocketUIImpl* m_pRocketUI; + + DeviceCallbacks( void ) : + m_iRefCount( 1 ), m_pRocketUI( NULL ) + { + } + + virtual void DeviceLost( void ) + { + //TODO: Windows version wants this + //m_pScaleform->NotifyRenderingDeviceLost(); + } + + virtual void DeviceReset( void *pDevice, void *pPresentParameters, void *pHWnd ) + { + m_pRocketUI->SetRenderingDevice( ( IDirect3DDevice9* )pDevice, ( D3DPRESENT_PARAMETERS* )pPresentParameters, ( HWND )pHWnd ); + } + + virtual void ScreenSizeChanged( int width, int height ) + { + m_pRocketUI->SetScreenSize( width, height ); + } +}; + + + + +#endif //KISAKSTRIKE_ROCKETUI_H \ No newline at end of file diff --git a/scaleformui/scaleformuiimpl/scaleformuiimpl.h b/scaleformui/scaleformuiimpl/scaleformuiimpl.h index 59ee58b7e..56631121e 100644 --- a/scaleformui/scaleformuiimpl/scaleformuiimpl.h +++ b/scaleformui/scaleformuiimpl/scaleformuiimpl.h @@ -17,6 +17,7 @@ #include "tier1/utlmap.h" #include "igameevents.h" #include "cdll_int.h" +#include "shaderapi/IShaderDevice.h" #if defined( USE_SDL ) || defined( OSX ) #include "appframework/ilaunchermgr.h" diff --git a/scaleformui/scaleformuiimpl/scaleformuiinitimpl.cpp b/scaleformui/scaleformuiimpl/scaleformuiinitimpl.cpp index 8c9987719..d091f3f4d 100644 --- a/scaleformui/scaleformuiimpl/scaleformuiinitimpl.cpp +++ b/scaleformui/scaleformuiimpl/scaleformuiinitimpl.cpp @@ -5,7 +5,9 @@ // $NoKeywords: $ //=============================================================================// +#include #include "stdafx.h" +#include "scaleformuiimpl.h" #include "scaleformuiintegration.h" #include "tier1/keyvalues.h" #include "vgui/ILocalize.h" diff --git a/thirdparty/RmlUi/.appveyor.yml b/thirdparty/RmlUi/.appveyor.yml new file mode 100644 index 000000000..62a11ee06 --- /dev/null +++ b/thirdparty/RmlUi/.appveyor.yml @@ -0,0 +1,128 @@ +version: build.{build} +image: Visual Studio 2017 +matrix: + fast_finish: true +environment: + FREETYPE_VER: 2.10.1 + VS_CXXFLAGS: /DWIN32 /D_WINDOWS /W4 /GR /EHsc /permissive- /w44062 + RUN_MINGW: false + matrix: + - RUN_MINGW: true + - VS_GENERATOR: Visual Studio 15 2017 Win64 + PLATFORM_NAME: win64 + - VS_GENERATOR: Visual Studio 15 2017 + PLATFORM_NAME: win32 +install: +- cmd: |- + cd Dependencies + + appveyor DownloadFile https://github.com/ubawurinna/freetype-windows-binaries/releases/download/v%FREETYPE_VER%/freetype.zip + unzip -o freetype.zip -d freetype_tmp + mv freetype_tmp/include include + mv freetype_tmp/%PLATFORM_NAME% lib + + cd .. + mkdir Build-Dynamic, Build-Static + + cd Build-Dynamic + cmake -G "%VS_GENERATOR%" -DBUILD_SHARED_LIBS=ON -DBUILD_SAMPLES=ON -DCMAKE_CXX_FLAGS="%VS_CXXFLAGS%" .. + + cd ../Build-Static + cmake -G "%VS_GENERATOR%" -DBUILD_SHARED_LIBS=OFF -DBUILD_SAMPLES=OFF .. + + cd .. + +build_script: +- cmd: |- + msbuild Build-Dynamic/RmlUi.sln /p:configuration=debug /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + + msbuild Build-Dynamic/RmlUi.sln /p:configuration=release /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + + msbuild Build-Static/RmlUi.sln /p:configuration=debug /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + + msbuild Build-Static/RmlUi.sln /p:configuration=release /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" + +after_build: +- cmd: |- + mkdir Bin + cd Bin + mkdir Dynamic-Debug, Dynamic-Release, Static-Debug, Static-Release + cp ../Build-Dynamic/Debug/Rml*.{lib,dll,pdb} Dynamic-Debug + cp ../Build-Dynamic/Release/Rml*.{lib,dll} Dynamic-Release + cp ../Build-Static/Debug/Rml*.{lib,pdb} Static-Debug + cp ../Build-Static/Release/Rml*.lib Static-Release + cd .. + + cp Build-Dynamic/Release/*.exe Samples + cp Bin/Dynamic-Release/*.dll Samples + cp Dependencies/lib/*.dll Samples + + mv Dependencies/lib/ Dependencies/freetype-%FREETYPE_VER% + cp Dependencies/freetype_tmp/*.TXT Dependencies/freetype-%FREETYPE_VER% + + IF NOT "%APPVEYOR_REPO_TAG_NAME%"=="" SET RMLUI_VERSION= %APPVEYOR_REPO_TAG_NAME% + + echo RmlUi%RMLUI_VERSION% library and sample binaries for %PLATFORM_NAME%.> Readme.txt& echo.>>Readme.txt + echo https://github.com/mikke89/RmlUi>> Readme.txt& echo.>>Readme.txt + echo Built using %VS_GENERATOR% on %APPVEYOR_REPO_COMMIT_TIMESTAMP:~0,10% (build %APPVEYOR_BUILD_NUMBER%).>> Readme.txt + echo Commit id: %APPVEYOR_REPO_COMMIT%.>> Readme.txt + + 7z a RmlUi-%PLATFORM_NAME%.zip Bin/ Include/ Readme.txt changelog.md LICENSE Dependencies/freetype-%FREETYPE_VER%/ Samples/ + + mkdir Samples\Dependencies\freetype-%FREETYPE_VER% + cp Dependencies/freetype-%FREETYPE_VER%/*.TXT Samples/Dependencies/freetype-%FREETYPE_VER% + IF "%PLATFORM_NAME%"=="win64" 7z a RmlUi-%PLATFORM_NAME%-samples-only.zip LICENSE .\Samples\* -r -xr!src\ -x!shell\ -x!luainvaders\ + +for: +- + matrix: + only: + - RUN_MINGW: true + install: + - cmd: |- + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-gcc" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-make" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-freetype" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-sfml" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-lua" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-SDL2" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-SDL2_image" + C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-glew" + + mkdir Build + cd Build + + set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + set PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH% + set GLEW_INCLUDE_DIR=C:/msys64/mingw64/include/GL + set GLEW_LIBRARIES=C:/msys64/mingw64/lib/libglew32.dll.a + + cmake -G "MinGW Makefiles" -DBUILD_SHARED_LIBS=ON -DENABLE_PRECOMPILED_HEADERS=OFF -DBUILD_SAMPLES=ON -DBUILD_LUA_BINDINGS=ON -DCMAKE_C_COMPILER=gcc.exe -DCMAKE_CXX_COMPILER=g++.exe -DCMAKE_MAKE_PROGRAM=mingw32-make.exe -DGLEW_INCLUDE_DIR=%GLEW_INCLUDE_DIR% -DGLEW_LIBRARIES=%GLEW_LIBRARIES% .. + + set CHERE_INVOKING=yes + set MSYSTEM=MINGW64 + + build_script: + - cmd: |- + C:\msys64\usr\bin\bash -lc "mingw32-make.exe -j4" + + after_build: + - cmd: |- + ls {*.exe,*.dll} -s -h -X + +artifacts: +- path: RmlUi-win64.zip +- path: RmlUi-win64-samples-only.zip +- path: RmlUi-win32.zip +deploy: + release: RmlUi $(APPVEYOR_REPO_TAG_NAME) + description: 'Release description' + provider: GitHub + auth_token: + secure: g/WlXrOszpqKYC++IvUvNOPhuEeHbMm+2/TWzcgQko+nIGKmjvfAWUxouNhgsUy9 + artifact: /.*\.zip/ + draft: true + prerelease: false + on: + APPVEYOR_REPO_TAG: true + RUN_MINGW: false diff --git a/thirdparty/RmlUi/.travis.valgrind.supp b/thirdparty/RmlUi/.travis.valgrind.supp new file mode 100644 index 000000000..92ffa8927 --- /dev/null +++ b/thirdparty/RmlUi/.travis.valgrind.supp @@ -0,0 +1,15 @@ +{ + Driver_leaks_1 + Memcheck:Leak + obj:/usr/lib/x86_64-linux-gnu/dri/swrast_dri.so +} +{ + Driver_cond_1 + Memcheck:Cond + obj:/usr/lib/x86_64-linux-gnu/dri/swrast_dri.so +} +{ + Driver_leaks_2 + Memcheck:Leak + obj:/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so +} \ No newline at end of file diff --git a/thirdparty/RmlUi/.travis.yml b/thirdparty/RmlUi/.travis.yml new file mode 100644 index 000000000..fe7e3be7f --- /dev/null +++ b/thirdparty/RmlUi/.travis.yml @@ -0,0 +1,118 @@ +sudo: false +dist: bionic +language: c++ +env: + global: + - CXXFLAGS="-pedantic -Wall -Wextra" + +cache: + apt: true + directories: + - $HOME/.deps + +matrix: + include: + - os: osx + osx_image: xcode10.3 + compiler: clang + - os: linux + compiler: clang + addons: + apt: + packages: + - cmake + - ninja-build + - libsdl2-dev + - libsdl2-image-dev + - libfreetype6-dev + - libglew-dev + - liblua5.2-dev + - libsfml-dev + - os: linux + compiler: clang + env: NO_FONT_INTERFACE_DEFAULT="ON" + addons: + apt: + packages: + - cmake + - ninja-build + - libsdl2-dev + - libsdl2-image-dev + - libfreetype6-dev + - libglew-dev + - liblua5.2-dev + - libsfml-dev + - os: linux + compiler: gcc + env: DISABLE_RTTI_AND_EXCEPTIONS="ON" NO_THIRDPARTY_CONTAINERS="ON" + addons: + apt: + packages: + - cmake + - ninja-build + - libsdl2-dev + - libsdl2-image-dev + - libfreetype6-dev + - libglew-dev + - liblua5.2-dev + - libsfml-dev + - os: linux + compiler: gcc + env: VALGRIND_SAMPLES="1" + services: + - xvfb + addons: + apt: + packages: + - cmake + - ninja-build + - libsdl2-dev + - libsdl2-image-dev + - libfreetype6-dev + - libglew-dev + - liblua5.2-dev + - libsfml-dev + - mesa-utils + - valgrind + +install: + - mkdir -p $HOME/.deps + - | + if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then + if [[ ! -d "$HOME/.deps/cmake" ]]; then + cd $HOME/.deps + CMAKE_URL="https://cmake.org/files/v3.16/cmake-3.16.3-Linux-x86_64.tar.gz" + mkdir -p cmake && travis_retry wget --no-clobber --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake + fi + export PATH=${HOME}/.deps/cmake/bin:${PATH} + echo ${PATH} + fi + - cmake --version + - cd "$TRAVIS_BUILD_DIR" + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cmake -DNO_THIRDPARTY_CONTAINERS=ON -DENABLE_PRECOMPILED_HEADERS=OFF -G Xcode .; fi + - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then cmake -DBUILD_LUA_BINDINGS=ON -DBUILD_SAMPLES=ON -DDISABLE_RTTI_AND_EXCEPTIONS=${DISABLE_RTTI_AND_EXCEPTIONS:-OFF} -DNO_THIRDPARTY_CONTAINERS=${NO_THIRDPARTY_CONTAINERS:-OFF} -DNO_FONT_INTERFACE_DEFAULT=${NO_FONT_INTERFACE_DEFAULT:-OFF} -G Ninja .; fi + +before_script: + - if [[ "$VALGRIND_SAMPLES" == "1" ]] && [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export DISPLAY=:99.0; fi + +script: + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then xcodebuild -project rmlui.xcodeproj/ -jobs 4 -configuration Release -scheme ALL_BUILD | xcpretty --color; test ${PIPESTATUS[0]} -eq 0; fi + - if [[ "$TRAVIS_OS_NAME" != "osx" ]]; then ninja; fi + - if [[ "$VALGRIND_SAMPLES" == "1" ]]; then mkdir build && DESTDIR=build ninja install; fi + - | + if [[ "$VALGRIND_SAMPLES" == "1" ]]; then + cnt=0 + vout=$(mktemp) + for f in $(find $TRAVIS_BUILD_DIR/build/usr/local/opt/RmlUi/Samples/ -executable -type f); do + cd `dirname $f` + sample=$(basename $f) + printf "\033[0;36m$sample\033[0m\n" + LD_LIBRARY_PATH=$TRAVIS_BUILD_DIR/build/usr/local/lib timeout --preserve-status --signal=TERM --kill-after=15 10 valgrind --leak-check=full --track-origins=yes --suppressions=$TRAVIS_BUILD_DIR/.travis.valgrind.supp --error-exitcode=1 --log-fd=1 ./$sample >>$vout + cnt=$((cnt+1)) + done; + + cat $vout + okcnt=$(grep 'ERROR SUMMARY: 0 errors' $vout | wc -l) + + if [[ "$okcnt" != "$cnt" ]]; then exit 1; fi + fi diff --git a/thirdparty/RmlUi/CMake/FileList.cmake b/thirdparty/RmlUi/CMake/FileList.cmake new file mode 100644 index 000000000..9ffb290b7 --- /dev/null +++ b/thirdparty/RmlUi/CMake/FileList.cmake @@ -0,0 +1,562 @@ +# This file was auto-generated with gen_filelists.sh + +set(Core_HDR_FILES + ${PROJECT_SOURCE_DIR}/Source/Core/Clock.h + ${PROJECT_SOURCE_DIR}/Source/Core/ComputeProperty.h + ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/DataControllerDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/DataExpression.h + ${PROJECT_SOURCE_DIR}/Source/Core/DataViewDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorGradient.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNinePatch.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontal.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontalInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImage.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImageInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVertical.h + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementAnimation.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementBackground.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementBorder.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementDecoration.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementHandle.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementImage.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementTextSelection.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputType.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeButton.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeCheckbox.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeRadio.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeRange.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeSubmit.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeText.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetDropDown.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetSlider.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInput.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInputMultiLine.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInputSingleLine.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInputSingleLinePassword.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/XMLNodeHandlerDataGrid.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/XMLNodeHandlerTabSet.h + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/XMLNodeHandlerTextArea.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.h + ${PROJECT_SOURCE_DIR}/Source/Core/ElementTextDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/EventDispatcher.h + ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancerDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/EventIterators.h + ${PROJECT_SOURCE_DIR}/Source/Core/EventSpecification.h + ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectBlur.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectGlow.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.h + ${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.h + ${PROJECT_SOURCE_DIR}/Source/Core/IdNameMap.h + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.h + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.h + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutEngine.h + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBox.h + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBoxText.h + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutLineBox.h + ${PROJECT_SOURCE_DIR}/Source/Core/Memory.h + ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.h + ${PROJECT_SOURCE_DIR}/Source/Core/Pool.h + ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertiesIterator.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserString.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserTransform.h + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyShorthandDefinition.h + ${PROJECT_SOURCE_DIR}/Source/Core/StreamFile.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetFactory.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNode.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelector.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorEmpty.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstChild.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstOfType.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastChild.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastOfType.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthChild.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastChild.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastOfType.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthOfType.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyChild.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyOfType.h + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetParser.h + ${PROJECT_SOURCE_DIR}/Source/Core/Template.h + ${PROJECT_SOURCE_DIR}/Source/Core/TemplateCache.h + ${PROJECT_SOURCE_DIR}/Source/Core/TextureDatabase.h + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayout.h + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRectangle.h + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRow.h + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.h + ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.h + ${PROJECT_SOURCE_DIR}/Source/Core/TransformState.h + ${PROJECT_SOURCE_DIR}/Source/Core/TransformUtilities.h + ${PROJECT_SOURCE_DIR}/Source/Core/Utilities.h + ${PROJECT_SOURCE_DIR}/Source/Core/WidgetScroll.h + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerBody.h + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerHead.h + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerTemplate.h + ${PROJECT_SOURCE_DIR}/Source/Core/XMLParseTools.h +) + +set(MASTER_Core_PUB_HDR_FILES + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core.h +) + +set(Core_PUB_HDR_FILES + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Config/Config.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Animation.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/BaseXMLParser.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Box.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Colour.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Colour.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ComputedValues.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Containers/chobo/flat_map.hpp + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Containers/chobo/flat_set.hpp + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Containers/robin_hood.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Context.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ContextInstancer.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ConvolutionFilter.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Core.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DataController.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DataModel.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DataTypeRegister.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DataTypes.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DataVariable.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DataView.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Debug.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Decorator.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/DecoratorInstancer.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Dictionary.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Element.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Element.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementDocument.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementInstancer.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/DataFormatter.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/DataQuery.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/DataSource.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/DataSourceListener.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementDataGrid.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementDataGridCell.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementDataGridExpandButton.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementDataGridRow.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementForm.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementFormControl.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementFormControlDataSelect.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementFormControlInput.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementFormControlSelect.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementFormControlTextArea.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementProgressBar.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/ElementTabSet.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Elements/SelectOption.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementScroll.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementText.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ElementUtilities.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Event.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/EventInstancer.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/EventListener.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/EventListenerInstancer.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Factory.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FileInterface.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontEffect.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontEffectInstancer.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontEngineInterface.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/FontGlyph.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Geometry.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/GeometryUtilities.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Header.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ID.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Input.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Log.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Math.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/MathTypes.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Matrix4.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Matrix4.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ObserverPtr.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Platform.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Plugin.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Profiling.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertiesIteratorView.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Property.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertyDefinition.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertyDictionary.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertyIdSet.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertyParser.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/PropertySpecification.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/RenderInterface.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/ScriptInterface.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Spritesheet.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Stream.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StreamMemory.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StringUtilities.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StyleSheet.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/StyleSheetSpecification.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/SystemInterface.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Texture.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Traits.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Transform.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/TransformPrimitive.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Tween.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/TypeConverter.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/TypeConverter.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Types.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/URL.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Variant.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Variant.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vector2.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vector2.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vector3.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vector3.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vector4.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vector4.inl + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/Vertex.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/XMLNodeHandler.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Core/XMLParser.h +) + +set(Core_SRC_FILES + ${PROJECT_SOURCE_DIR}/Source/Core/BaseXMLParser.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Box.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Clock.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ComputeProperty.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Context.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ContextInstancerDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ConvolutionFilter.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Core.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataController.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataControllerDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataExpression.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataModel.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataTypeRegister.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataVariable.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataView.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DataViewDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Decorator.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorGradient.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorNinePatch.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiled.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBox.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledBoxInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontal.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledHorizontalInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImage.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledImageInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVertical.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DecoratorTiledVerticalInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/DocumentHeader.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Element.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementAnimation.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementBackground.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementBorder.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementDecoration.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementDefinition.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementDocument.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementHandle.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/DataFormatter.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/DataQuery.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/DataSource.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/DataSourceListener.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementDataGrid.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementDataGridCell.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementDataGridExpandButton.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementDataGridRow.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementForm.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementFormControl.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementFormControlDataSelect.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementFormControlInput.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementFormControlSelect.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementFormControlTextArea.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementImage.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementProgressBar.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementTabSet.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/ElementTextSelection.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputType.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeButton.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeCheckbox.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeRadio.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeRange.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeSubmit.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/InputTypeText.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/SelectOption.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetDropDown.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetSlider.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInput.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInputMultiLine.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInputSingleLine.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/WidgetTextInputSingleLinePassword.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/XMLNodeHandlerDataGrid.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/XMLNodeHandlerTabSet.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Elements/XMLNodeHandlerTextArea.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementScroll.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementStyle.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementText.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementTextDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ElementUtilities.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Event.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/EventDispatcher.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/EventInstancerDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/EventListenerInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/EventSpecification.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Factory.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FileInterface.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FileInterfaceDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffect.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectBlur.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectGlow.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectOutline.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEffectShadow.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineInterface.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Geometry.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/GeometryDatabase.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/GeometryUtilities.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBox.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutBlockBoxSpace.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutEngine.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBox.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutInlineBoxText.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/LayoutLineBox.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Log.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Math.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Memory.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/ObserverPtr.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Plugin.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PluginRegistry.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Profiling.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertiesIteratorView.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Property.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDefinition.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyDictionary.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserAnimation.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserColour.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserKeyword.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserNumber.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserString.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertyParserTransform.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/PropertySpecification.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/RenderInterface.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Spritesheet.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Stream.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StreamFile.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StreamMemory.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StringUtilities.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheet.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetFactory.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNode.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelector.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorEmpty.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstChild.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorFirstOfType.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastChild.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorLastOfType.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthChild.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastChild.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorNthOfType.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyChild.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetParser.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/StyleSheetSpecification.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/SystemInterface.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Template.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TemplateCache.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Texture.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TextureDatabase.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayout.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRectangle.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutRow.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TextureLayoutTexture.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TextureResource.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Transform.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TransformPrimitive.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TransformState.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TransformUtilities.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Tween.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/TypeConverter.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/URL.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Variant.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Vector3.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/Vector4.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/WidgetScroll.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandler.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerBody.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerHead.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLNodeHandlerTemplate.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLParser.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/XMLParseTools.cpp +) + +set(Debugger_HDR_FILES + ${PROJECT_SOURCE_DIR}/Source/Debugger/BeaconSource.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/CommonSource.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/DebuggerPlugin.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/DebuggerSystemInterface.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementContextHook.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementLog.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/FontSource.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/Geometry.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/InfoSource.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/LogSource.h + ${PROJECT_SOURCE_DIR}/Source/Debugger/MenuSource.h +) + +set(MASTER_Debugger_PUB_HDR_FILES + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Debugger.h +) + +set(Debugger_PUB_HDR_FILES + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Debugger/Debugger.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Debugger/Header.h +) + +set(Debugger_SRC_FILES + ${PROJECT_SOURCE_DIR}/Source/Debugger/Debugger.cpp + ${PROJECT_SOURCE_DIR}/Source/Debugger/DebuggerPlugin.cpp + ${PROJECT_SOURCE_DIR}/Source/Debugger/DebuggerSystemInterface.cpp + ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementContextHook.cpp + ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementInfo.cpp + ${PROJECT_SOURCE_DIR}/Source/Debugger/ElementLog.cpp + ${PROJECT_SOURCE_DIR}/Source/Debugger/Geometry.cpp +) + +if(NOT NO_FONT_INTERFACE_DEFAULT) + set(Core_HDR_FILES + ${Core_HDR_FILES} + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFace.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceHandleDefault.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceLayer.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFamily.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontProvider.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontTypes.h + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FreeTypeInterface.h + ) + + set(Core_SRC_FILES + ${Core_SRC_FILES} + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFace.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFaceLayer.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontFamily.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FontProvider.cpp + ${PROJECT_SOURCE_DIR}/Source/Core/FontEngineDefault/FreeTypeInterface.cpp + ) +endif() + +set(Lua_HDR_FILES + ${PROJECT_SOURCE_DIR}/Source/Lua/Colourb.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Colourf.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Context.h + ${PROJECT_SOURCE_DIR}/Source/Lua/ContextDocumentsProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Document.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Element.h + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementAttributesProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementChildNodesProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/As.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/DataFormatter.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/DataSource.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementDataGrid.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementDataGridRow.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementForm.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControl.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlDataSelect.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlInput.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlSelect.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlTextArea.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementTabSet.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/LuaDataFormatter.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/LuaDataSource.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/SelectOptionsProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementStyleProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementText.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Event.h + ${PROJECT_SOURCE_DIR}/Source/Lua/EventParametersProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/GlobalLuaFunctions.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Log.h + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaDocument.h + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaDocumentElementInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaElementInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaEventListener.h + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaEventListenerInstancer.h + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaPlugin.h + ${PROJECT_SOURCE_DIR}/Source/Lua/RmlUi.h + ${PROJECT_SOURCE_DIR}/Source/Lua/RmlUiContextsProxy.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Vector2f.h + ${PROJECT_SOURCE_DIR}/Source/Lua/Vector2i.h +) + +set(Lua_PUB_HDR_FILES + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Lua/Header.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Lua/IncludeLua.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Lua/Interpreter.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Lua/Lua.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Lua/LuaType.h + ${PROJECT_SOURCE_DIR}/Include/RmlUi/Lua/Utilities.h +) + +set(Lua_SRC_FILES + ${PROJECT_SOURCE_DIR}/Source/Lua/Colourb.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Colourf.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Context.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/ContextDocumentsProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Document.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Element.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementAttributesProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementChildNodesProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/DataFormatter.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/DataSource.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementDataGrid.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementDataGridRow.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementForm.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControl.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlDataSelect.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlInput.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlSelect.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementFormControlTextArea.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/ElementTabSet.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/LuaDataFormatter.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/LuaDataSource.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Elements/SelectOptionsProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementStyleProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/ElementText.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Event.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/EventParametersProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/GlobalLuaFunctions.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Interpreter.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Log.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Lua.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaDocument.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaDocumentElementInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaElementInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaEventListener.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaEventListenerInstancer.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaPlugin.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/LuaType.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/RmlUi.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/RmlUiContextsProxy.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Utilities.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Vector2f.cpp + ${PROJECT_SOURCE_DIR}/Source/Lua/Vector2i.cpp +) + diff --git a/thirdparty/RmlUi/CMake/Modules/FindCarbon.cmake b/thirdparty/RmlUi/CMake/Modules/FindCarbon.cmake new file mode 100644 index 000000000..bae2ee82d --- /dev/null +++ b/thirdparty/RmlUi/CMake/Modules/FindCarbon.cmake @@ -0,0 +1,36 @@ +# - Try to find Carbon +# Once done, this will define +# +# Carbon_FOUND - system has Carbon +# Carbon_INCLUDE_DIRS - the Carbon include directories +# Carbon_LIBRARIES - link these to use Carbon + +include(FindPkgMacros) +findpkg_begin(Carbon) + +# construct search paths +set(Carbon_PREFIX_PATH ${Carbon_HOME} $ENV{Carbon_HOME} + ${OGRE_HOME} $ENV{OGRE_HOME}) +create_search_paths(Carbon) +# redo search if prefix path changed +clear_if_changed(Carbon_PREFIX_PATH + Carbon_LIBRARY_FWK + Carbon_LIBRARY_REL + Carbon_LIBRARY_DBG + Carbon_INCLUDE_DIR +) + +set(Carbon_LIBRARY_NAMES Carbon) +get_debug_names(Carbon_LIBRARY_NAMES) + +use_pkgconfig(Carbon_PKGC Carbon) + +findpkg_framework(Carbon) + +find_path(Carbon_INCLUDE_DIR NAMES Carbon.h HINTS ${Carbon_INC_SEARCH_PATH} ${Carbon_PKGC_INCLUDE_DIRS} PATH_SUFFIXES Carbon) +find_library(Carbon_LIBRARY_REL NAMES ${Carbon_LIBRARY_NAMES} HINTS ${Carbon_LIB_SEARCH_PATH} ${Carbon_PKGC_LIBRARY_DIRS}) +find_library(Carbon_LIBRARY_DBG NAMES ${Carbon_LIBRARY_NAMES_DBG} HINTS ${Carbon_LIB_SEARCH_PATH} ${Carbon_PKGC_LIBRARY_DIRS}) +make_library_set(Carbon_LIBRARY) + +findpkg_finish(Carbon) +add_parent_dir(Carbon_INCLUDE_DIRS Carbon_INCLUDE_DIR) \ No newline at end of file diff --git a/thirdparty/RmlUi/CMake/Modules/FindPkgMacros.cmake b/thirdparty/RmlUi/CMake/Modules/FindPkgMacros.cmake new file mode 100644 index 000000000..2eda3b88d --- /dev/null +++ b/thirdparty/RmlUi/CMake/Modules/FindPkgMacros.cmake @@ -0,0 +1,147 @@ +################################################################## +# Provides some common functionality for the FindPackage modules +################################################################## + +# Begin processing of package +macro(findpkg_begin PREFIX) + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS "Looking for ${PREFIX}...") + endif () +endmacro(findpkg_begin) + +# Display a status message unless FIND_QUIETLY is set +macro(pkg_message PREFIX) + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS ${ARGN}) + endif () +endmacro(pkg_message) + +# Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes +macro(getenv_path VAR) + set(ENV_${VAR} $ENV{${VAR}}) + # replace won't work if var is blank + if (ENV_${VAR}) + string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) + endif () +endmacro(getenv_path) + +# Construct search paths for includes and libraries from a PREFIX_PATH +macro(create_search_paths PREFIX) + foreach(dir ${${PREFIX}_PREFIX_PATH}) + set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH} + ${dir}/include ${dir}/Include ${dir}/include/${PREFIX} ${dir}/Headers) + set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} + ${dir}/lib ${dir}/Lib ${dir}/lib/${PREFIX} ${dir}/Libs) + set(${PREFIX}_BIN_SEARCH_PATH ${${PREFIX}_BIN_SEARCH_PATH} + ${dir}/bin) + endforeach(dir) + set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH}) +endmacro(create_search_paths) + +# clear cache variables if a certain variable changed +macro(clear_if_changed TESTVAR) + # test against internal check variable + # HACK: Apparently, adding a variable to the cache cleans up the list + # a bit. We need to also remove any empty strings from the list, but + # at the same time ensure that we are actually dealing with a list. + list(APPEND ${TESTVAR} "") + list(REMOVE_ITEM ${TESTVAR} "") + if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}") + message(STATUS "${TESTVAR} changed.") + foreach(var ${ARGN}) + set(${var} "NOTFOUND" CACHE STRING "x" FORCE) + endforeach(var) + endif () + set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE) +endmacro(clear_if_changed) + +# Try to get some hints from pkg-config, if available +macro(use_pkgconfig PREFIX PKGNAME) + find_package(PkgConfig) + if (PKG_CONFIG_FOUND) + pkg_check_modules(${PREFIX} ${PKGNAME}) + endif () +endmacro (use_pkgconfig) + +# Couple a set of release AND debug libraries (or frameworks) +macro(make_library_set PREFIX) + if (${PREFIX}_FWK) + set(${PREFIX} ${${PREFIX}_FWK}) + elseif (${PREFIX}_REL AND ${PREFIX}_DBG) + set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG}) + elseif (${PREFIX}_REL) + set(${PREFIX} ${${PREFIX}_REL}) + elseif (${PREFIX}_DBG) + set(${PREFIX} ${${PREFIX}_DBG}) + endif () +endmacro(make_library_set) + +# Generate debug names from given release names +macro(get_debug_names PREFIX) + foreach(i ${${PREFIX}}) + set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) + endforeach(i) +endmacro(get_debug_names) + +# Add the parent dir from DIR to VAR +macro(add_parent_dir VAR DIR) + get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE) + set(${VAR} ${${VAR}} ${${DIR}_TEMP}) +endmacro(add_parent_dir) + +# Do the final processing for the package find. +macro(findpkg_finish PREFIX) + # skip if already processed during this run + if (NOT ${PREFIX}_FOUND) + if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) + set(${PREFIX}_FOUND TRUE) + set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) + set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") + endif () + else () + if (NOT ${PREFIX}_FIND_QUIETLY) + message(STATUS "Could not locate ${PREFIX}") + endif () + if (${PREFIX}_FIND_REQUIRED) + message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.") + endif () + endif () + + mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK) + endif () +endmacro(findpkg_finish) + + +# Slightly customised framework finder +MACRO(findpkg_framework fwk) + IF(APPLE) + SET(${fwk}_FRAMEWORK_PATH + ${${fwk}_FRAMEWORK_SEARCH_PATH} + ${CMAKE_FRAMEWORK_PATH} + ~/Library/Frameworks + /Library/Frameworks + /System/Library/Frameworks + /Network/Library/Frameworks + /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/ + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Release + ${CMAKE_CURRENT_SOURCE_DIR}/lib/Debug + ${OGRE_PREFIX_PATH}/lib/Release + ${OGRE_PREFIX_PATH}/lib/Debug + ${OGRE_PREFIX_BUILD}/lib/Release + ${OGRE_PREFIX_BUILD}/lib/Debug + ) + FOREACH(dir ${${fwk}_FRAMEWORK_PATH}) + SET(fwkpath ${dir}/${fwk}.framework) + IF(EXISTS ${fwkpath}) + SET(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES} + ${fwkpath}/Headers ${fwkpath}/PrivateHeaders) + SET(${fwk}_FRAMEWORK_PATH ${dir}) + if (NOT ${fwk}_LIBRARY_FWK) + SET(${fwk}_LIBRARY_FWK "-framework ${fwk}") + endif () + ENDIF(EXISTS ${fwkpath}) + ENDFOREACH(dir) + ENDIF(APPLE) +ENDMACRO(findpkg_framework) \ No newline at end of file diff --git a/thirdparty/RmlUi/CMake/Modules/FindSDL2.cmake b/thirdparty/RmlUi/CMake/Modules/FindSDL2.cmake new file mode 100644 index 000000000..d5ea55608 --- /dev/null +++ b/thirdparty/RmlUi/CMake/Modules/FindSDL2.cmake @@ -0,0 +1,165 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# Source: https://code.google.com/p/freerct/source/browse/trunk/CMake/FindSDL2.cmake +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDLmain.h and SDLmain.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +SET(SDL2_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES include/SDL2 include + PATHS ${SDL2_SEARCH_PATHS} +) + +FIND_LIBRARY(SDL2_LIBRARY_TEMP + NAMES SDL2 + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS ${SDL2_SEARCH_PATHS} +) + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS ${SDL2_SEARCH_PATHS} + ) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +IF(SDL2_LIBRARY_TEMP) + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/thirdparty/RmlUi/CMake/Modules/FindSDL2_image.cmake b/thirdparty/RmlUi/CMake/Modules/FindSDL2_image.cmake new file mode 100644 index 000000000..d1aa11632 --- /dev/null +++ b/thirdparty/RmlUi/CMake/Modules/FindSDL2_image.cmake @@ -0,0 +1,119 @@ +# Locate SDL2_image library +# This module defines +# SDL2_IMAGE_LIBRARY, the name of the library to link against +# SDL2_IMAGE_FOUND, if false, do not try to link to SDL2_image +# SDL2_IMAGE_INCLUDE_DIR, where to find SDL.h +# +# Source: https://code.google.com/p/freerct/source/browse/trunk/CMake/FindSDL2_ttf.cmake +# +# $SDL2_IMAGE_DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2_IMAGE_DIR +# used in building SDL2_image. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +SET(SDL2_IMAGE_SEARCH_PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) + +FIND_PATH(SDL2_IMAGE_INCLUDE_DIR SDL_image.h + HINTS + $ENV{SDL2_IMAGE_DIR} + PATH_SUFFIXES include/SDL2 include + PATHS ${SDL2_IMAGE_SEARCH_PATHS} +) + +FIND_LIBRARY(SDL2_IMAGE_LIBRARY_TEMP + NAMES SDL2_image + HINTS + $ENV{SDL2_IMAGE_DIR} + PATH_SUFFIXES lib64 lib + PATHS ${SDL2_IMAGE_SEARCH_PATHS} +) + +# SDL2_image may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +# IF(NOT APPLE) + # FIND_PACKAGE(Threads) +# ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2_image -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +IF(SDL2_IMAGE_LIBRARY_TEMP) + # For OS X, SDL2_IMAGE uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + # IF(APPLE) + # SET(SDL2_IMAGE_LIBRARY_TEMP ${SDL2_IMAGE_LIBRARY_TEMP} "-framework Cocoa") + # ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + # IF(NOT APPLE) + # SET(SDL2_IMAGE_LIBRARY_TEMP ${SDL2_IMAGE_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + # ENDIF(NOT APPLE) + + # For MinGW library + # IF(MINGW) + # SET(SDL2_IMAGE_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_IMAGE_LIBRARY_TEMP}) + # ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_IMAGE_LIBRARY ${SDL2_IMAGE_LIBRARY_TEMP} CACHE STRING "Where the SDL2_IMAGE Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_IMAGE_LIBRARY_TEMP "${SDL2_IMAGE_LIBRARY_TEMP}" CACHE INTERNAL "") +ENDIF(SDL2_IMAGE_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2_image REQUIRED_VARS SDL2_IMAGE_LIBRARY SDL2_IMAGE_INCLUDE_DIR) diff --git a/thirdparty/RmlUi/CMake/Modules/FindSFML.cmake b/thirdparty/RmlUi/CMake/Modules/FindSFML.cmake new file mode 100644 index 000000000..99cbff2e0 --- /dev/null +++ b/thirdparty/RmlUi/CMake/Modules/FindSFML.cmake @@ -0,0 +1,209 @@ +# This script locates the SFML library +# ------------------------------------ +# +# Usage +# ----- +# +# When you try to locate the SFML libraries, you must specify which modules you want to use (system, window, graphics, network, audio, main). +# If none is given, the SFML_LIBRARIES variable will be empty and you'll end up linking to nothing. +# example: +# find_package(SFML COMPONENTS graphics window system) // find the graphics, window and system modules +# +# You can enforce a specific version, either MAJOR.MINOR or only MAJOR. +# If nothing is specified, the version won't be checked (ie. any version will be accepted). +# example: +# find_package(SFML COMPONENTS ...) // no specific version required +# find_package(SFML 2 COMPONENTS ...) // any 2.x version +# find_package(SFML 2.4 COMPONENTS ...) // version 2.4 or greater +# +# By default, the dynamic libraries of SFML will be found. To find the static ones instead, +# you must set the SFML_STATIC_LIBRARIES variable to TRUE before calling find_package(SFML ...). +# In case of static linking, the SFML_STATIC macro will also be defined by this script. +# example: +# set(SFML_STATIC_LIBRARIES TRUE) +# find_package(SFML 2 COMPONENTS network system) +# +# On Mac OS X if SFML_STATIC_LIBRARIES is not set to TRUE then by default CMake will search for frameworks unless +# CMAKE_FIND_FRAMEWORK is set to "NEVER" for example. Please refer to CMake documentation for more details. +# Moreover, keep in mind that SFML frameworks are only available as release libraries unlike dylibs which +# are available for both release and debug modes. +# +# If SFML is not installed in a standard path, you can use the SFML_ROOT CMake (or environment) variable +# to tell CMake where SFML is. +# +# Output +# ------ +# +# This script defines the following variables: +# - For each specified module XXX (system, window, graphics, network, audio, main): +# - SFML_XXX_LIBRARY_DEBUG: the name of the debug library of the xxx module (set to SFML_XXX_LIBRARY_RELEASE is no debug version is found) +# - SFML_XXX_LIBRARY_RELEASE: the name of the release library of the xxx module (set to SFML_XXX_LIBRARY_DEBUG is no release version is found) +# - SFML_XXX_LIBRARY: the name of the library to link to for the xxx module (includes both debug and optimized names if necessary) +# - SFML_XXX_FOUND: true if either the debug or release library of the xxx module is found +# - SFML_LIBRARIES: the list of all libraries corresponding to the required modules +# - SFML_FOUND: true if all the required modules are found +# - SFML_INCLUDE_DIR: the path where SFML headers are located (the directory containing the SFML/Config.hpp file) +# +# example: +# find_package(SFML 2 COMPONENTS system window graphics audio REQUIRED) +# include_directories(${SFML_INCLUDE_DIR}) +# add_executable(myapp ...) +# target_link_libraries(myapp ${SFML_LIBRARIES}) + +# define the SFML_STATIC macro if static build was chosen +if(SFML_STATIC_LIBRARIES) + add_definitions(-DSFML_STATIC) +endif() + +# deduce the libraries suffix from the options +set(FIND_SFML_LIB_SUFFIX "") +if(SFML_STATIC_LIBRARIES) + set(FIND_SFML_LIB_SUFFIX "${FIND_SFML_LIB_SUFFIX}-s") +endif() + +# find the SFML include directory +find_path(SFML_INCLUDE_DIR SFML/Config.hpp + PATH_SUFFIXES include + PATHS + ${SFML_ROOT} + $ENV{SFML_ROOT} + ~/Library/Frameworks + /Library/Frameworks + /usr/local/ + /usr/ + /sw # Fink + /opt/local/ # DarwinPorts + /opt/csw/ # Blastwave + /opt/) + +# check the version number +set(SFML_VERSION_OK TRUE) +if(SFML_FIND_VERSION AND SFML_INCLUDE_DIR) + # extract the major and minor version numbers from SFML/Config.hpp + # we have to handle framework a little bit differently : + if("${SFML_INCLUDE_DIR}" MATCHES "SFML.framework") + set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/Headers/Config.hpp") + else() + set(SFML_CONFIG_HPP_INPUT "${SFML_INCLUDE_DIR}/SFML/Config.hpp") + endif() + FILE(READ "${SFML_CONFIG_HPP_INPUT}" SFML_CONFIG_HPP_CONTENTS) + STRING(REGEX MATCH ".*#define SFML_VERSION_MAJOR ([0-9]+).*#define SFML_VERSION_MINOR ([0-9]+).*" SFML_CONFIG_HPP_CONTENTS "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_MAJOR ([0-9]+).*" "\\1" SFML_VERSION_MAJOR "${SFML_CONFIG_HPP_CONTENTS}") + STRING(REGEX REPLACE ".*#define SFML_VERSION_MINOR ([0-9]+).*" "\\1" SFML_VERSION_MINOR "${SFML_CONFIG_HPP_CONTENTS}") + math(EXPR SFML_REQUESTED_VERSION "${SFML_FIND_VERSION_MAJOR} * 10 + ${SFML_FIND_VERSION_MINOR}") + + # if we could extract them, compare with the requested version number + if (SFML_VERSION_MAJOR) + # transform version numbers to an integer + math(EXPR SFML_VERSION "${SFML_VERSION_MAJOR} * 10 + ${SFML_VERSION_MINOR}") + + # compare them + if(SFML_VERSION LESS SFML_REQUESTED_VERSION) + set(SFML_VERSION_OK FALSE) + endif() + else() + # SFML version is < 2.0 + if (SFML_REQUESTED_VERSION GREATER 19) + set(SFML_VERSION_OK FALSE) + set(SFML_VERSION_MAJOR 1) + set(SFML_VERSION_MINOR x) + endif() + endif() +endif() + +# find the requested modules +set(SFML_FOUND TRUE) # will be set to false if one of the required modules is not found +set(FIND_SFML_LIB_PATHS + ${SFML_ROOT} + $ENV{SFML_ROOT} + ~/Library/Frameworks + /Library/Frameworks + /usr/local + /usr + /sw + /opt/local + /opt/csw + /opt) +foreach(FIND_SFML_COMPONENT ${SFML_FIND_COMPONENTS}) + string(TOLOWER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_LOWER) + string(TOUPPER ${FIND_SFML_COMPONENT} FIND_SFML_COMPONENT_UPPER) + set(FIND_SFML_COMPONENT_NAME sfml-${FIND_SFML_COMPONENT_LOWER}${FIND_SFML_LIB_SUFFIX}) + + # no suffix for sfml-main, it is always a static library + if(FIND_SFML_COMPONENT_LOWER STREQUAL "main") + set(FIND_SFML_COMPONENT_NAME sfml-${FIND_SFML_COMPONENT_LOWER}) + endif() + + # debug library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG + NAMES ${FIND_SFML_COMPONENT_NAME}-d + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_LIB_PATHS}) + + # release library + find_library(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE + NAMES ${FIND_SFML_COMPONENT_NAME} + PATH_SUFFIXES lib64 lib + PATHS ${FIND_SFML_LIB_PATHS}) + + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG OR SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + # library found + set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND TRUE) + + # if both are found, set SFML_XXX_LIBRARY to contain both + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY debug ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG} + optimized ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + endif() + + # if only one debug/release variant is found, set the other to be equal to the found one + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE) + # debug and not release + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG}) + endif() + if (SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE AND NOT SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG) + # release and not debug + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY ${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE}) + endif() + else() + # library not found + set(SFML_FOUND FALSE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_FOUND FALSE) + set(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY "") + set(FIND_SFML_MISSING "${FIND_SFML_MISSING} SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY") + endif() + + # mark as advanced + MARK_AS_ADVANCED(SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_RELEASE + SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY_DEBUG) + + # add to the global list of libraries + set(SFML_LIBRARIES ${SFML_LIBRARIES} "${SFML_${FIND_SFML_COMPONENT_UPPER}_LIBRARY}") +endforeach() + +# handle errors +if(NOT SFML_VERSION_OK) + # SFML version not ok + set(FIND_SFML_ERROR "SFML found but version too low (requested: ${SFML_FIND_VERSION}, found: ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR})") + set(SFML_FOUND FALSE) +elseif(NOT SFML_FOUND) + # include directory or library not found + set(FIND_SFML_ERROR "Could NOT find SFML (missing: ${FIND_SFML_MISSING})") +endif() +if (NOT SFML_FOUND) + if(SFML_FIND_REQUIRED) + # fatal error + message(FATAL_ERROR ${FIND_SFML_ERROR}) + elseif(NOT SFML_FIND_QUIETLY) + # error but continue + message("${FIND_SFML_ERROR}") + endif() +endif() + +# handle success +if(SFML_FOUND) + message(STATUS "Found SFML ${SFML_VERSION_MAJOR}.${SFML_VERSION_MINOR} in ${SFML_INCLUDE_DIR}") +endif() diff --git a/thirdparty/RmlUi/CMake/Modules/FindTracy.cmake b/thirdparty/RmlUi/CMake/Modules/FindTracy.cmake new file mode 100644 index 000000000..314752a48 --- /dev/null +++ b/thirdparty/RmlUi/CMake/Modules/FindTracy.cmake @@ -0,0 +1,20 @@ +# - Try to find Tracy +# Once done, this will define +# +# TRACY_FOUND - system has Tracy +# TRACY_INCLUDE_DIR - the Tracy include directory + +set(TRACY_DIR "" CACHE PATH "Parent directory of Tracy library") + +find_path(TRACY_INCLUDE_DIR Tracy.hpp PATHS ${TRACY_DIR} $ENV{TRACY_DIR} PATH_SUFFIXES tracy) + +set(TRACY_FOUND "NO") +if(TRACY_INCLUDE_DIR) + message(STATUS "Found Tracy ${TRACY_INCLUDE_DIR}...") + mark_as_advanced(TRACY_DIR TRACY_INCLUDE_DIR) + set(TRACY_FOUND "YES") +elseif(Tracy_FIND_REQUIRED) + message(FATAL_ERROR "Required library Tracy not found! Install the library and try again. If the library is already installed, set the missing variables manually in cmake.") +else() + message(STATUS "Library Tracy not found...") +endif() diff --git a/thirdparty/RmlUi/CMake/Platform/iOS.cmake b/thirdparty/RmlUi/CMake/Platform/iOS.cmake new file mode 100644 index 000000000..274a5a1c1 --- /dev/null +++ b/thirdparty/RmlUi/CMake/Platform/iOS.cmake @@ -0,0 +1,190 @@ +# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake +# files which are included with CMake 2.8.4 +# It has been altered for iOS development + +# Options: +# +# IOS_PLATFORM = OS (default) or SIMULATOR +# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders +# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. +# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. +# +# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder +# By default this location is automatcially chosen based on the IOS_PLATFORM value above. +# If set manually, it will override the default location and force the user of a particular Developer Platform +# +# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder +# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. +# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. +# If set manually, this will force the use of a specific SDK version + +# Macros: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) +# A convenience macro for setting xcode specific properties on targets +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the iOS environment. +# Thanks to the android-cmake project for providing the command + + +# Standard settings +set (CMAKE_SYSTEM_NAME Darwin) +set (CMAKE_SYSTEM_VERSION 1) +set (UNIX True) +set (APPLE True) +set (IOS True) + +# Required as of cmake 2.8.10 +set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) + +# Determine the cmake host system version so we know where to find the iOS SDKs +find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) +if (CMAKE_UNAME) + exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) + string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") +endif (CMAKE_UNAME) + +# Skip the platform compiler checks for cross compiling +set (CMAKE_CXX_COMPILER_WORKS TRUE) +set (CMAKE_C_COMPILER_WORKS TRUE) + +# All iOS/Darwin specific settings - some may be redundant +set (CMAKE_SHARED_LIBRARY_PREFIX "lib") +set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set (CMAKE_SHARED_MODULE_PREFIX "lib") +set (CMAKE_SHARED_MODULE_SUFFIX ".so") +set (CMAKE_MODULE_EXISTS 1) +set (CMAKE_DL_LIBS "") + +set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +# Hidden visibilty is required for cxx on iOS +set (CMAKE_C_FLAGS_INIT "") +set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden") + +set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") +set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") + +set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") +set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") +set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") + +# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree +# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache +# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) +# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex +if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) +endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + +# Setup iOS platform unless specified manually with IOS_PLATFORM +if (NOT DEFINED IOS_PLATFORM) + set (IOS_PLATFORM "OS") +endif (NOT DEFINED IOS_PLATFORM) +set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") + +# Check the platform selection and setup for developer root +if (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") + + # This causes the installers to properly locate the output libraries + set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") +elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") + set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") + + # This causes the installers to properly locate the output libraries + set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") +else (${IOS_PLATFORM} STREQUAL "OS") + message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") +endif (${IOS_PLATFORM} STREQUAL "OS") + +# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT +# Note Xcode 4.3 changed the installation location, choose the most recent one available +set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") +set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") +if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) + if (EXISTS ${XCODE_POST_43_ROOT}) + set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) + elseif(EXISTS ${XCODE_PRE_43_ROOT}) + set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) + endif (EXISTS ${XCODE_POST_43_ROOT}) +endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) +set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") + +# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT +if (NOT DEFINED CMAKE_IOS_SDK_ROOT) + file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") + if (_CMAKE_IOS_SDKS) + list (SORT _CMAKE_IOS_SDKS) + list (REVERSE _CMAKE_IOS_SDKS) + list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) + else (_CMAKE_IOS_SDKS) + message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") + endif (_CMAKE_IOS_SDKS) + message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") +endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) +set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") + +# Set the sysroot default to the most recent SDK +set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") + +# set the architecture for iOS +# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually +if (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_ARCH armv6 armv7 armv7s arm64) +else (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_ARCH i386 x86_64) +endif (${IOS_PLATFORM} STREQUAL "OS") + +if (NOT DEFINED CMAKE_OSX_ARCHITECTURES) + set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") +endif (NOT DEFINED CMAKE_OSX_ARCHITECTURES) + +# Set the find root to the iOS developer roots and to user defined paths +set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") + +# default to searching for frameworks first +set (CMAKE_FIND_FRAMEWORK FIRST) + +# set up the default search directories for frameworks +set (CMAKE_SYSTEM_FRAMEWORK_PATH + ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks + ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks + ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks +) + +# only search the iOS sdks, not the remainder of the host filesystem +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + + +# This little macro lets you set any XCode specific property +macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) + set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) +endmacro (set_xcode_property) + + +# This macro lets you find executable programs on the host system +macro (find_host_package) + set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set (IOS FALSE) + + find_package(${ARGN}) + + set (IOS TRUE) + set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) + set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endmacro (find_host_package) + diff --git a/thirdparty/RmlUi/CMake/RmlUiConfig.cmake.build.in b/thirdparty/RmlUi/CMake/RmlUiConfig.cmake.build.in new file mode 100644 index 000000000..5afd2838f --- /dev/null +++ b/thirdparty/RmlUi/CMake/RmlUiConfig.cmake.build.in @@ -0,0 +1,11 @@ +@PACKAGE_INIT@ + +set_and_check(RmlUi_INCLUDE_DIRS "@PACKAGE_INCLUDE_DIR@") +set(RmlUi_LIBRARIES @RMLUI_EXPORTED_TARGETS@) +list(GET RmlUi_LIBRARIES 0 RMLUI_FIRST_TARGET) + +if(NOT (TARGET ${RMLUI_FIRST_TARGET})) + include("${CMAKE_CURRENT_LIST_DIR}/RmlUiTargets.cmake") +endif() + +check_required_components(RmlUi) diff --git a/thirdparty/RmlUi/CMake/RmlUiConfig.cmake.install.in b/thirdparty/RmlUi/CMake/RmlUiConfig.cmake.install.in new file mode 100644 index 000000000..88362b270 --- /dev/null +++ b/thirdparty/RmlUi/CMake/RmlUiConfig.cmake.install.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +set_and_check(RmlUi_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") +set(RmlUi_LIBRARIES @RMLUI_EXPORTED_TARGETS@) +include("${CMAKE_CURRENT_LIST_DIR}/RmlUiTargets.cmake") + +check_required_components(RmlUi) diff --git a/thirdparty/RmlUi/CMake/SampleFileList.cmake b/thirdparty/RmlUi/CMake/SampleFileList.cmake new file mode 100644 index 000000000..3c532627f --- /dev/null +++ b/thirdparty/RmlUi/CMake/SampleFileList.cmake @@ -0,0 +1,289 @@ +# This file was auto-generated with gen_samplelists.sh + +set(shell_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/src/precompiled.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/Input.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/Shell.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellFileInterface.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellOpenGL.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellRenderInterfaceExtensions.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellRenderInterfaceOpenGL.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/ShellSystemInterface.h +) + +set(shell_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/src/Input.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/Shell.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellFileInterface.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellRenderInterfaceOpenGL.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/ShellSystemInterface.cpp +) + +set(animation_HDR_FILES +) + +set(animation_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/animation/src/main.cpp +) + +set(benchmark_HDR_FILES +) + +set(benchmark_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/benchmark/src/main.cpp +) + +set(bitmapfont_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineBitmap.h + ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.h +) + +set(bitmapfont_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineBitmap.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/FontEngineInterfaceBitmap.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/src/main.cpp +) + +set(customlog_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/customlog/src/SystemInterface.h +) + +set(customlog_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/customlog/src/main.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/customlog/src/SystemInterface.cpp +) + +set(databinding_HDR_FILES +) + +set(databinding_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/databinding/src/main.cpp +) + +set(demo_HDR_FILES +) + +set(demo_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/demo/src/main.cpp +) + +set(drag_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/DragListener.h + ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/Inventory.h +) + +set(drag_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/DragListener.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/Inventory.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/drag/src/main.cpp +) + +set(loaddocument_HDR_FILES +) + +set(loaddocument_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/loaddocument/src/main.cpp +) + +set(treeview_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/src/FileFormatter.h + ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/src/FileSystem.h +) + +set(treeview_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/src/FileFormatter.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/src/FileSystem.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/src/main.cpp +) + +set(transform_HDR_FILES +) + +set(transform_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/transform/src/main.cpp +) + +set(sdl2_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/RenderInterfaceSDL2.h + ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/SystemInterfaceSDL2.h +) + +set(sdl2_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/main.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/RenderInterfaceSDL2.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/sdl2/src/SystemInterfaceSDL2.cpp +) + +set(sfml2_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/RenderInterfaceSFML.h + ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/SystemInterfaceSFML.h +) + +set(sfml2_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/main.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/RenderInterfaceSFML.cpp + ${PROJECT_SOURCE_DIR}/Samples/basic/sfml2/src/SystemInterfaceSFML.cpp +) + +set(tutorial_template_HDR_FILES +) + +set(tutorial_template_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/template/src/main.cpp +) + +set(tutorial_datagrid_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorDefender.h + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorInstancerDefender.h + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/HighScores.h +) + +set(tutorial_datagrid_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/DecoratorInstancerDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/HighScores.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/src/main.cpp +) + +set(tutorial_datagrid_tree_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorDefender.h + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.h + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScores.h + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScoresShipFormatter.h +) + +set(tutorial_datagrid_tree_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/DecoratorInstancerDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScores.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/HighScoresShipFormatter.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/src/main.cpp +) + +set(tutorial_drag_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/drag/src/Inventory.h +) + +set(tutorial_drag_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/tutorial/drag/src/Inventory.cpp + ${PROJECT_SOURCE_DIR}/Samples/tutorial/drag/src/main.cpp +) + +set(invaders_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorDefender.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerDefender.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerStarfield.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorStarfield.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Defender.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/ElementGame.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Event.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandler.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerHighScore.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerOptions.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerStartGame.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventInstancer.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventManager.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Game.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/GameDetails.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScores.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresNameFormatter.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresShipFormatter.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Invader.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Mothership.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Shield.h + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Sprite.h +) + +set(invaders_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorInstancerStarfield.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/DecoratorStarfield.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Defender.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/ElementGame.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Event.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandler.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerHighScore.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerOptions.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventHandlerStartGame.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventInstancer.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/EventManager.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Game.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/GameDetails.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScores.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresNameFormatter.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/HighScoresShipFormatter.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Invader.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/main.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Mothership.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Shield.cpp + ${PROJECT_SOURCE_DIR}/Samples/invaders/src/Sprite.cpp +) + +set(luainvaders_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorDefender.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorInstancerDefender.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorInstancerStarfield.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorStarfield.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Defender.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/ElementGame.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/ElementGameInstancer.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Game.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/GameDetails.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/HighScores.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Invader.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/LuaInterface.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Mothership.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Shield.h + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Sprite.h +) + +set(luainvaders_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorInstancerDefender.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorInstancerStarfield.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/DecoratorStarfield.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Defender.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/ElementGame.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/ElementGameInstancer.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Game.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/GameDetails.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/HighScores.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Invader.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/LuaInterface.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/main.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Mothership.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Shield.cpp + ${PROJECT_SOURCE_DIR}/Samples/luainvaders/src/Sprite.cpp +) + +# Deal with platform specific sources for sample shell +if(WIN32) + list(APPEND shell_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellWin32.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/InputWin32.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp + ) + list(APPEND shell_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/InputWin32.h + ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/IncludeWindows.h + ) +elseif(APPLE) + list(APPEND shell_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellMacOSX.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/InputMacOSX.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp + ) + list(APPEND shell_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/include/macosx/InputMacOSX.h + ) +else() + list(APPEND shell_SRC_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellX11.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/InputX11.cpp + ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp + ) + list(APPEND shell_HDR_FILES + ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/InputX11.h + ) +endif() diff --git a/thirdparty/RmlUi/CMake/builddist.py b/thirdparty/RmlUi/CMake/builddist.py new file mode 100644 index 000000000..414acc4d4 --- /dev/null +++ b/thirdparty/RmlUi/CMake/builddist.py @@ -0,0 +1,181 @@ +#!/usr/bin/python +import subprocess +import os +import sys +import getopt +import traceback +import shutil +import re + +def Usage(args): + print(sys.argv[0] + ' [-h] [-s] [-b] [-a] [-v version]') + print('') + print(' -h\t: This help screen') + print(' -s\t: Include full source code and build files') + print(' -b\t: Include sample binaries') + print(' -a\t: Create archive using 7z') + print(' -v\t: Specify RmlUi version') + print('') + sys.exit() + +def CheckVSVars(): + if 'VCINSTALLDIR' in os.environ: + return + + if not 'VS90COMNTOOLS' in os.environ: + print("Unable to find VS9 install - check your VS90COMNTOOLS environment variable") + sys.exit() + + path = os.environ['VS90COMNTOOLS'] + subprocess.call('"' + path + 'vsvars32.bat" > NUL && ' + ' '.join(sys.argv)) + sys.exit() + +def ProcessOptions(args): + + options = {'RMLUI_VERSION': 'custom', 'FULL_SOURCE': False, 'ARCHIVE_NAME': 'RmlUi-sdk', 'SAMPLE_BINARIES': False, 'ARCHIVE': False} + + try: + optlist, args = getopt.getopt(args, 'v:hsba') + except getopt.GetoptError as e: + print('\nError: ' + str(e) + '\n') + Usage(args) + + for opt in optlist: + if opt[0] == '-h': + Usage(args) + if opt[0] == '-v': + options['RMLUI_VERSION'] = opt[1] + if opt[0] == '-s': + options['FULL_SOURCE'] = True + options['ARCHIVE_NAME'] = 'RmlUi-source' + if opt[0] == '-b': + options['SAMPLE_BINARIES'] = True + if opt[0] == '-a': + options['ARCHIVE'] = True + + return options + +def Build(project, configs, defines = {}): + + old_cl = '' + if 'CL' in os.environ: + old_cl = os.environ['CL'] + else: + os.environ['CL'] = '' + + for name, value in defines.items(): + os.environ['CL'] = os.environ['CL'] + ' /D' + name + '=' + value + + for config in configs: + cmd = '"' + os.environ['VCINSTALLDIR'] + '\\vcpackages\\vcbuild.exe" /rebuild ' + project + '.vcproj "' + config + '|Win32"' + ret = subprocess.call(cmd) + if ret != 0: + print("Failed to build " + project) + sys.exit() + + os.environ['CL'] = old_cl + +def DelTree(path): + if not os.path.exists(path): + return + + print('Deleting ' + path + '...') + for root, dirs, files in os.walk(path, topdown=False): + for name in files: + os.remove(os.path.join(root, name)) + for name in dirs: + os.rmdir(os.path.join(root, name)) + +def CopyFiles(source_path, destination_path, file_list = [], exclude_directories = [], exclude_files = [], preserve_paths = True): + working_directory = os.getcwd() + source_directory = os.path.abspath(os.path.join(working_directory, os.path.normpath(source_path))) + destination_directory = os.path.abspath(os.path.join(working_directory, os.path.normpath(destination_path))) + print("Copying " + source_directory + " to " + destination_directory + " ...") + + if not os.path.exists(source_directory): + print("Warning: Source directory " + source_directory + " doesn't exist.") + return False + + for root, directories, files in os.walk(source_directory, topdown=True): + directories[:] = [d for d in directories if d not in exclude_directories] + + for file in files: + # Skip files not in the include list. + if len(file_list) > 0: + included = False + for include in file_list: + if re.search(include, file): + included = True + break; + + if not included: + continue + + # Determine our subdirectory. + subdir = root.replace(source_directory, "") + if subdir[:1] == os.path.normcase('/'): + subdir = subdir[1:] + + # Skip paths in the exclude list + excluded = False + for exclude in exclude_files: + if re.search(exclude, file): + excluded = True + break + + if excluded: + continue + + # Build up paths + source_file = os.path.join(root, file) + destination_subdir = destination_directory + if preserve_paths: + destination_subdir = os.path.join(destination_directory, subdir) + + if not os.path.exists(destination_subdir): + os.makedirs(destination_subdir) + destination_file = os.path.join(destination_subdir, file) + + # Copy files + try: + shutil.copy(source_file, destination_file) + except: + print("Failed copying " + source_file + " to " + destination_file) + traceback.print_exc() + + return True + +def Archive(archive_name, path): + cwd = os.getcwd() + os.chdir(path + '/..') + file_name = archive_name + '.zip' + if os.path.exists(file_name): + os.unlink(file_name) + os.system('7z a ' + file_name + ' ' + path[path.rfind('/')+1:]) + os.chdir(cwd) + +def main(): + options = ProcessOptions(sys.argv[1:]) + + #CheckVSVars() + #Build('RmlCore', ['Debug', 'Release'], {'RMLUI_VERSION': '\\"' + options['RMLUI_VERSION'] + '\\"'}) + #Build('RmlControls', ['Debug', 'Release']) + #Build('RmlDebugger', ['Debug', 'Release']) + + DelTree('../Distribution/RmlUi') + CopyFiles('../Include', '../Distribution/RmlUi/Include') + CopyFiles('../Build', '../Distribution/RmlUi/Build', ['\.dll$', '^Rml.*\.lib$'], ['CMakeFiles']) + CopyFiles('../CMake', '../Distribution/RmlUi/CMake', ['\.cmake$', '\.in$', '\.plist$', '\.py$', '\.sh$']) + CopyFiles('../Samples', '../Distribution/RmlUi/Samples', ['\.h$', '\.cpp$', '\.rml$', '\.rcss$', '\.tga$', '\.py$', '\.otf$', '\.ttf$', '\.txt$']) + if options['FULL_SOURCE']: + CopyFiles('../Build', '../Distribution/RmlUi/Build', ['\.vcxproj$', '\.sln$', '\.vsprops$', '\.py$'], ['CMakeFiles']) + CopyFiles('../Source', '../Distribution/RmlUi/Source', ['\.cpp$', '\.h$', '\.inl$']) + if options['SAMPLE_BINARIES']: + CopyFiles('../Build', '../Distribution/RmlUi/Build', ['\.exe$'], ['CMakeFiles']) + shutil.copyfile('../LICENSE', '../Distribution/RmlUi/LICENSE') + shutil.copyfile('../readme.md', '../Distribution/RmlUi/readme.md') + if options['ARCHIVE']: + Archive(options['ARCHIVE_NAME'] + '-' + options['RMLUI_VERSION'], '../Distribution/RmlUi'); + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/thirdparty/RmlUi/CMake/gen_filelists.sh b/thirdparty/RmlUi/CMake/gen_filelists.sh new file mode 100644 index 000000000..d9eee6f1e --- /dev/null +++ b/thirdparty/RmlUi/CMake/gen_filelists.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +basedir=".." +file=CMake/FileList.cmake +src='set(lib_SRC_FILES' +hdr='set(lib_HDR_FILES' +masterpubhdr='set(MASTER_lib_PUB_HDR_FILES' +pubhdr='set(lib_PUB_HDR_FILES' +srcdir='${PROJECT_SOURCE_DIR}' +fontdefaultbegin='if(NOT NO_FONT_INTERFACE_DEFAULT)' +fontdefaultend='endif()' +srcpath=Source +hdrpath=Include/RmlUi +luapath=Lua +fontdefaultpath=FontEngineDefault + +printfiles() { + # Print headers + echo ${hdr/lib/$1} >>$file + find $srcpath/$1 -maxdepth 3 -path */$luapath -prune -o -path */$fontdefaultpath -prune -o \( -iname "*.h" -o -iname "*.hpp" \) -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ')\n' >>$file + # Print master header for library + echo ${masterpubhdr/lib/$1} >>$file + echo ' '$srcdir/Include/RmlUi/$1.h >>$file + echo -e ')\n' >>$file + # Print public headers sub directory + echo ${pubhdr/lib/$1} >>$file + if [[ "$1" == "Core" ]]; then echo ' '$srcdir/Include/RmlUi/Config/Config.h >>$file; fi + find $hdrpath/$1 -maxdepth 3 -path */$luapath -prune -o -path */$fontdefaultpath -prune -o \( -iname "*.h" -o -iname "*.inl" -o -iname "*.hpp" \) -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ')\n' >>$file + # Print source files + echo ${src/lib/$1} >>$file + find $srcpath/$1 -maxdepth 3 -path */$luapath -prune -o -path */$fontdefaultpath -prune -o -iname "*.cpp" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ')\n' >>$file +} + +printfontdefaultfiles() { + # Print headers + echo $fontdefaultbegin >>$file + echo ' '${hdr/lib/$1} >>$file + echo ' ${'$1'_HDR_FILES}' >>$file + find $srcpath/$1/$fontdefaultpath -iname "*.h" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ' )\n' >>$file + # Print source files + echo ' '${src/lib/$1} >>$file + echo ' ${'$1'_SRC_FILES}' >>$file + find $srcpath/$1/$fontdefaultpath -iname "*.cpp" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ' )' >>$file + echo -e $fontdefaultend'\n' >>$file +} + +printluafiles() { + # Print headers + echo ${hdr/lib/Lua} >>$file + find $srcpath/$luapath$1 -iname "*.h" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ')\n' >>$file + # Print public headers + echo ${pubhdr/lib/Lua} >>$file + find $hdrpath/$luapath$1 -iname "*.h" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file 2>/dev/null + echo -e ')\n' >>$file + # Print source files + echo ${src/lib/Lua} >>$file + find $srcpath/$luapath$1 -iname "*.cpp" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ')\n' >>$file +} + +pushd $basedir +echo -e "# This file was auto-generated with gen_filelists.sh\n" >$file +for lib in "Core" "Debugger"; do + printfiles $lib +done + +printfontdefaultfiles "Core" + +printluafiles + +popd diff --git a/thirdparty/RmlUi/CMake/gen_samplelists.sh b/thirdparty/RmlUi/CMake/gen_samplelists.sh new file mode 100755 index 000000000..51c56fe73 --- /dev/null +++ b/thirdparty/RmlUi/CMake/gen_samplelists.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +basedir=".." +file=CMake/SampleFileList.cmake +src='set(sample_SRC_FILES' +hdr='set(sample_HDR_FILES' +srcdir='${PROJECT_SOURCE_DIR}' +srcpath=Samples +samples=( 'shell' + 'basic/animation' 'basic/benchmark' 'basic/bitmapfont' 'basic/customlog' 'basic/databinding' 'basic/demo' 'basic/drag' 'basic/loaddocument' 'basic/treeview' 'basic/transform' + 'basic/sdl2' 'basic/sfml2' + 'tutorial/template' 'tutorial/datagrid' 'tutorial/datagrid_tree' 'tutorial/drag' + 'invaders' 'luainvaders' +) + +printfiles() { + # Print headers + name=${1//basic\//} #substitute basic/ for nothing + name=${name//tutorial\//tutorial_} #substitute 'tutorial/' for 'tutorial_' + echo ${hdr/sample/$name} >>$file + find $srcpath/$1/src -maxdepth 1 -iname "*.h" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + find $srcpath/$1/include -maxdepth 1 -iname "*.h" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file 2>/dev/null + echo -e ')\n' >>$file + # Print source files + echo ${src/sample/$name} >>$file + find $srcpath/$1/src -maxdepth 1 -iname "*.cpp" -exec echo ' '$srcdir/{} \; 2>/dev/null | sort -f >>$file + echo -e ')\n' >>$file +} + +pushd $basedir +echo -e "# This file was auto-generated with gen_samplelists.sh\n" >$file +for sample in ${samples[@]}; do + printfiles $sample +done + +echo '# Deal with platform specific sources for sample shell' >> $file +echo 'if(WIN32)' >> $file +echo ' list(APPEND shell_SRC_FILES' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellWin32.cpp' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/InputWin32.cpp' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/win32/ShellRenderInterfaceExtensionsOpenGL_Win32.cpp' >> $file +echo ' )' >> $file +echo ' list(APPEND shell_HDR_FILES' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/InputWin32.h' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/include/win32/IncludeWindows.h' >> $file +echo ' )' >> $file +echo 'elseif(APPLE)' >> $file +echo ' list(APPEND shell_SRC_FILES' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellMacOSX.cpp' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/InputMacOSX.cpp' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/macosx/ShellRenderInterfaceExtensionsOpenGL_MacOSX.cpp' >> $file +echo ' )' >> $file +echo ' list(APPEND shell_HDR_FILES' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/include/macosx/InputMacOSX.h' >> $file +echo ' )' >> $file +echo 'else()' >> $file +echo ' list(APPEND shell_SRC_FILES' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellX11.cpp' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/InputX11.cpp' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/src/x11/ShellRenderInterfaceExtensionsOpenGL_X11.cpp' >> $file +echo ' )' >> $file +echo ' list(APPEND shell_HDR_FILES' >> $file +echo ' ${PROJECT_SOURCE_DIR}/Samples/shell/include/x11/InputX11.h' >> $file +echo ' )' >> $file +echo 'endif()' >> $file + +popd + diff --git a/thirdparty/RmlUi/CMake/plist/RocketControlsOSX-Info.plist b/thirdparty/RmlUi/CMake/plist/RocketControlsOSX-Info.plist new file mode 100644 index 000000000..fa1bd23e9 --- /dev/null +++ b/thirdparty/RmlUi/CMake/plist/RocketControlsOSX-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/thirdparty/RmlUi/CMake/plist/RocketCoreOSX-Info.plist b/thirdparty/RmlUi/CMake/plist/RocketCoreOSX-Info.plist new file mode 100644 index 000000000..fa1bd23e9 --- /dev/null +++ b/thirdparty/RmlUi/CMake/plist/RocketCoreOSX-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/thirdparty/RmlUi/CMake/plist/RocketDebuggerOSX-Info.plist b/thirdparty/RmlUi/CMake/plist/RocketDebuggerOSX-Info.plist new file mode 100644 index 000000000..fa1bd23e9 --- /dev/null +++ b/thirdparty/RmlUi/CMake/plist/RocketDebuggerOSX-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.yourcompany.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/thirdparty/RmlUi/CMakeLists.txt b/thirdparty/RmlUi/CMakeLists.txt new file mode 100644 index 000000000..5c2fed3e0 --- /dev/null +++ b/thirdparty/RmlUi/CMakeLists.txt @@ -0,0 +1,787 @@ +#=================================== +# Build script for RmlUi =========== +#=================================== + +cmake_minimum_required(VERSION 3.0) + +#Downgrade ABI for kisakstrike +if(UNIX AND NOT APPLE) + message(STATUS "Downgrading CXX11 ABI for kisakstrike!") + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) +endif() +# +if(APPLE) + # This has to be before most other options so CMake properly handles the + # compiler variables, it MUST bebefore the project() definition + if(IOS_PLATFORM) + set(CMAKE_TOOLCHAIN_FILE CMake/Platform/iOS.cmake) + endif(IOS_PLATFORM) + + option(BUILD_UNIVERSAL_BINARIES "Build universal binaries for all architectures supported" ON) + if (NOT CMAKE_OSX_ARCHITECTURES AND BUILD_UNIVERSAL_BINARIES) + if(IOS) + # set the architecture for iOS + if (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_ARCH armv6 armv7 armv7s arm64) + set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS") + else (${IOS_PLATFORM} STREQUAL "OS") + set (IOS_ARCH x86_64) + set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE STRING "Build architecture for iOS Simulator") + endif (${IOS_PLATFORM} STREQUAL "OS") + + else(IOS) + # set the architectures for OS X + set (OSXI_ARCH x86_64) + set (CMAKE_OSX_ARCHITECTURES ${OSXI_ARCH} CACHE STRING "Build architecture for OS X universal binaries") + endif(IOS) + endif (NOT CMAKE_OSX_ARCHITECTURES AND BUILD_UNIVERSAL_BINARIES) +endif(APPLE) + +if(COMMAND cmake_policy) + cmake_policy(SET CMP0015 NEW) +endif(COMMAND cmake_policy) + +# Enable the use of MACOSX_RPATH by default for CMake v3.0+; this effectively +# allows plug 'n' play functionality, so to speak -- the resulting shared +# library files can simply be copied over into the end-user's application +# bundle or framework bundle. No mucking around with install_name_tool. +# +# See also: +# cmake --help-policy cmp0042 +# http://www.kitware.com/blog/home/post/510 +if(POLICY CMP0042) + cmake_policy(SET CMP0042 NEW) +endif(POLICY CMP0042) +if (POLICY CMP0072) + cmake_policy (SET CMP0072 NEW) +endif(POLICY CMP0072) +if(POLICY CMP0074) + cmake_policy(SET CMP0074 NEW) +endif(POLICY CMP0074) + +project(RmlUi LANGUAGES C CXX VERSION 4.0) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(RMLUI_VERSION_RELEASE false) + +if(RMLUI_VERSION_RELEASE) + set(RMLUI_VERSION_SUFFIX "") +else() + set(RMLUI_VERSION_SUFFIX "-dev") +endif() + +set(RMLUI_VERSION_SHORT ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${RMLUI_VERSION_SUFFIX}) + +# paths +include(GNUInstallDirs) + +# Search in the 'cmake' directory for additional CMake modules. +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake;${PROJECT_SOURCE_DIR}/CMake/Modules) + +#=================================== +# Environment tests ================ +#=================================== + +include(TestForANSIForScope) +include(TestForANSIStreamHeaders) +include(TestForSTDNamespace) + +#=================================== +# Provide hints as to where depends= +# might be found = +#=================================== + +if(NOT DEFINED ENV{FREETYPE_DIR}) + set(ENV{FREETYPE_DIR} "${PROJECT_SOURCE_DIR}/Dependencies") +endif() + +if(NOT DEFINED ENV{LUA_DIR}) + set(ENV{LUA_DIR} "${PROJECT_SOURCE_DIR}/Dependencies") +endif() + +if(NOT DEFINED ENV{SDL2DIR}) + set(ENV{SDL2DIR} "${PROJECT_SOURCE_DIR}/Dependencies") +endif() + +if(NOT DEFINED ENV{SDL2_IMAGE_DIR}) + set(ENV{SDL2_IMAGE_DIR} "${PROJECT_SOURCE_DIR}/Dependencies") +endif() + +if(NOT DEFINED ENV{SFML_ROOT}) + set(ENV{SFML_ROOT} "${PROJECT_SOURCE_DIR}/Dependencies") +endif() + +if(NOT DEFINED ENV{TRACY_DIR}) + set(ENV{TRACY_DIR} "${PROJECT_SOURCE_DIR}/Dependencies") +endif() + +#=================================== +# Plaform specific global hacks ==== +#=================================== + +if(APPLE) + # Disables naked builtins from AssertMacros.h which + # This prevents naming collisions such as those from the check() + # function macro with LuaType::check + add_definitions(-D__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES=0) +endif(APPLE) + +#=================================== +# Build options ==================== +#=================================== + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING + "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." + FORCE) +endif() + +if(NOT IOS) + option(BUILD_SHARED_LIBS "Build shared (dynamic) libraries" ON) +endif(NOT IOS) + +option(BUILD_LUA_BINDINGS "Build Lua bindings" OFF) + +if(APPLE) + option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF) +endif() + +option(BUILD_SAMPLES "Build samples" OFF) + +option(MATRIX_ROW_MAJOR "Use row-major matrices. Column-major matrices are used by default." OFF) + +if(APPLE) + if(IOS) + if(BUILD_SHARED_LIBS) + message(FATAL_ERROR "BUILD_SHARED_LIBS must be OFF for iOS builds. iOS does not support shared libraries.") + endif(BUILD_SHARED_LIBS) + endif(IOS) + + if(BUILD_FRAMEWORK) + if(NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode") + message(FATAL_ERROR "You should use Xcode generator with BUILD_FRAMEWORK enabled") + endif() + if(NOT BUILD_SHARED_LIBS) + message(FATAL_ERROR "BUILD_SHARED_LIBS must be ON with BUILD_FRAMEWORK enabled") + endif() + endif() +else(APPLE) + if(BUILD_FRAMEWORK) + message(FATAL_ERROR "BUILD_FRAMEWORK is only supported on Mac OS X with the Xcode generator") + endif() +endif(APPLE) + +option(NO_FONT_INTERFACE_DEFAULT "Do not include the default font engine in the build. Allows building without the FreeType dependency, but a custom font engine must be created and set." OFF) +if(NO_FONT_INTERFACE_DEFAULT) + add_definitions(-DRMLUI_NO_FONT_INTERFACE_DEFAULT) +endif() + +if(NOT BUILD_SHARED_LIBS) + add_definitions(-DRMLUI_STATIC_LIB) + message("-- Building static libraries. Make sure to #define RMLUI_STATIC_LIB before including RmlUi in your project.") +endif() + +option(NO_THIRDPARTY_CONTAINERS "Only use standard library containers." OFF) +if( NO_THIRDPARTY_CONTAINERS ) + add_definitions(-DRMLUI_NO_THIRDPARTY_CONTAINERS) + message("-- No third-party containers will be used: Make sure to #define RMLUI_NO_THIRDPARTY_CONTAINERS before including RmlUi in your project.") +endif() + +option(CUSTOM_CONFIGURATION "Customize RmlUi configuration files for overriding the default configuration and types." OFF) + +set(CUSTOM_CONFIGURATION_FILE "" CACHE STRING "Custom configuration file to be included in place of .") +if( CUSTOM_CONFIGURATION AND CUSTOM_CONFIGURATION_FILE ) + add_definitions(-DRMLUI_CUSTOM_CONFIGURATION_FILE="${CUSTOM_CONFIGURATION_FILE}") + message("-- Including ${CUSTOM_CONFIGURATION_FILE} instead of ") +endif () + +set(CUSTOM_INCLUDE_DIRS "" CACHE STRING "Extra include directories (use with CUSTOM_CONFIGURATION_FILE).") +if( CUSTOM_CONFIGURATION AND CUSTOM_INCLUDE_DIRS ) + include_directories(${CUSTOM_INCLUDE_DIRS}) +endif () + +set(CUSTOM_LINK_LIBRARIES "" CACHE STRING "Extra link libraries (use with CUSTOM_CONFIGURATION_FILE).") + +if( CUSTOM_CONFIGURATION ) + mark_as_advanced( CLEAR CUSTOM_CONFIGURATION_FILE CUSTOM_INCLUDE_DIRS CUSTOM_LINK_LIBRARIES ) +else() + mark_as_advanced( FORCE CUSTOM_CONFIGURATION_FILE CUSTOM_INCLUDE_DIRS CUSTOM_LINK_LIBRARIES ) + + if( CUSTOM_CONFIGURATION_FILE OR CUSTOM_INCLUDE_DIRS OR CUSTOM_LINK_LIBRARIES ) + message("-- CUSTOM_CONFIGURATION disabled, but custom configuration variables are set. They will have no effect.") + endif() +endif() + +option(ENABLE_TRACY_PROFILING "Enable profiling with Tracy. Source files can be placed in Dependencies/tracy." OFF) +if( ENABLE_TRACY_PROFILING ) + find_package(Tracy REQUIRED) + + include_directories(${TRACY_INCLUDE_DIR}) + + if( CMAKE_CONFIGURATION_TYPES ) + list(APPEND CMAKE_CONFIGURATION_TYPES Tracy) + list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING + "Add the configurations that we need" + FORCE) + set(CMAKE_C_FLAGS_TRACY "${CMAKE_CXX_FLAGS_RELEASE} -DRMLUI_ENABLE_PROFILING") + set(CMAKE_CXX_FLAGS_TRACY "${CMAKE_CXX_FLAGS_RELEASE} -DRMLUI_ENABLE_PROFILING") + set(CMAKE_EXE_LINKER_FLAGS_TRACY "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") + set(CMAKE_SHARED_LINKER_FLAGS_TRACY "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") + message("-- Tracy profiling enabled in configuration 'Tracy'.") + else() + message("-- Tracy profiling enabled.") + add_definitions(-DRMLUI_ENABLE_PROFILING) + endif() +elseif( CMAKE_CONFIGURATION_TYPES ) + list(REMOVE_ITEM CMAKE_CONFIGURATION_TYPES Tracy) +endif() + +option(DISABLE_RTTI_AND_EXCEPTIONS "Build with rtti and exceptions disabled." OFF) +if(DISABLE_RTTI_AND_EXCEPTIONS) + add_definitions(-DRMLUI_USE_CUSTOM_RTTI) + message("-- C++ RTTI and exceptions will be disabled: Make sure to #define RMLUI_USE_CUSTOM_RTTI before including RmlUi in your project.") +endif() + +option(ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" ON) +set(PRECOMPILED_HEADERS_ENABLED OFF) +if (ENABLE_PRECOMPILED_HEADERS AND (CMAKE_VERSION VERSION_LESS 3.16.0)) + message("-- Could not enable precompiled headers. Need CMake version 3.16.0 or greater.") +elseif (ENABLE_PRECOMPILED_HEADERS) + set(PRECOMPILED_HEADERS_ENABLED ON) +endif() + +#=================================== +# Find dependencies ================ +#=================================== + +# FreeType +if(NOT NO_FONT_INTERFACE_DEFAULT) + find_package(Freetype REQUIRED) + + if(FREETYPE_FOUND) + include_directories(${FREETYPE_INCLUDE_DIRS}) + link_directories(${FREETYPE_LINK_DIRS}) + list(APPEND CORE_LINK_LIBS ${FREETYPE_LIBRARY}) + endif() +endif() + +#Lua +if(BUILD_LUA_BINDINGS) + find_package(Lua REQUIRED) + if(LUA_FOUND) + include_directories(${LUA_INCLUDE_DIR}) + list(APPEND LUA_BINDINGS_LINK_LIBS ${LUA_LIBRARIES}) + endif() +endif() + + +#=================================== +# Setup paths ====================== +#=================================== + +include_directories( + ${PROJECT_SOURCE_DIR}/Include +) + +# Include list of source files +include(FileList) + +if(NOT BUILD_FRAMEWORK) +#=================================== +# Build libraries ================== +#=================================== + +set(LIBRARIES Core Debugger) + +foreach(library ${LIBRARIES}) + set(NAME Rml${library}) + + add_library(${NAME} + ${${library}_HDR_FILES} + ${${library}_PUB_HDR_FILES} + ${MASTER_${library}_PUB_HDR_FILES} + ${${library}_SRC_FILES} + ) + + set_target_properties(${NAME} PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) + + if (MSVC) + target_compile_options(${NAME} PUBLIC "/MP") + endif(MSVC) + + if( MATRIX_ROW_MAJOR ) + target_compile_definitions(${NAME} -DRMLUI_MATRIX_ROW_MAJOR=1) + endif () + + if( CUSTOM_CONFIGURATION AND CUSTOM_LINK_LIBRARIES ) + target_link_libraries(${NAME} ${CUSTOM_LINK_LIBRARIES}) + endif () + + install(TARGETS ${NAME} + EXPORT RmlUiTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + + set(RMLUI_EXPORTED_TARGETS ${RMLUI_EXPORTED_TARGETS} ${NAME}) +endforeach(library) + +if( CUSTOM_CONFIGURATION ) + foreach(library ${CUSTOM_LINK_LIBRARIES}) + install(TARGETS ${library} + EXPORT RmlUiTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + set(RMLUI_EXPORTED_TARGETS ${RMLUI_EXPORTED_TARGETS} ${library}) + endforeach(library ${CUSTOM_LINK_LIBRARIES}) +endif() + +target_compile_definitions(RmlCore PRIVATE RMLUI_VERSION="${RMLUI_VERSION_SHORT}") + +if (PRECOMPILED_HEADERS_ENABLED) + target_precompile_headers(RmlCore PRIVATE ${PROJECT_SOURCE_DIR}/Source/Core/precompiled.h) +endif() + + +else(NOT BUILD_FRAMEWORK) + #=================================== + # Build combined Framework ========= + #=================================== + + set(NAME RmlUi) + + set(MASTER_PUB_HDR_FILES + ${MASTER_Core_PUB_HDR_FILES} + ${MASTER_Debugger_PUB_HDR_FILES} + ) + + add_library(${NAME} + ${Core_HDR_FILES} + ${MASTER_Core_PUB_HDR_FILES} + ${Core_PUB_HDR_FILES} + ${Core_SRC_FILES} + ${Debugger_HDR_FILES} + ${MASTER_Debugger_PUB_HDR_FILES} + ${Debugger_PUB_HDR_FILES} + ${Debugger_SRC_FILES} + ) + + set_target_properties(${NAME} PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) + + set_property(SOURCE ${MASTER_PUB_HDR_FILES} + PROPERTY MACOSX_PACKAGE_LOCATION Headers + ) + set_property(SOURCE ${Core_PUB_HDR_FILES} + PROPERTY MACOSX_PACKAGE_LOCATION Headers/Core + ) + set_property(SOURCE ${Debugger_PUB_HDR_FILES} + PROPERTY MACOSX_PACKAGE_LOCATION Headers/Debugger + ) + set_target_properties(${NAME} PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER com.rmlui.${NAME} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${RMLUI_VERSION_SHORT} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" + PUBLIC_HEADER ${MASTER_PUB_HDR_FILES} + ) + + install(TARGETS ${NAME} + EXPORT RmlUiTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + FRAMEWORK DESTINATION Library/Frameworks + ) + + set(RMLUI_EXPORTED_TARGETS ${RMLUI_EXPORTED_TARGETS} ${NAME}) +endif(NOT BUILD_FRAMEWORK) + +# Build Lua bindings +if(BUILD_LUA_BINDINGS) + set(NAME RmlLua) + + add_library(${NAME} ${Lua_SRC_FILES} + ${Lua_HDR_FILES} + ${Lua_PUB_HDR_FILES} + ) + + set_target_properties(${NAME} PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + ) + + install(TARGETS ${NAME} + EXPORT RmlUiTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + + set(RMLUI_EXPORTED_TARGETS ${RMLUI_EXPORTED_TARGETS} ${NAME}) +endif() + + +if(DISABLE_RTTI_AND_EXCEPTIONS) + if( CMAKE_COMPILER_IS_GNUCXX ) + add_definitions( -fno-rtti -fno-exceptions ) + elseif( MSVC ) + add_definitions( -D_HAS_EXCEPTIONS=0 /GR- ) + if(CMAKE_CXX_FLAGS MATCHES "/EHsc ") + string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + message(STATUS "CMAKE_CXX_FLAGS matches /EHsc before end of string replaced...") + endif() + + if(CMAKE_CXX_FLAGS MATCHES "/EHsc$") + string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + message(STATUS "CMAKE_CXX_FLAGS matches /EHsc at end of string replaced...") + endif() + else() + message(STATUS "Could not create build configuration without rtti and exceptions...") + endif() +endif() + + +#=================================== +# Link libraries =================== +#=================================== + +if(NOT BUILD_FRAMEWORK) +target_link_libraries(RmlCore ${CORE_LINK_LIBS}) +target_link_libraries(RmlDebugger RmlCore) +else(NOT BUILD_FRAMEWORK) +target_link_libraries(RmlUi ${CORE_LINK_LIBS}) +endif(NOT BUILD_FRAMEWORK) + +if(BUILD_LUA_BINDINGS) + if(NOT BUILD_FRAMEWORK) + target_link_libraries(RmlLua RmlCore ${LUA_BINDINGS_LINK_LIBS}) + else(NOT BUILD_FRAMEWORK) + target_link_libraries(RmlLua RmlUi ${LUA_BINDINGS_LINK_LIBS}) + endif(NOT BUILD_FRAMEWORK) +endif() + + +#=================================== +# Build samples ==================== +#=================================== + +# Build and link the samples +macro(bl_sample NAME) + if (WIN32) + add_executable(${NAME} WIN32 ${${NAME}_SRC_FILES} ${${NAME}_HDR_FILES} ) + elseif(APPLE) + add_executable(${NAME} MACOSX_BUNDLE ${${NAME}_SRC_FILES} ${${NAME}_HDR_FILES} ) + + # The first rpath is to the proper location where the framework/library SHOULD be, the second is to the location actually seen + # in the build environment + if(BUILD_FRAMEWORK) + set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-rpath @executable_path/../Frameworks") + else() + set_target_properties(${NAME} PROPERTIES LINK_FLAGS "-rpath @executable_path/../lib") + endif() + else() + add_executable(${NAME} ${${NAME}_SRC_FILES} ${${NAME}_HDR_FILES} ) + endif() + + target_link_libraries(${NAME} ${ARGN}) +endmacro() + +if(BUILD_SAMPLES) + include(SampleFileList) + + set(samples treeview customlog drag loaddocument transform bitmapfont animation benchmark demo databinding) + set(tutorials template datagrid datagrid_tree drag) + +if(NOT BUILD_FRAMEWORK) + set(sample_LIBRARIES + shell + RmlCore + RmlDebugger + ) +else(NOT BUILD_FRAMEWORK) + set(sample_LIBRARIES + shell + RmlUi + ) +endif(NOT BUILD_FRAMEWORK) + + # Find OpenGL + find_package(OpenGL REQUIRED) + + if(OPENGL_FOUND) + include_directories(${OPENGL_INCLUDE_DIR}) + list(APPEND sample_LIBRARIES ${OPENGL_LIBRARIES}) + endif() + + # Set up required system libraries + if(APPLE) + include(FindCarbon) + find_package(Carbon REQUIRED) + + if (Carbon_FOUND) + include_directories(${Carbon_INCLUDE_DIR}) + list(APPEND sample_LIBRARIES ${Carbon_LIBRARIES}) + endif() + else() + find_package(X11 REQUIRED) + if (X11_FOUND) + list(APPEND sample_LIBRARIES ${X11_LIBRARIES}) + # shell/src/x11/InputX11.cpp:InitialiseX11Keymap uses Xkb if + # possible instead of XGetKeyboardMapping for performance + if(X11_Xkb_FOUND) + FIND_PACKAGE_MESSAGE(X11 "Found X11 KBlib: ${X11_X11_LIB}" "[${X11_X11_LIB}][${X11_XkbINCLUDE_DIR}]") + add_definitions(-DHAS_X11XKBLIB) + endif() + endif() + endif() + + set(SAMPLES_DIR opt/RmlUi/Samples CACHE PATH "path to samples dir") + + if(WIN32) + mark_as_advanced(SAMPLES_DIR) + endif() + + # The samples and tutorials use the shell library + include_directories(${PROJECT_SOURCE_DIR}/Samples/shell/include) + + # Build and install sample shell library + add_library(shell STATIC ${shell_SRC_FILES} ${shell_HDR_FILES}) + + if (PRECOMPILED_HEADERS_ENABLED) + target_precompile_headers(shell PRIVATE ${PROJECT_SOURCE_DIR}/Samples/shell/src/precompiled.h) + endif() + + if (WIN32) + target_link_libraries(shell PUBLIC shlwapi) + endif() + + if( CUSTOM_CONFIGURATION AND CUSTOM_LINK_LIBRARIES ) + target_link_libraries(shell PUBLIC ${CUSTOM_LINK_LIBRARIES}) + endif () + + # Build and install the basic samples + foreach(sample ${samples}) + bl_sample(${sample} ${sample_LIBRARIES}) + + # The samples always set this as their current working directory + install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/${sample}) + install(TARGETS ${sample} + RUNTIME DESTINATION ${SAMPLES_DIR}/${sample} + BUNDLE DESTINATION ${SAMPLES_DIR}) + endforeach() + + message("-- Can SDL2 sample be built") + find_package(SDL2) + if(SDL2_FOUND) + find_package(SDL2_image) + if(SDL2_IMAGE_FOUND) + find_package(GLEW) + if(GLEW_FOUND) + message("-- Can SDL2 sample be built - yes") + include_directories(${SDL2_INCLUDE_DIR} ${SDL2_IMAGE_INCLUDE_DIR} ${GLEW_INCLUDE_DIR}) + + bl_sample(sdl2 ${sample_LIBRARIES} ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARY} ${GLEW_LIBRARIES}) + + # The samples always set this as their current working directory + install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sdl2) + install(TARGETS sdl2 + RUNTIME DESTINATION ${SAMPLES_DIR}/sdl2 + BUNDLE DESTINATION ${SAMPLES_DIR}) + else() + message("-- Can SDL2 sample be built - GLEW not found") + endif() + else() + message("-- Can SDL2 sample be built - SDL2_image not found") + endif() + else() + message("-- Can SDL2 sample be built - SDL2 not found") + endif() + + + message("-- Can SFML 2.x sample be built") + if (WIN32) + find_package(SFML 2 COMPONENTS graphics window system main) + else() + find_package(SFML 2 COMPONENTS graphics window system) + endif() + if(NOT SFML_FOUND) + message("-- Can SFML 2.x sample be built - no") + else() + find_package(GLEW) + if(GLEW_FOUND) + message("-- Can SFML 2.x sample be built - yes: with GLEW") + include_directories(${SFML_INCLUDE_DIR} ${GLEW_INCLUDE_DIR}) + add_definitions( -DENABLE_GLEW ) + bl_sample(sfml2 ${sample_LIBRARIES} ${SFML_LIBRARIES} ${GLEW_LIBRARIES}) + else() + message("-- Can SFML 2.x sample be built - yes: without GLEW") + include_directories(${SFML_INCLUDE_DIR}) + bl_sample(sfml2 ${sample_LIBRARIES} ${SFML_LIBRARIES}) + endif() + + # The samples always set this as their current working directory + install(DIRECTORY DESTINATION ${SAMPLES_DIR}/basic/sfml2) + install(TARGETS sfml2 + RUNTIME DESTINATION ${SAMPLES_DIR}/sfml2 + BUNDLE DESTINATION ${SAMPLES_DIR}) + endif() + + # Build and install the tutorials + foreach(tutorial ${tutorials}) + set(tutorial_fullname tutorial_${tutorial}) + bl_sample(${tutorial_fullname} ${sample_LIBRARIES}) + + # The tutorials always set this as their current working directory + install(DIRECTORY DESTINATION ${SAMPLES_DIR}/tutorial/${tutorial}) + install(TARGETS ${tutorial_fullname} + RUNTIME DESTINATION ${SAMPLES_DIR}/${tutorial} + BUNDLE DESTINATION ${SAMPLES_DIR}) + endforeach() + + # Build and install invaders sample + bl_sample(invaders ${sample_LIBRARIES}) + install(DIRECTORY DESTINATION ${SAMPLES_DIR}/invaders) + install(TARGETS invaders + RUNTIME DESTINATION ${SAMPLES_DIR}/invaders + BUNDLE DESTINATION ${SAMPLES_DIR}) + + if(BUILD_LUA_BINDINGS) + bl_sample(luainvaders RmlLua ${sample_LIBRARIES} ${LUA_BINDINGS_LINK_LIBS}) + install(DIRECTORY DESTINATION ${SAMPLES_DIR}/luainvaders) + install(TARGETS luainvaders + RUNTIME DESTINATION ${SAMPLES_DIR}/luainvaders + BUNDLE DESTINATION ${SAMPLES_DIR}) + endif() +endif() + + +#=================================== +# Installation ===================== +#=================================== + +if(BUILD_LUA_BINDINGS) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Include/RmlUi + DESTINATION include + ) +else() + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Include/RmlUi + DESTINATION include + PATTERN "Lua" EXCLUDE + ) +endif() + +if(BUILD_SAMPLES) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/assets + DESTINATION ${SAMPLES_DIR} + ) + + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/tutorial/template/data + DESTINATION ${SAMPLES_DIR}/tutorial/template + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid/data + DESTINATION ${SAMPLES_DIR}/tutorial/datagrid + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/tutorial/datagrid_tree/data + DESTINATION ${SAMPLES_DIR}/tutorial/datagrid_tree + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/tutorial/drag/data + DESTINATION ${SAMPLES_DIR}/tutorial/drag + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/animation/data + DESTINATION ${SAMPLES_DIR}/basic/animation + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/benchmark/data + DESTINATION ${SAMPLES_DIR}/basic/benchmark + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/bitmapfont/data + DESTINATION ${SAMPLES_DIR}/basic/bitmapfont + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/databinding/data + DESTINATION ${SAMPLES_DIR}/basic/databinding + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/demo/data + DESTINATION ${SAMPLES_DIR}/basic/demo + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/transform/data + DESTINATION ${SAMPLES_DIR}/basic/transform + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/treeview/data + DESTINATION ${SAMPLES_DIR}/basic/treeview + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/basic/drag/data + DESTINATION ${SAMPLES_DIR}/basic/drag + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/invaders/data + DESTINATION ${SAMPLES_DIR}/invaders + ) + + if(BUILD_LUA_BINDINGS) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/luainvaders/data + DESTINATION ${SAMPLES_DIR}/luainvaders + ) + install(DIRECTORY ${PROJECT_SOURCE_DIR}/Samples/luainvaders/lua + DESTINATION ${SAMPLES_DIR}/luainvaders + ) + endif() +endif() + +#=================================== +# Generate Config.cmake files ====== +#=================================== + +# Try to include helper module +include(CMakePackageConfigHelpers OPTIONAL RESULT_VARIABLE PkgHelpers_AVAILABLE) + +# guard against older versions of cmake which do not provide it +if(PkgHelpers_AVAILABLE) + set (INCLUDE_INSTALL_DIR "include") + set (LIB_INSTALL_DIR "lib") + set (INCLUDE_DIR "${PROJECT_SOURCE_DIR}/Include") + + # generate configuration for install tree + configure_package_config_file(${PROJECT_SOURCE_DIR}/CMake/RmlUiConfig.cmake.install.in + ${CMAKE_CURRENT_BINARY_DIR}/install/RmlUiConfig.cmake + INSTALL_DESTINATION ${LIB_INSTALL_DIR}/RmlUi/cmake + PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR) + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/install/RmlUiConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion ) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/install/RmlUiConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/install/RmlUiConfigVersion.cmake + DESTINATION ${LIB_INSTALL_DIR}/RmlUi/cmake ) + install(EXPORT RmlUiTargets + DESTINATION ${LIB_INSTALL_DIR}/RmlUi/cmake) + + # generate configuration for build tree + configure_package_config_file(${PROJECT_SOURCE_DIR}/CMake/RmlUiConfig.cmake.build.in + ${CMAKE_CURRENT_BINARY_DIR}/RmlUiConfig.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + PATH_VARS INCLUDE_DIR CMAKE_CURRENT_BINARY_DIR) + export(TARGETS ${RMLUI_EXPORTED_TARGETS} + FILE "${CMAKE_CURRENT_BINARY_DIR}/RmlUiTargets.cmake") + write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/RmlUiConfigVersion.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion ) + set(RmlUi_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE PATH "The directory containing a CMake configuration file for RmlUi.") +else() + message("If you wish to use find_package(RmlUi) in your own project to find RmlUi library" + " please update cmake to version which provides CMakePackageConfighelpers module" + " or write generators for RmlUiConfig.cmake by yourself.") +endif() diff --git a/thirdparty/RmlUi/Dependencies/.gitignore b/thirdparty/RmlUi/Dependencies/.gitignore new file mode 100644 index 000000000..f316fb30f --- /dev/null +++ b/thirdparty/RmlUi/Dependencies/.gitignore @@ -0,0 +1,4 @@ +include/ +lib/ +tracy/ +*/ diff --git a/thirdparty/RmlUi/Dependencies/empty.txt b/thirdparty/RmlUi/Dependencies/empty.txt new file mode 100644 index 000000000..e69de29bb diff --git a/thirdparty/RmlUi/Dependencies/osx-depends.sh b/thirdparty/RmlUi/Dependencies/osx-depends.sh new file mode 100755 index 000000000..62a7b7620 --- /dev/null +++ b/thirdparty/RmlUi/Dependencies/osx-depends.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env sh + +BUILD_FREETYPE2=YES +BUILD_LUA=YES +BUILD_PLATFORM=osx + + +#Get depends root directory + +pushd `dirname $0` > /dev/null +SCRIPT_PATH=`pwd` +popd > /dev/null + +DEPS_DIR=${SCRIPT_PATH} + +BUILD_OUTPUTDIR=${DEPS_DIR}/${BUILD_PLATFORM} + +if [ ! -d "${BUILD_OUTPUTDIR}" ]; then + mkdir "${BUILD_OUTPUTDIR}" +fi +if [ ! -d "${BUILD_OUTPUTDIR}/lib" ]; then + mkdir "${BUILD_OUTPUTDIR}/lib" +fi +if [ ! -d "${BUILD_OUTPUTDIR}/include" ]; then + mkdir "${BUILD_OUTPUTDIR}/include" +fi + +create_ios_outdir_lipo() +{ + for lib_i386 in `find $LOCAL_OUTDIR/i386 -name "lib*.a"`; do + lib_arm7=`echo $lib_i386 | sed "s/i386/arm7/g"` + lib_arm7s=`echo $lib_i386 | sed "s/i386/arm7s/g"` + lib=`echo $lib_i386 | sed "s/i386//g"` + xcrun -sdk iphoneos lipo -arch armv7s $lib_arm7s -arch armv7 $lib_arm7 -create -output $lib + done +} + +build_freetype() +{ + + cd "${DEPS_DIR}" + if [ ! -d "freetype2" ]; then + git clone --recursive git://git.sv.nongnu.org/freetype/freetype2.git freetype2 + fi + + cd freetype2 + + cmake CMakeLists.txt -DBUILD_SHARED_LIBS:BOOL=false + make + + cmake CMakeLists.txt -DBUILD_SHARED_LIBS:BOOL=true + make + + if [ ! -d "${BUILD_OUTPUTDIR}/include/freetype2" ]; then + mkdir "${BUILD_OUTPUTDIR}/include/freetype2" + fi + cp -Rp include/* "${BUILD_OUTPUTDIR}/include/freetype2/" + cp libfreetype.a "${BUILD_OUTPUTDIR}/lib/" + cp libfreetype.dylib "${BUILD_OUTPUTDIR}/lib/" + + cd "${DEPS_DIR}" +} + + +build_freetype diff --git a/thirdparty/RmlUi/Include/RmlUi/Config/Config.h b/thirdparty/RmlUi/Include/RmlUi/Config/Config.h new file mode 100644 index 000000000..522da4bc2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Config/Config.h @@ -0,0 +1,203 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CONFIG_CONFIG_H +#define RMLUI_CONFIG_CONFIG_H + +/* + * This file provides the means to configure various types used across RmlUi. It is possible to override container + * types with your own, provided they are compatible with STL, or customize STL containers, for example by setting + * custom allocators. This file may be edited directly, or can be copied to an alternate location, modified, and + * included by setting the CMake option CUSTOM_CONFIGURATION_FILE (RMLUI_CUSTOM_CONFIGURATION_FILE preprocessor + * define) to the path of that file. + */ + +#ifdef RMLUI_CUSTOM_CONFIGURATION_FILE +#include RMLUI_CUSTOM_CONFIGURATION_FILE +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef RMLUI_NO_THIRDPARTY_CONTAINERS +#include +#include +#else +#include "../Core/Containers/chobo/flat_map.hpp" +#include "../Core/Containers/chobo/flat_set.hpp" +#include "../Core/Containers/robin_hood.h" +#endif // RMLUI_NO_THIRDPARTY_CONTAINERS + +namespace Rml { + +// Default matrix type to be used. This alias may be set to ColumnMajorMatrix4f or RowMajorMatrix4f. This alias can not +// be set here because matrix types are defined after this include in Core/Types.h. +#ifdef RMLUI_MATRIX_ROW_MAJOR +#define RMLUI_MATRIX4_TYPE RowMajorMatrix4f +#else +#define RMLUI_MATRIX4_TYPE ColumnMajorMatrix4f +#endif + +// A way to disable 'final' specified for Rml::Releaser class. It breaks EASTL. +#define RMLUI_RELEASER_FINAL final + +// Containers types. +template +using Vector = std::vector; +template +using Array = std::array; +template +using Stack = std::stack; +template +using List = std::list; +template +using Queue = std::queue; +template +using Pair = std::pair; +template +using UnorderedMultimap = std::unordered_multimap< Key, Value >; +#ifdef RMLUI_NO_THIRDPARTY_CONTAINERS +template +using UnorderedMap = std::unordered_map< Key, Value >; +template +using SmallUnorderedMap = UnorderedMap< Key, Value >; +template +using UnorderedSet = std::unordered_set< T >; +template +using SmallUnorderedSet = std::unordered_set< T >; +template +using SmallOrderedSet = std::set< T >; +#else +template < typename Key, typename Value> +using UnorderedMap = robin_hood::unordered_flat_map< Key, Value >; +template +using SmallUnorderedMap = chobo::flat_map< Key, Value >; +template +using UnorderedSet = robin_hood::unordered_flat_set< T >; +template +using SmallUnorderedSet = chobo::flat_set< T >; +template +using SmallOrderedSet = chobo::flat_set< T >; +#endif // RMLUI_NO_THIRDPARTY_CONTAINERS +template +inline std::move_iterator MakeMoveIterator(Iterator it) { return std::make_move_iterator(it); } + +// Utilities. +template +using Hash = std::hash; +template +using Function = std::function; + +// Strings. +using String = std::string; +using StringList = Vector< String >; +using U16String = std::u16string; + +// Smart pointer types. +template +using UniquePtr = std::unique_ptr; +template +class Releaser; +template +using UniqueReleaserPtr = std::unique_ptr>; +template +using SharedPtr = std::shared_ptr; +template +using WeakPtr = std::weak_ptr; +template +inline SharedPtr MakeShared(Args... args) { return std::make_shared(std::forward(args)...); } +template +inline UniquePtr MakeUnique(Args... args) { return std::make_unique(std::forward(args)...); } + +} + + +/*** +// The following defines should be used for inserting custom type cast operators for conversion of RmlUi types +// to user types. RmlUi uses template math types, therefore conversion operators to non-templated types +// should be done using SFINAE as in example below. + +// Extra code to be inserted into RmlUi::Color<> class body. Note: be mindful of colorspaces used by different +// color types. RmlUi assumes that float colors are interpreted in linear colorspace while byte colors are +// interpreted as sRGB. + +#define RMLUI_COLOUR_USER_EXTRA \ + template>* = nullptr> \ + operator MyColor() const { return MyColor( \ + (float)red / 255.0f, (float)green / 255.0f, (float)blue / 255.0f, (float)alpha / 255.0f); } \ + template>* = nullptr> \ + operator MyColor() const { return MyColor(red, green, blue, alpha); } \ + +// Extra code to be inserted into RmlUi::Vector2<> class body. +#define RMLUI_VECTOR2_USER_EXTRA \ + template>* = nullptr> \ + operator typename MyIntVector2() const { return MyIntVector2(x, y); } \ + template>* = nullptr> \ + operator MyVector2() const { return MyVector2(x, y); } \ + template>* = nullptr> \ + Vector2(MyIntVector2 value) : Vector2(value.x_, value.y_) { } \ + template>* = nullptr> \ + Vector2(MyVector2 value) : Vector2(value.x_, value.y_) { } \ + +// Extra code to be inserted into RmlUi::Vector3<> class body. +#define RMLUI_VECTOR3_USER_EXTRA \ + template>* = nullptr> \ + operator typename MyIntVector3() const { return MyIntVector3(x, y, z); } \ + template>* = nullptr> \ + operator MyVector3() const { return MyVector3(x, y, z); } \ + template>* = nullptr> \ + Vector3(MyIntVector3 value) : Vector3(value.x_, value.y_, value.z_) { } \ + template>* = nullptr> \ + Vector3(MyVector3 value) : Vector3(value.x_, value.y_, value.z_) { } \ + +// Extra code to be inserted into RmlUi::Vector4<> class body. +#define RMLUI_VECTOR4_USER_EXTRA \ + template>* = nullptr> \ + operator typename MyIntVector4() const { return MyIntVector4(x, y, z, w); } \ + template>* = nullptr> \ + operator MyVector4() const { return MyVector4(x, y, z, w); } \ + template>* = nullptr> \ + Vector4(MyIntVector4 value) : Vector4(value.x_, value.y_, value.z_, value.w_) { } \ + template>* = nullptr> \ + Vector4(MyVector4 value) : Vector4(value.x_, value.y_, value.z_, value.w_) { } \ + +// Extra code to be inserted into RmlUi::Matrix4<> class body. + #define RMLUI_MATRIX4_USER_EXTRA operator MyMatrix4() const { return MyMatrix4(data()); } +***/ + + +#endif // RMLUI_USER_CONFIG_FILE + +#endif // RMLUI_CONFIG_CONFIG_H diff --git a/thirdparty/RmlUi/Include/RmlUi/Core.h b/thirdparty/RmlUi/Include/RmlUi/Core.h new file mode 100644 index 000000000..c9cbb1119 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core.h @@ -0,0 +1,110 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_H +#define RMLUI_CORE_H + +#include "Core/Core.h" + +#include "Core/Types.h" +#include "Core/Math.h" +#include "Core/Header.h" +#include "Core/Animation.h" +#include "Core/Box.h" +#include "Core/ComputedValues.h" +#include "Core/Context.h" +#include "Core/ContextInstancer.h" +#include "Core/ConvolutionFilter.h" +#include "Core/DataController.h" +#include "Core/DataModel.h" +#include "Core/DataTypeRegister.h" +#include "Core/DataTypes.h" +#include "Core/DataVariable.h" +#include "Core/DataView.h" +#include "Core/Decorator.h" +#include "Core/DecoratorInstancer.h" +#include "Core/Element.h" +#include "Core/ElementDocument.h" +#include "Core/ElementInstancer.h" +#include "Core/ElementScroll.h" +#include "Core/ElementText.h" +#include "Core/ElementUtilities.h" +#include "Core/Event.h" +#include "Core/EventInstancer.h" +#include "Core/EventListener.h" +#include "Core/EventListenerInstancer.h" +#include "Core/Factory.h" +#include "Core/FileInterface.h" +#include "Core/FontEffect.h" +#include "Core/FontEffectInstancer.h" +#include "Core/FontEngineInterface.h" +#include "Core/FontGlyph.h" +#include "Core/Geometry.h" +#include "Core/GeometryUtilities.h" +#include "Core/ID.h" +#include "Core/Input.h" +#include "Core/Log.h" +#include "Core/Plugin.h" +#include "Core/PropertiesIteratorView.h" +#include "Core/Property.h" +#include "Core/PropertyDefinition.h" +#include "Core/PropertyDictionary.h" +#include "Core/PropertyIdSet.h" +#include "Core/PropertyParser.h" +#include "Core/PropertySpecification.h" +#include "Core/RenderInterface.h" +#include "Core/Spritesheet.h" +#include "Core/StringUtilities.h" +#include "Core/StyleSheet.h" +#include "Core/StyleSheetSpecification.h" +#include "Core/SystemInterface.h" +#include "Core/Texture.h" +#include "Core/Transform.h" +#include "Core/TransformPrimitive.h" +#include "Core/Tween.h" +#include "Core/TypeConverter.h" +#include "Core/Vertex.h" +#include "Core/XMLNodeHandler.h" +#include "Core/XMLParser.h" + +#include "Core/Elements/DataFormatter.h" +#include "Core/Elements/ElementDataGrid.h" +#include "Core/Elements/ElementDataGridCell.h" +#include "Core/Elements/ElementDataGridExpandButton.h" +#include "Core/Elements/ElementDataGridRow.h" +#include "Core/Elements/ElementForm.h" +#include "Core/Elements/ElementFormControl.h" +#include "Core/Elements/ElementFormControlDataSelect.h" +#include "Core/Elements/ElementFormControlInput.h" +#include "Core/Elements/ElementFormControlSelect.h" +#include "Core/Elements/ElementFormControlTextArea.h" +#include "Core/Elements/ElementProgressBar.h" +#include "Core/Elements/ElementTabSet.h" +#include "Core/Elements/SelectOption.h" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Animation.h b/thirdparty/RmlUi/Include/RmlUi/Core/Animation.h new file mode 100644 index 000000000..ffd638d8e --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Animation.h @@ -0,0 +1,75 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2018 Michael Ragazzon + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ANIMATION_H +#define RMLUI_CORE_ANIMATION_H + +#include "Types.h" +#include "Tween.h" +#include "ID.h" + +namespace Rml { + +/* Data parsed from the 'animation' property. */ +struct Animation { + float duration = 0.0f; + Tween tween; + float delay = 0.0f; + bool alternate = false; + bool paused = false; + int num_iterations = 1; + String name; +}; + +/* Data parsed from the 'transition' property. */ +struct Transition { + PropertyId id = PropertyId::Invalid; + Tween tween; + float duration = 0.0f; + float delay = 0.0f; + float reverse_adjustment_factor = 0.0f; +}; + +struct TransitionList { + bool none = true; + bool all = false; + Vector transitions; + + TransitionList() {} + TransitionList(bool none, bool all, Vector transitions) : + none(none), all(all), transitions(transitions) {} +}; + +inline bool operator==(const Animation& a, const Animation& b) { return a.duration == b.duration && a.tween == b.tween && a.delay == b.delay && a.alternate == b.alternate && a.paused == b.paused && a.num_iterations == b.num_iterations && a.name == b.name; } +inline bool operator!=(const Animation& a, const Animation& b) { return !(a == b); } +inline bool operator==(const Transition& a, const Transition& b) { return a.id == b.id && a.tween == b.tween && a.duration == b.duration && a.delay == b.delay && a.reverse_adjustment_factor == b.reverse_adjustment_factor; } +inline bool operator!=(const Transition& a, const Transition& b) { return !(a == b); } +inline bool operator==(const TransitionList& a, const TransitionList& b) { return a.none == b.none && a.all == b.all && a.transitions == b.transitions; } +inline bool operator!=(const TransitionList& a, const TransitionList& b) { return !(a == b); } + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/BaseXMLParser.h b/thirdparty/RmlUi/Include/RmlUi/Core/BaseXMLParser.h new file mode 100644 index 000000000..3238b3eb1 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/BaseXMLParser.h @@ -0,0 +1,139 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_BASEXMLPARSER_H +#define RMLUI_CORE_BASEXMLPARSER_H + +#include "Header.h" +#include "Types.h" +#include "Dictionary.h" + +namespace Rml { + +class Stream; +class URL; +using XMLAttributes = Dictionary; + +enum class XMLDataType { Text, CData, InnerXML }; + +/** + @author Peter Curry + */ + +class RMLUICORE_API BaseXMLParser +{ + public: + BaseXMLParser(); + virtual ~BaseXMLParser(); + + /// Registers a tag as containing general character data. This will mean the contents of the tag will be parsed + /// similarly to a CDATA tag (ie, no other markup will be recognised until the section's closing tag is found). + /// @param[in] tag The tag to register as containing generic character data. + void RegisterCDATATag(const String& tag); + + /// When an XML attribute with the given name is encountered during parsing, then all content below the current + /// node is treated as data. + /// @note While children nodes are treated as data (text), it is assumed that the content represents valid XML. + /// The parsing proceeds as normal except that the Handle...() functions are not called until the + /// starting node is closed. Then, all its contents are submitted as Data (raw text string). + /// @note In particular, this behavior is useful for some data-binding views. + void RegisterInnerXMLAttribute(const String& attribute_name); + + /// Parses the given stream as an XML file, and calls the handlers when + /// interesting phenomena are encountered. + void Parse(Stream* stream); + + /// Get the line number in the stream. + /// @return The line currently being processed in the XML stream. + int GetLineNumber() const; + /// Get the line number of the last open tag in the stream. + int GetLineNumberOpenTag() const; + + /// Called when the parser finds the beginning of an element tag. + virtual void HandleElementStart(const String& name, const XMLAttributes& attributes); + /// Called when the parser finds the end of an element tag. + virtual void HandleElementEnd(const String& name); + /// Called when the parser encounters data. + virtual void HandleData(const String& data, XMLDataType type); + + protected: + const URL* GetSourceURLPtr() const; + + private: + const URL* source_url = nullptr; + String xml_source; + size_t xml_index = 0; + + void Next(); + bool AtEnd() const; + char Look() const; + + void HandleElementStartInternal(const String& name, const XMLAttributes& attributes); + void HandleElementEndInternal(const String& name); + void HandleDataInternal(const String& data, XMLDataType type); + + void ReadHeader(); + void ReadBody(); + bool ReadOpenTag(); + + bool ReadCloseTag(size_t xml_index_tag); + bool ReadAttributes(XMLAttributes& attributes, bool& parse_raw_xml_content); + bool ReadCDATA(const char* tag_terminator = nullptr); + + // Reads from the stream until a complete word is found. + // @param[out] word Word thats been found + // @param[in] terminators List of characters that terminate the search + bool FindWord(String& word, const char* terminators = nullptr); + // Reads from the stream until the given character set is found. All + // intervening characters will be returned in data. + bool FindString(const char* string, String& data, bool escape_brackets = false); + // Returns true if the next sequence of characters in the stream + // matches the given string. If consume is set and this returns true, + // the characters will be consumed. + bool PeekString(const char* string, bool consume = true); + + int line_number = 0; + int line_number_open_tag = 0; + int open_tag_depth = 0; + + // Enabled when an attribute for inner xml data is encountered (see description in Register...() above). + bool inner_xml_data = false; + int inner_xml_data_terminate_depth = 0; + size_t inner_xml_data_index_begin = 0; + + // The element attributes being read. + XMLAttributes attributes; + // The loose data being read. + String data; + + SmallUnorderedSet< String > cdata_tags; + SmallUnorderedSet< String > attributes_for_inner_xml_data; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Box.h b/thirdparty/RmlUi/Include/RmlUi/Core/Box.h new file mode 100644 index 000000000..eaecfbb22 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Box.h @@ -0,0 +1,122 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_BOX_H +#define RMLUI_CORE_BOX_H + +#include "Types.h" + +namespace Rml { + +/** + Stores a box with four sized areas; content, padding, a border and margin. See + http://www.w3.org/TR/REC-CSS2/box.html#box-dimensions for a diagram. + + @author Peter Curry + */ + +class RMLUICORE_API Box +{ +public: + enum Area + { + MARGIN = 0, + BORDER = 1, + PADDING = 2, + CONTENT = 3, + NUM_AREAS = 3, // ignores CONTENT + }; + + enum Edge + { + TOP = 0, + RIGHT = 1, + BOTTOM = 2, + LEFT = 3, + NUM_EDGES = 4 + }; + + /// Initialises a zero-sized box. + Box(); + /// Initialises a box with a default content area and no padding, borders and margins. + Box(const Vector2f& content); + ~Box(); + + /// Returns the offset of this box. This will usually be (0, 0). + /// @return The box's offset. + const Vector2f& GetOffset() const; + /// Returns the top-left position of one of the box's areas, relative to the top-left of the border area. This + /// means the position of the margin area is likely to be negative. + /// @param area[in] The desired area. + /// @return The position of the area. + Vector2f GetPosition(Area area = Box::CONTENT) const; + /// Returns the size of one of the box's areas. This will include all inner areas. + /// @param area[in] The desired area. + /// @return The size of the requested area. + Vector2f GetSize(Area area = Box::CONTENT) const; + + /// Sets the offset of the box, relative usually to the owning element. This should only be set for auxiliary + /// boxes of an element. + /// @param offset[in] The offset of the box from the primary box. + void SetOffset(const Vector2f& offset); + /// Sets the size of the content area. + /// @param content[in] The size of the new content area. + void SetContent(const Vector2f& content); + /// Sets the size of one of the edges of one of the box's outer areas. + /// @param area[in] The area to change. + /// @param edge[in] The area edge to change. + /// @param size[in] The new size of the area segment. + void SetEdge(Area area, Edge edge, float size); + + /// Returns the size of one of the area edges. + /// @param area[in] The desired area. + /// @param edge[in] The desired edge. + /// @return The size of the requested area edge. + float GetEdge(Area area, Edge edge) const; + /// Returns the cumulative size of one edge up to one of the box's areas. + /// @param area[in] The area to measure up to (and including). So, MARGIN will return the width of the margin, and PADDING will be the sum of the margin, border and padding. + /// @param edge[in] The desired edge. + /// @return The cumulative size of the edge. + float GetCumulativeEdge(Area area, Edge edge) const; + + /// Compares the size of the content area and the other area edges. + /// @return True if the boxes represent the same area. + bool operator==(const Box& rhs) const; + /// Compares the size of the content area and the other area edges. + /// @return True if the boxes do not represent the same area. + bool operator!=(const Box& rhs) const; + +private: + Vector2f content; + float area_edges[NUM_AREAS][NUM_EDGES]; + + Vector2f offset; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Colour.h b/thirdparty/RmlUi/Include/RmlUi/Core/Colour.h new file mode 100644 index 000000000..fac164dae --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Colour.h @@ -0,0 +1,124 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_COLOUR_H +#define RMLUI_CORE_COLOUR_H + +#include "Header.h" + +namespace Rml { + +/** + Templated class for a four-component RGBA colour. + + @author Peter Curry + */ + +template < typename ColourType, int AlphaDefault > +class Colour +{ +public: + /// Initialising constructor. + /// @param[in] rgb Initial red, green and blue value of the colour. + /// @param[in] alpha Initial alpha value of the colour. + inline Colour(ColourType rgb = ColourType{ 0 }, ColourType alpha = ColourType{ AlphaDefault }); + /// Initialising constructor. + /// @param[in] red Initial red value of the colour. + /// @param[in] green Initial green value of the colour. + /// @param[in] blue Initial blue value of the colour. + /// @param[in] alpha Initial alpha value of the colour. + inline Colour(ColourType red, ColourType green, ColourType blue, ColourType alpha = ColourType{ AlphaDefault }); + + /// Returns the sum of this colour and another. This does not saturate the channels. + /// @param[in] rhs The colour to add this to. + /// @return The sum of the two colours. + inline Colour operator+(const Colour& rhs) const; + /// Returns the result of subtracting another colour from this colour. + /// @param[in] rhs The colour to subtract from this colour. + /// @return The result of the subtraction. + inline Colour operator-(const Colour& rhs) const; + /// Returns the result of multiplying this colour by another. + /// @param[in] rhs The colour to multiply by. + /// @return The result of the multiplication. + Colour operator*(const Colour& rhs) const; + /// Returns the result of multiplying this colour component-wise by a scalar. + /// @param[in] rhs The scalar value to multiply by. + /// @return The result of the scale. + inline Colour operator*(float rhs) const; + /// Returns the result of dividing this colour component-wise by a scalar. + /// @param[in] rhs The scalar value to divide by. + /// @return The result of the scale. + inline Colour operator/(float rhs) const; + + /// Adds another colour to this in-place. This does not saturate the channels. + /// @param[in] rhs The colour to add. + inline void operator+=(const Colour& rhs); + /// Subtracts another colour from this in-place. + /// @param[in] rhs The colour to subtract. + inline void operator-=(const Colour& rhs); + /// Multiplies this colour component-wise with another in-place. + /// @param[in] rhs The colour to multiply by. + /// @return This colour, post-operation. + void operator*=(const Colour& rhs); + /// Scales this colour component-wise in-place. + /// @param[in] rhs The value to scale this colours's components by. + inline void operator*=(float rhs); + /// Scales this colour component-wise in-place by the inverse of a value. + /// @param[in] rhs The value to divide this colour's components by. + inline void operator/=(float rhs); + + /// Equality operator. + /// @param[in] rhs The colour to compare this against. + /// @return True if the two colours are equal, false otherwise. + inline bool operator==(const Colour& rhs) { return red == rhs.red && green == rhs.green && blue == rhs.blue && alpha == rhs.alpha; } + /// Inequality operator. + /// @param[in] rhs The colour to compare this against. + /// @return True if the two colours are not equal, false otherwise. + inline bool operator!=(const Colour& rhs) { return red != rhs.red || green != rhs.green || blue != rhs.blue || alpha != rhs.alpha; } + + /// Auto-cast operator. + /// @return A pointer to the first value. + inline operator const ColourType*() const { return &red; } + /// Constant auto-cast operator. + /// @return A constant pointer to the first value. + inline operator ColourType*() { return &red; } + + ColourType red, green, blue, alpha; + +#ifdef RMLUI_COLOUR_USER_EXTRA + RMLUI_COLOUR_USER_EXTRA +#endif +}; + +} // namespace Rml + + +#include "Colour.inl" + + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Colour.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Colour.inl new file mode 100644 index 000000000..049a5f3df --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Colour.inl @@ -0,0 +1,122 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { + +// Lightweight, non-initialising constructor. +template < typename ColourType, int AlphaDefault > +Colour< ColourType, AlphaDefault >::Colour(ColourType rgb, ColourType alpha) + : red(rgb), green(rgb), blue(rgb), alpha(alpha) +{ +} + +// Initialising constructor. +template < typename ColourType, int AlphaDefault > +Colour< ColourType, AlphaDefault >::Colour(ColourType red, ColourType green, ColourType blue, ColourType alpha) + : red(red), green(green), blue(blue), alpha(alpha) +{ +} + +// Returns the sum of this colour and another. This does not saturate the channels. +template < typename ColourType, int AlphaDefault > +Colour< ColourType, AlphaDefault > Colour< ColourType, AlphaDefault >::operator+(const Colour< ColourType, AlphaDefault >& rhs) const +{ + return Colour< ColourType, AlphaDefault >(red + rhs.red, green + rhs.green, blue + rhs.blue, alpha + rhs.alpha); +} + +// Returns the result of subtracting another colour from this colour. +template < typename ColourType, int AlphaDefault > +Colour< ColourType, AlphaDefault > Colour< ColourType, AlphaDefault >::operator-(const Colour< ColourType, AlphaDefault >& rhs) const +{ + return Colour< ColourType, AlphaDefault >(red - rhs.red, green - rhs.green, blue - rhs.blue, alpha - rhs.alpha); +} + +// Returns the result of multiplying this colour component-wise by a scalar. +template < typename ColourType, int AlphaDefault > +Colour< ColourType, AlphaDefault > Colour< ColourType, AlphaDefault >::operator*(float rhs) const +{ + return Colour((ColourType) (red * rhs), (ColourType) (green * rhs), (ColourType) (blue * rhs), (ColourType) (alpha * rhs)); +} + +// Returns the result of dividing this colour component-wise by a scalar. +template < typename ColourType, int AlphaDefault > +Colour< ColourType, AlphaDefault > Colour< ColourType, AlphaDefault >::operator/(float rhs) const +{ + return Colour((ColourType) (red / rhs), (ColourType) (green / rhs), (ColourType) (blue / rhs), (ColourType) (alpha / rhs)); +} + +// Adds another colour to this in-place. This does not saturate the channels. +template < typename ColourType, int AlphaDefault > +void Colour< ColourType, AlphaDefault >::operator+=(const Colour& rhs) +{ + red += rhs.red; + green += rhs.green; + blue += rhs.blue; + alpha += rhs.alpha; +} + +// Subtracts another colour from this in-place. +template < typename ColourType, int AlphaDefault > +void Colour< ColourType, AlphaDefault >::operator-=(const Colour& rhs) +{ + red -= rhs.red; + green -= rhs.green; + blue -= rhs.blue; + alpha -= rhs.alpha; +} + +// Scales this colour component-wise in-place. +template < typename ColourType, int AlphaDefault > +void Colour< ColourType, AlphaDefault >::operator*=(float rhs) +{ + red = (ColourType)(red * rhs); + green = (ColourType)(green * rhs); + blue = (ColourType)(blue * rhs); + alpha = (ColourType)(alpha * rhs); +} + +// Scales this colour component-wise in-place by the inverse of a value. +template < typename ColourType, int AlphaDefault > +void Colour< ColourType, AlphaDefault >::operator/=(float rhs) +{ + *this *= (1.0f / rhs); +} + +template < > +Colour< float, 1 > RMLUICORE_API Colour< float, 1 >::operator*(const Colour< float, 1 >& rhs) const; + +template < > +Colour< byte, 255 > RMLUICORE_API Colour< byte, 255 >::operator*(const Colour< byte, 255 >& rhs) const; + +template < > +void RMLUICORE_API Colour< float, 1 >::operator*=(const Colour& rhs); + +template < > +void RMLUICORE_API Colour< byte, 255 >::operator*=(const Colour& rhs); + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ComputedValues.h b/thirdparty/RmlUi/Include/RmlUi/Core/ComputedValues.h new file mode 100644 index 000000000..85634dc4c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ComputedValues.h @@ -0,0 +1,224 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_COMPUTEDVALUES_H +#define RMLUI_CORE_COMPUTEDVALUES_H + +#include "Types.h" +#include "Animation.h" + +namespace Rml { + +namespace Style +{ + +struct LengthPercentageAuto { + enum Type { Auto, Length, Percentage } type = Length; + float value = 0; + LengthPercentageAuto() {} + LengthPercentageAuto(Type type, float value = 0) : type(type), value(value) {} +}; +struct LengthPercentage { + enum Type { Length, Percentage } type = Length; + float value = 0; + LengthPercentage() {} + LengthPercentage(Type type, float value = 0) : type(type), value(value) {} +}; + +struct NumberAuto { + enum Type { Auto, Number } type = Number; + float value = 0; + NumberAuto() {} + NumberAuto(Type type, float value = 0) : type(type), value(value) {} +}; + + +using Margin = LengthPercentageAuto; +using Padding = LengthPercentage; + +enum class Display : uint8_t { None, Block, Inline, InlineBlock }; +enum class Position : uint8_t { Static, Relative, Absolute, Fixed }; + +using Top = LengthPercentageAuto; +using Right = LengthPercentageAuto; +using Bottom = LengthPercentageAuto; +using Left = LengthPercentageAuto; + +enum class Float : uint8_t { None, Left, Right }; +enum class Clear : uint8_t { None, Left, Right, Both }; + +using ZIndex = NumberAuto; + +using Width = LengthPercentageAuto; +using MinWidth = LengthPercentage; +using MaxWidth = LengthPercentage; + +using Height = LengthPercentageAuto; +using MinHeight = LengthPercentage; +using MaxHeight = LengthPercentage; + +struct LineHeight { + float value = 12.f * 1.2f; // The computed value (length) + enum InheritType { Number, Length } inherit_type = Number; + float inherit_value = 1.2f; + LineHeight() {} + LineHeight(float value, InheritType inherit_type, float inherit_value) : value(value), inherit_type(inherit_type), inherit_value(inherit_value) {} +}; +struct VerticalAlign { + enum Type { Baseline, Middle, Sub, Super, TextTop, TextBottom, Top, Bottom, Length } type; + float value; // For length type + VerticalAlign(Type type = Baseline) : type(type), value(0) {} + VerticalAlign(float value) : type(Length), value(value) {} +}; + +enum class Overflow : uint8_t { Visible, Hidden, Auto, Scroll }; +struct Clip { + enum class Type : uint8_t { Auto, None, Number }; + // Note, internally 'number' is encoded with Auto as 0 and None as -1. However, the enum must correspond to the keywords in StyleSheetSpec. + int number = 0; + Clip() {} + Clip(Type type, int number = 0) : number(type == Type::Auto ? 0 : (type == Type::None ? -1 : number)) {} +}; + +enum class Visibility : uint8_t { Visible, Hidden }; + +enum class FontStyle : uint8_t { Normal, Italic }; +enum class FontWeight : uint8_t { Normal, Bold }; + +enum class TextAlign : uint8_t { Left, Right, Center, Justify }; +enum class TextDecoration : uint8_t { None, Underline, Overline, LineThrough }; +enum class TextTransform : uint8_t { None, Capitalize, Uppercase, Lowercase }; +enum class WhiteSpace : uint8_t { Normal, Pre, Nowrap, Prewrap, Preline }; + +enum class Drag : uint8_t { None, Drag, DragDrop, Block, Clone }; +enum class TabIndex : uint8_t { None, Auto }; +enum class Focus : uint8_t { None, Auto }; +enum class PointerEvents : uint8_t { None, Auto }; + +using PerspectiveOrigin = LengthPercentage; +using TransformOrigin = LengthPercentage; + +enum class OriginX : uint8_t { Left, Center, Right }; +enum class OriginY : uint8_t { Top, Center, Bottom }; + + +/* + A computed value is a value resolved as far as possible :before: introducing layouting. See CSS specs for details of each property. + + Note: Enums and default values must correspond to the keywords and defaults in `StyleSheetSpecification.cpp`. +*/ + +struct ComputedValues +{ + Margin margin_top, margin_right, margin_bottom, margin_left; + Padding padding_top, padding_right, padding_bottom, padding_left; + float border_top_width = 0, border_right_width = 0, border_bottom_width = 0, border_left_width = 0; + Colourb border_top_color{ 255, 255, 255 }, border_right_color{ 255, 255, 255 }, border_bottom_color{ 255, 255, 255 }, border_left_color{ 255, 255, 255 }; + + Display display = Display::Inline; + Position position = Position::Static; + + Top top{ Top::Auto }; + Right right{ Right::Auto }; + Bottom bottom{ Bottom::Auto }; + Left left{ Left::Auto }; + + Float float_ = Float::None; + Clear clear = Clear::None; + + ZIndex z_index = { ZIndex::Auto }; + + Width width = { Width::Auto }; + MinWidth min_width; + MaxWidth max_width{ MaxWidth::Length, -1.f }; + Height height = { Height::Auto }; + MinHeight min_height; + MaxHeight max_height{ MaxHeight::Length, -1.f }; + + LineHeight line_height; + VerticalAlign vertical_align; + + Overflow overflow_x = Overflow::Visible, overflow_y = Overflow::Visible; + Clip clip; + + Visibility visibility = Visibility::Visible; + + Colourb background_color = Colourb(255, 255, 255, 0); + Colourb color = Colourb(255, 255, 255); + Colourb image_color = Colourb(255, 255, 255); + float opacity = 1; + + String font_family; + FontStyle font_style = FontStyle::Normal; + FontWeight font_weight = FontWeight::Normal; + float font_size = 12.f; + // Font face used to render text and resolve ex properties. Does not represent a true property + // like most computed values, but placed here as it is used and inherited in a similar manner. + FontFaceHandle font_face_handle = 0; + + TextAlign text_align = TextAlign::Left; + TextDecoration text_decoration = TextDecoration::None; + TextTransform text_transform = TextTransform::None; + WhiteSpace white_space = WhiteSpace::Normal; + + String cursor; + + Drag drag = Drag::None; + TabIndex tab_index = TabIndex::None; + Focus focus = Focus::Auto; + float scrollbar_margin = 0; + PointerEvents pointer_events = PointerEvents::Auto; + + float perspective = 0; + PerspectiveOrigin perspective_origin_x = { PerspectiveOrigin::Percentage, 50.f }; + PerspectiveOrigin perspective_origin_y = { PerspectiveOrigin::Percentage, 50.f }; + + TransformPtr transform; + TransformOrigin transform_origin_x = { TransformOrigin::Percentage, 50.f }; + TransformOrigin transform_origin_y = { TransformOrigin::Percentage, 50.f }; + float transform_origin_z = 0.0f; + + TransitionList transition; + AnimationList animation; + + DecoratorsPtr decorator; + FontEffectsPtr font_effect; // Sorted by layer first (back then front), then by declaration order. +}; +} + + +// Resolves a computed LengthPercentage value to the base unit 'px'. +// Percentages are scaled by the base_value. +// Note: Auto must be manually handled during layout, here it returns zero. +RMLUICORE_API float ResolveValue(Style::LengthPercentageAuto length, float base_value); +RMLUICORE_API float ResolveValue(Style::LengthPercentage length, float base_value); + + +using ComputedValues = Style::ComputedValues; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Containers/chobo/flat_map.hpp b/thirdparty/RmlUi/Include/RmlUi/Core/Containers/chobo/flat_map.hpp new file mode 100644 index 000000000..c53f326ce --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Containers/chobo/flat_map.hpp @@ -0,0 +1,755 @@ +// chobo-flat-map v1.01 +// +// std::map-like class with an underlying vector +// +// MIT License: +// Copyright(c) 2016 Chobolabs Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files(the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and / or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions : +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// VERSION HISTORY +// +// 1.01 (2016-09-27) Fix for keys with no operator==. Clean up of assignment. +// Added swap method. +// 1.00 (2016-09-23) First public release +// +// +// DOCUMENTATION +// +// Simply include this file wherever you need. +// It defines the class chobo::flat_map, which is an almsot drop-in replacement +// of std::map. Flat map has an optional underlying container which by default +// is std::vector. Thus the items in the map are in a continuous block of +// memory. Thus iterating over the map is cache friendly, at the cost of +// O(n) for insert and erase. +// +// The elements inside (like in std::map) are kept in an order sorted by key. +// Getting a value by key is O(log2 n) +// +// It generally performs much faster than std::map for smaller sets of elements +// +// The difference with std::map, which makes flat_map an not-exactly-drop-in +// replacement is the last template argument: +// * std::map has +// * chobo::flat_map has +// The container must be an std::vector compatible type (chobo::static_vector +// and chobo::vector_ptr are, for example, viable). The container value type +// must be std::pair. +// +// Changing the allocator. +// +// If you want to change the allocator of flat map, you'll have to provide a +// container with the appriate one. Example: +// +// chobo::flat_map< +// string, +// int, +// less, +// std::vector, MyAllocator> +// > mymap +// +// +// Configuration +// +// chobo::flat_map has two configurable settings: +// +// 1. Throw +// Whether to throw exceptions: when `at` is called with a non-existent key. +// By default, like std::map, it throws an std::out_of_range exception. If you define +// CHOBO_FLAT_MAP_NO_THROW before including this header, the exception will +// be substituted by an assertion. +// +// 2. const char* overloads +// By default chobo::flat_map provides overloads for the access methods +// (at, operator[], find, lower_bound, count) for const char* for cases when +// std::string is the key, so that no allocations happen when accessing with +// a C-string of a string literal. +// However if const char* or any other class with implicit conversion from +// const char* is the key, they won't compile. +// If you plan on using flat_map with such keys, you'll need to define +// CHOBO_FLAT_MAP_NO_CONST_CHAR_OVERLOADS before including the header +// +// +// TESTS +// +// The tests are included in the header file and use doctest (https://github.com/onqtam/doctest). +// To run them, define CHOBO_FLAT_MAP_TEST_WITH_DOCTEST before including +// the header in a file which has doctest.h already included. +// +// Additionally if chobo::static_vector is also available you may define +// CHOBO_FLAT_MAP_TEST_STATIC_VECTOR_WITH_DOCTEST to test flat_map with an +// unrelying static_vector +// +// Additionally if chobo::vector_ptr is also available you may define +// CHOBO_FLAT_MAP_TEST_VECTOR_PTR_WITH_DOCTEST to test flat_map with an +// unrelying vector_ptr +// +#pragma once + +#include +#include +#include + +#if !defined(CHOBO_FLAT_MAP_NO_CONST_CHAR_OVERLOADS) +#include +#endif + +#if !defined(CHOBO_FLAT_MAP_NO_THROW) +# include +# define _CHOBO_THROW_FLAT_MAP_OUT_OF_RANGE() throw std::out_of_range("chobo::flat_map out of range") +#else +# include +# define _CHOBO_THROW_FLAT_MAP_OUT_OF_RANGE() assert(false && "chobo::flat_map out of range") +#endif + +namespace chobo +{ + +template , typename Container = std::vector>> +class flat_map +{ +public: + typedef Key key_type; + typedef T mapped_type; + typedef std::pair value_type; + typedef Container container_type; + typedef Compare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename container_type::allocator_type allocator_type; + typedef typename std::allocator_traits::pointer pointer; + typedef typename std::allocator_traits::pointer const_pointer; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::reverse_iterator reverse_iterator; + typedef typename container_type::const_reverse_iterator const_reverse_iterator; + typedef typename container_type::difference_type difference_type; + typedef typename container_type::size_type size_type; + + flat_map() + {} + + explicit flat_map(const key_compare& comp, const allocator_type& alloc = allocator_type()) + : m_cmp(comp) + , m_container(alloc) + {} + + flat_map(const flat_map& x) = default; + flat_map(flat_map&& x) = default; + + flat_map(std::initializer_list ilist) : m_cmp(Compare()) + { + m_container.reserve(ilist.size()); + for (auto&& il : ilist) + emplace(il); + } + + flat_map& operator=(const flat_map& x) + { + m_cmp = x.m_cmp; + m_container = x.m_container; + return *this; + } + flat_map& operator=(flat_map&& x) + { + m_cmp = std::move(x.m_cmp); + m_container = std::move(x.m_container); + return *this; + } + + iterator begin() noexcept { return m_container.begin(); } + const_iterator begin() const noexcept { return m_container.begin(); } + iterator end() noexcept { return m_container.end(); } + const_iterator end() const noexcept { return m_container.end(); } + reverse_iterator rbegin() noexcept { return m_container.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_container.rbegin(); } + reverse_iterator rend() noexcept { return m_container.rend(); } + const_reverse_iterator rend() const noexcept { return m_container.rend(); } + const_iterator cbegin() const noexcept { return m_container.cbegin(); } + const_iterator cend() const noexcept { return m_container.cend(); } + + bool empty() const noexcept { return m_container.empty(); } + size_type size() const noexcept { return m_container.size(); } + size_type max_size() const noexcept { return m_container.max_size(); } + + void reserve(size_type count) { return m_container.reserve(count); } + size_type capacity() const noexcept { return m_container.capacity(); } + + void clear() noexcept { m_container.clear(); } + + iterator lower_bound(const key_type& k) + { + return std::lower_bound(m_container.begin(), m_container.end(), k, m_cmp); + } + + const_iterator lower_bound(const key_type& k) const + { + return std::lower_bound(m_container.begin(), m_container.end(), k, m_cmp); + } + + iterator find(const key_type& k) + { + auto i = lower_bound(k); + if (i != end() && !m_cmp(k, *i)) + return i; + + return end(); + } + + const_iterator find(const key_type& k) const + { + auto i = lower_bound(k); + if (i != end() && !m_cmp(k, *i)) + return i; + + return end(); + } + + size_t count(const key_type& k) const + { + return find(k) == end() ? 0 : 1; + } + + template + std::pair insert(P&& val) + { + auto i = lower_bound(val.first); + if (i != end() && !m_cmp(val.first, *i)) + { + return { i, false }; + } + + return{ m_container.emplace(i, std::forward

(val)), true }; + } + + std::pair insert(const value_type& val) + { + auto i = lower_bound(val.first); + if (i != end() && !m_cmp(val.first, *i)) + { + return { i, false }; + } + + return{ m_container.emplace(i, val), true }; + } + + template + std::pair emplace(Args&&... args) + { + value_type val(std::forward(args)...); + return insert(std::move(val)); + } + + iterator erase(const_iterator pos) + { + return m_container.erase(pos); + } + + size_type erase(const key_type& k) + { + auto i = find(k); + if (i == end()) + { + return 0; + } + + erase(i); + return 1; + } + + mapped_type& operator[](const key_type& k) + { + auto i = lower_bound(k); + if (i != end() && !m_cmp(k, *i)) + { + return i->second; + } + + i = m_container.emplace(i, k, mapped_type()); + return i->second; + } + + mapped_type& operator[](key_type&& k) + { + auto i = lower_bound(k); + if (i != end() && !m_cmp(k, *i)) + { + return i->second; + } + + i = m_container.emplace(i, std::forward(k), mapped_type()); + return i->second; + } + + mapped_type& at(const key_type& k) + { + auto i = lower_bound(k); + if (i == end() || m_cmp(*i, k)) + { + _CHOBO_THROW_FLAT_MAP_OUT_OF_RANGE(); + } + + return i->second; + } + + const mapped_type& at(const key_type& k) const + { + auto i = lower_bound(k); + if (i == end() || m_cmp(*i, k)) + { + _CHOBO_THROW_FLAT_MAP_OUT_OF_RANGE(); + } + + return i->second; + } + + void swap(flat_map& x) + { + std::swap(m_cmp, x.m_cmp); + m_container.swap(x.m_container); + } + + const container_type& container() const noexcept + { + return m_container; + } + + // DANGER! If you're not careful with this function, you may irreversably break the map + container_type& modify_container() noexcept + { + return m_container; + } + +#if !defined(CHOBO_FLAT_MAP_NO_CONST_CHAR_OVERLOADS) + /////////////////////////////////////////////////////////////////////////////////// + // const char* overloads for maps with an std::string key to avoid allocs + iterator lower_bound(const char* k) + { + static_assert(std::is_same::value, "flat_map::lower_bound(const char*) works only for std::strings"); + static_assert(std::is_same, key_compare>::value, "flat_map::lower_bound(const char*) works only for std::string-s, compared with std::less"); + return std::lower_bound(m_container.begin(), m_container.end(), k, [](const value_type& a, const char* b) -> bool + { + return strcmp(a.first.c_str(), b) < 0; + }); + } + + const_iterator lower_bound(const char* k) const + { + static_assert(std::is_same::value, "flat_map::lower_bound(const char*) works only for std::strings"); + static_assert(std::is_same, key_compare>::value, "flat_map::lower_bound(const char*) works only for std::string-s, compared with std::less"); + return std::lower_bound(m_container.begin(), m_container.end(), k, [](const value_type& a, const char* b) -> bool + { + return strcmp(a.first.c_str(), b) < 0; + }); + } + + mapped_type& operator[](const char* k) + { + auto i = lower_bound(k); + if (i != end() && i->first == k) + { + return i->second; + } + + i = m_container.emplace(i, k, mapped_type()); + return i->second; + } + + mapped_type& at(const char* k) + { + auto i = lower_bound(k); + if (i == end() || i->first != k) + { + _CHOBO_THROW_FLAT_MAP_OUT_OF_RANGE(); + } + + return i->second; + } + + const mapped_type& at(const char* k) const + { + auto i = lower_bound(k); + if (i == end() || i->first != k) + { + _CHOBO_THROW_FLAT_MAP_OUT_OF_RANGE(); + } + + return i->second; + } + + iterator find(const char* k) + { + auto i = lower_bound(k); + if (i != end() && i->first == k) + return i; + + return end(); + } + + const_iterator find(const char* k) const + { + auto i = lower_bound(k); + if (i != end() && i->first == k) + return i; + + return end(); + } + + size_t count(const char* k) const + { + return find(k) == end() ? 0 : 1; + } + +#endif // !defined(CHOBO_FLAT_MAP_NO_CONST_CHAR_OVERLOADS) + +private: + struct pair_compare + { + pair_compare() = default; + pair_compare(const key_compare& kc) : kcmp(kc) {} + bool operator()(const value_type& a, const key_type& b) const + { + return kcmp(a.first, b); + } + + bool operator()(const key_type& a, const value_type& b) const + { + return kcmp(a, b.first); + } + + key_compare kcmp; + }; + pair_compare m_cmp; + container_type m_container; +}; + +template +bool operator==(const flat_map& a, const flat_map& b) +{ + return a.container() == b.container(); +} + +template +bool operator!=(const flat_map& a, const flat_map& b) +{ + return a.container() != b.container(); +} +template +bool operator<(const flat_map& a, const flat_map& b) +{ + return a.container() < b.container(); +} + +} + +#if defined(CHOBO_FLAT_MAP_TEST_WITH_DOCTEST) + +#include + +namespace chobo_flat_map_test +{ + +// struct with no operator== +struct int_wrap +{ + int_wrap() = default; + int_wrap(int i) : val(i) {} + int val; + + struct compare + { + bool operator()(const int_wrap& a, const int_wrap& b) const + { + return a.val < b.val; + } + }; +}; + +} + +TEST_CASE("[flat_map] test") +{ + using namespace chobo; + using namespace chobo_flat_map_test; + + flat_map ifmap; + CHECK(ifmap.empty()); + CHECK(ifmap.size() == 0); + CHECK(ifmap.capacity() == 0); + CHECK(ifmap.begin() == ifmap.end()); + + ifmap[1] = 3.2f; + CHECK(ifmap.size() == 1); + + auto ifit = ifmap.begin(); + CHECK(ifit->first == 1); + CHECK(ifit->second == 3.2f); + CHECK(ifmap[1] == 3.2f); + CHECK(ifmap.at(1) == 3.2f); + CHECK(ifmap.count(1) == 1); + CHECK(ifmap.count(5) == 0); + + ++ifit; + CHECK(ifit == ifmap.end()); + + auto res = ifmap.insert(std::make_pair(6, 3.14f)); + CHECK(res.second); + CHECK(res.first == ifmap.begin() + 1); + + res = ifmap.emplace(3, 5.5f); + CHECK(res.second); + CHECK(res.first == ifmap.begin() + 1); + + res = ifmap.emplace(6, 8.f); + CHECK(!res.second); + CHECK(res.first == ifmap.begin() + 2); + + ifmap[2] = 5; + ifmap[52] = 15; + ifmap[12] = 1; + CHECK(ifmap.size() == 6); + + auto cmp = [](const flat_map::value_type& a, const flat_map::value_type& b) -> bool + { + return a.first < b.first; + }; + + CHECK(std::is_sorted(ifmap.begin(), ifmap.end(), cmp)); + + ifmap.erase(12); + CHECK(ifmap.size() == 5); + + CHECK(std::is_sorted(ifmap.begin(), ifmap.end(), cmp)); + + ifit = ifmap.find(12); + CHECK(ifit == ifmap.end()); + + ifit = ifmap.find(6); + CHECK(ifit != ifmap.end()); + ifmap.erase(ifit); + + CHECK(ifmap.size() == 4); + CHECK(std::is_sorted(ifmap.begin(), ifmap.end(), cmp)); + ifit = ifmap.find(6); + CHECK(ifit == ifmap.end()); + + // + + flat_map simap; + + CHECK(simap["123"] == 0); + + CHECK(simap.begin()->first.c_str() == "123"); + + ++simap["asd"]; + + auto siit = simap.find("asd"); + CHECK(siit != simap.end()); + CHECK(siit->second == 1); + CHECK(siit == simap.begin() + 1); + + CHECK(simap.count("bababa") == 0); + CHECK(simap.count("asd") == 1); + + std::string asd = "asd"; + CHECK(simap.at(asd) == simap.at("asd")); + + simap["0The quick brown fox jumps over the lazy dog"] = 555; + CHECK(simap.begin()->first[1] == 'T'); + const void* cstr = simap.begin()->first.c_str(); + + auto simap2 = std::move(simap); + CHECK(simap.empty()); + CHECK(simap2.begin()->first.c_str() == cstr); + + simap = std::move(simap2); + CHECK(simap2.empty()); + CHECK(simap.begin()->first.c_str() == cstr); + + CHECK(simap2 != simap); + simap2 = simap; + CHECK(simap2 == simap); + + // no == comparable tests + flat_map iwmap; + iwmap[5] = 1; + iwmap[20] = 15; + iwmap[10] = 5; + + auto iwi = iwmap.emplace(3, 4); + CHECK(iwi.second == true); + CHECK(iwi.first == iwmap.begin()); + + CHECK(iwmap.begin()->first.val == 3); + CHECK(iwmap.begin()->second == 4); + CHECK(iwmap.rbegin()->first.val == 20); + CHECK(iwmap.rbegin()->second == 15); + CHECK(iwmap.at(10) == 5); + + iwi = iwmap.insert(std::pair(11, 6)); + CHECK(iwi.second == true); + CHECK(iwi.first + 2 == iwmap.end()); + + CHECK(iwmap[11] == 6); + + iwi = iwmap.emplace(10, 55); + CHECK(iwi.second == false); + CHECK(iwi.first->second == 5); + + CHECK(iwmap.find(18) == iwmap.end()); + CHECK(iwmap.find(11) != iwmap.end()); + + const auto ciwmap = iwmap; + + CHECK(ciwmap.begin()->first.val == 3); + CHECK(ciwmap.begin()->second == 4); + CHECK(ciwmap.rbegin()->first.val == 20); + CHECK(ciwmap.rbegin()->second == 15); + CHECK(ciwmap.at(10) == 5); + + CHECK(ciwmap.find(18) == ciwmap.end()); + CHECK(ciwmap.find(11) != ciwmap.end()); + + // swap + flat_map m1, m2; + m1.reserve(10); + m1[1] = 2; + m1[2] = 5; + auto m1c = m1.capacity(); + + CHECK(m2.capacity() == 0); + m1.swap(m2); + + CHECK(m2.size() == 2); + CHECK(m2.capacity() == m1c); + CHECK(m1.capacity() == 0); + + // self usurp + m2 = m2; + CHECK(m2.size() == 2); + CHECK(m2.capacity() == m1c); +} + +#if defined(CHOBO_FLAT_MAP_TEST_STATIC_VECTOR_WITH_DOCTEST) + +TEST_CASE("[flat_map] static_vector test") +{ + using namespace chobo; + + flat_map, static_vector, 10>> smap; + CHECK(smap.empty()); + CHECK(smap.size() == 0); + CHECK(smap.capacity() == 10); + CHECK(smap.begin() == smap.end()); + + smap[1] = 3; + CHECK(smap.size() == 1); + + auto ifit = smap.begin(); + CHECK(ifit->first == 1); + CHECK(ifit->second == 3); + CHECK(smap[1] == 3); + CHECK(smap.at(1) == 3); + CHECK(smap.count(1) == 1); + CHECK(smap.count(5) == 0); + + ++ifit; + CHECK(ifit == smap.end()); + + auto res = smap.insert(std::make_pair(6, 3)); + CHECK(res.second); + CHECK(res.first == smap.begin() + 1); + + res = smap.emplace(3, 5); + CHECK(res.second); + CHECK(res.first == smap.begin() + 1); + + res = smap.emplace(6, 8); + CHECK(!res.second); + CHECK(res.first == smap.begin() + 2); + + smap[2] = 5; + smap[52] = 15; + smap[12] = 1; + CHECK(smap.size() == 6); + + auto cmp = [](const flat_map::value_type& a, const flat_map::value_type& b) -> bool + { + return a.first < b.first; + }; + + CHECK(std::is_sorted(smap.begin(), smap.end(), cmp)); + + smap.erase(12); + CHECK(smap.size() == 5); + + CHECK(std::is_sorted(smap.begin(), smap.end(), cmp)); + + ifit = smap.find(12); + CHECK(ifit == smap.end()); + + ifit = smap.find(6); + CHECK(ifit != smap.end()); + smap.erase(ifit); + + CHECK(smap.size() == 4); + CHECK(std::is_sorted(smap.begin(), smap.end(), cmp)); + ifit = smap.find(6); + CHECK(ifit == smap.end()); +} + +#endif + +#if defined(CHOBO_FLAT_MAP_TEST_VECTOR_PTR_WITH_DOCTEST) + +TEST_CASE("[flat_map] vector_ptr test") +{ + using namespace chobo; + flat_map, vector_ptr>> smap; + + std::vector> vec; + smap.modify_container().reset(&vec); + + smap[1] = '1'; + smap[3] = '3'; + + CHECK(smap.at(3) == '3'); + + auto smap2 = smap; + CHECK(smap2.size() == 2); + CHECK(smap2[1] == '1'); + CHECK(smap2.at(3) == '3'); + + smap2[0] = '0'; + + CHECK(smap.size() == 3); + CHECK(smap[0] == '0'); + + smap.clear(); + + CHECK(smap2.empty()); +} + +#endif + + +#endif + diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Containers/chobo/flat_set.hpp b/thirdparty/RmlUi/Include/RmlUi/Core/Containers/chobo/flat_set.hpp new file mode 100644 index 000000000..28676e92c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Containers/chobo/flat_set.hpp @@ -0,0 +1,561 @@ +// chobo-flat-set v1.00 +// +// std::set-like class with an underlying vector +// +// Unofficial, chobo-like container, largely based on chobo::flat_map +// +// MIT License: +// Copyright(c) 2019 Michael R. P. Ragazzon +// Copyright(c) 2016 Chobolabs Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files(the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and / or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions : +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// VERSION HISTORY +// +// 1.00 (2019-05-04) First public release +// +// +// DOCUMENTATION +// +// Simply include this file wherever you need. +// It defines the class chobo::flat_set, which is an almsot drop-in replacement +// of std::set. Flat set has an optional underlying container which by default +// is std::vector. Thus the items in the set are in a continuous block of +// memory. Thus iterating over the set is cache friendly, at the cost of +// O(n) for insert and erase. +// +// The elements inside (like in std::set) are kept in an order sorted by key. +// Getting a value by key is O(log2 n) +// +// It generally performs much faster than std::set for smaller sets of elements +// +// The difference with std::set, which makes flat_set an not-exactly-drop-in +// replacement is the last template argument: +// * std::set has +// * chobo::flat_set has +// The container must be an std::vector compatible type (chobo::static_vector +// and chobo::vector_ptr are, for example, viable). The container value type +// must be 'value'. +// +// Changing the allocator. +// +// If you want to change the allocator of flat set, you'll have to provide a +// container with the appriate one. Example: +// +// chobo::flat_set< +// string, +// less, +// std::vector<, MyAllocator> +// > myset +// +// +// Configuration +// +// chobo::flat_set has one configurable setting: +// +// 1. const char* overloads +// By default chobo::flat_set provides overloads for the access methods +// (at, operator[], find, lower_bound, count) for const char* for cases when +// std::string is the key, so that no allocations happen when accessing with +// a C-string of a string literal. +// However if const char* or any other class with implicit conversion from +// const char* is the key, they won't compile. +// If you plan on using flat_set with such keys, you'll need to define +// CHOBO_FLAT_SET_NO_CONST_CHAR_OVERLOADS before including the header +// +// +// TESTS +// +// The tests are included in the header file and use doctest (https://github.com/onqtam/doctest). +// To run them, define CHOBO_FLAT_SET_TEST_WITH_DOCTEST before including +// the header in a file which has doctest.h already included. +// +// Additionally if chobo::static_vector is also available you may define +// CHOBO_FLAT_SET_TEST_STATIC_VECTOR_WITH_DOCTEST to test flat_set with an +// unrelying static_vector +// +// Additionally if chobo::vector_ptr is also available you may define +// CHOBO_FLAT_SET_TEST_VECTOR_PTR_WITH_DOCTEST to test flat_set with an +// unrelying vector_ptr +// +#pragma once + +#include +#include +#include + +#if !defined(CHOBO_FLAT_SET_NO_CONST_CHAR_OVERLOADS) +#include +#endif + +namespace chobo +{ + +template , typename Container = std::vector> +class flat_set +{ +public: + typedef T key_type; + typedef T value_type; + typedef Container container_type; + typedef Compare key_compare; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef typename container_type::allocator_type allocator_type; + typedef typename std::allocator_traits::pointer pointer; + typedef typename std::allocator_traits::pointer const_pointer; + typedef typename container_type::iterator iterator; + typedef typename container_type::const_iterator const_iterator; + typedef typename container_type::reverse_iterator reverse_iterator; + typedef typename container_type::const_reverse_iterator const_reverse_iterator; + typedef typename container_type::difference_type difference_type; + typedef typename container_type::size_type size_type; + + flat_set() + {} + + explicit flat_set(const key_compare& comp, const allocator_type& alloc = allocator_type()) + : m_cmp(comp) + , m_container(alloc) + {} + + flat_set(const flat_set& x) = default; + flat_set(flat_set&& x) = default; + + + flat_set(std::initializer_list ilist) + { + m_container.reserve(ilist.size()); + for (auto&& il : ilist) + emplace(il); + } + + flat_set& operator=(const flat_set& x) + { + m_cmp = x.m_cmp; + m_container = x.m_container; + return *this; + } + flat_set& operator=(flat_set&& x) noexcept + { + m_cmp = std::move(x.m_cmp); + m_container = std::move(x.m_container); + return *this; + } + + iterator begin() noexcept { return m_container.begin(); } + const_iterator begin() const noexcept { return m_container.begin(); } + iterator end() noexcept { return m_container.end(); } + const_iterator end() const noexcept { return m_container.end(); } + reverse_iterator rbegin() noexcept { return m_container.rbegin(); } + const_reverse_iterator rbegin() const noexcept { return m_container.rbegin(); } + reverse_iterator rend() noexcept { return m_container.rend(); } + const_reverse_iterator rend() const noexcept { return m_container.rend(); } + const_iterator cbegin() const noexcept { return m_container.cbegin(); } + const_iterator cend() const noexcept { return m_container.cend(); } + + bool empty() const noexcept { return m_container.empty(); } + size_type size() const noexcept { return m_container.size(); } + size_type max_size() const noexcept { return m_container.max_size(); } + + void reserve(size_type count) { return m_container.reserve(count); } + size_type capacity() const noexcept { return m_container.capacity(); } + + void clear() noexcept { m_container.clear(); } + + iterator lower_bound(const key_type& k) + { + return std::lower_bound(m_container.begin(), m_container.end(), k, m_cmp); + } + + const_iterator lower_bound(const key_type& k) const + { + return std::lower_bound(m_container.begin(), m_container.end(), k, m_cmp); + } + + iterator find(const key_type& k) + { + auto i = lower_bound(k); + if (i != end() && !m_cmp(k, *i)) + return i; + + return end(); + } + + const_iterator find(const key_type& k) const + { + auto i = lower_bound(k); + if (i != end() && !m_cmp(k, *i)) + return i; + + return end(); + } + + size_t count(const key_type& k) const + { + return find(k) == end() ? 0 : 1; + } + + template + std::pair insert(P&& val) + { + auto i = lower_bound(val); + if (i != end() && !m_cmp(val, *i)) + { + return { i, false }; + } + + return{ m_container.emplace(i, std::forward

(val)), true }; + } + + template + void insert(InputIt first, InputIt last) + { + difference_type diff = std::distance(first, last); + if(diff > 0) reserve(size() + (size_t)diff); + for (auto it = first; it != last; ++it) + emplace(*it); + } + + template + std::pair emplace(Args&&... args) + { + value_type val(std::forward(args)...); + return insert(std::move(val)); + } + + iterator erase(const_iterator pos) + { + return m_container.erase(pos); + } + + size_type erase(const key_type& k) + { + auto i = find(k); + if (i == end()) + { + return 0; + } + + erase(i); + return 1; + } + + void swap(flat_set& x) + { + std::swap(m_cmp, x.m_cmp); + m_container.swap(x.m_container); + } + + const container_type& container() const noexcept + { + return m_container; + } + + // DANGER! If you're not careful with this function, you may irreversably break the set + container_type& modify_container() noexcept + { + return m_container; + } + +#if !defined(CHOBO_FLAT_SET_NO_CONST_CHAR_OVERLOADS) + /////////////////////////////////////////////////////////////////////////////////// + // const char* overloads for sets with an std::string key to avoid allocs + iterator lower_bound(const char* k) + { + static_assert(std::is_same::value, "flat_set::lower_bound(const char*) works only for std::strings"); + static_assert(std::is_same, key_compare>::value, "flat_set::lower_bound(const char*) works only for std::string-s, compared with std::less"); + return std::lower_bound(m_container.begin(), m_container.end(), k, [](const value_type& a, const char* b) -> bool + { + return strcmp(a.c_str(), b) < 0; + }); + } + + const_iterator lower_bound(const char* k) const + { + static_assert(std::is_same::value, "flat_set::lower_bound(const char*) works only for std::strings"); + static_assert(std::is_same, key_compare>::value, "flat_set::lower_bound(const char*) works only for std::string-s, compared with std::less"); + return std::lower_bound(m_container.begin(), m_container.end(), k, [](const value_type& a, const char* b) -> bool + { + return strcmp(a.c_str(), b) < 0; + }); + } + + iterator find(const char* k) + { + auto i = lower_bound(k); + if (i != end() && *i == k) + return i; + + return end(); + } + + const_iterator find(const char* k) const + { + auto i = lower_bound(k); + if (i != end() && *i == k) + return i; + + return end(); + } + + size_t count(const char* k) const + { + return find(k) == end() ? 0 : 1; + } + +#endif // !defined(CHOBO_FLAT_SET_NO_CONST_CHAR_OVERLOADS) + +private: + key_compare m_cmp; + container_type m_container; +}; + +template +bool operator==(const flat_set& a, const flat_set& b) +{ + return a.container() == b.container(); +} +template +bool operator!=(const flat_set& a, const flat_set& b) +{ + return a.container() != b.container(); +} +template +bool operator<(const flat_set& a, const flat_set& b) +{ + return a.container() < b.container(); +} + +} + +#if defined(CHOBO_FLAT_SET_TEST_WITH_DOCTEST) + +#include + +namespace chobo_flat_set_test +{ + +// struct with no operator== +struct int_wrap +{ + int_wrap() = default; + int_wrap(int i) : val(i) {} + int val; + + struct compare + { + bool operator()(const int_wrap& a, const int_wrap& b) const + { + return a.val < b.val; + } + }; +}; + +} + +TEST_CASE("[flat_set] test") +{ + using namespace chobo; + using namespace chobo_flat_set_test; + + flat_set iset; + CHECK(iset.empty()); + CHECK(iset.size() == 0); + CHECK(iset.capacity() == 0); + CHECK(iset.begin() == iset.end()); + + iset.insert(3); + CHECK(iset.size() == 1); + + auto iit = iset.begin(); + CHECK(*iit == 3); + CHECK(iset.count(3) == 1); + CHECK(iset.count(5) == 0); + + ++iit; + CHECK(iit == iset.end()); + + auto res = iset.insert(6); + CHECK(res.second); + CHECK(res.first == iset.begin() + 1); + + res = iset.emplace(4); + CHECK(res.second); + CHECK(res.first == iset.begin() + 1); + + res = iset.emplace(6); + CHECK(!res.second); + CHECK(res.first == iset.begin() + 2); + + iset.emplace(3); + CHECK(iset.size() == 3); + iset.emplace(9); + iset.insert(9); + iset.emplace(12); + CHECK(iset.size() == 5); + + auto cmp = [](const flat_set::value_type& a, const flat_set::value_type& b) -> bool + { + return a < b; + }; + + CHECK(std::is_sorted(iset.begin(), iset.end(), cmp)); + + iset.erase(12); + CHECK(iset.size() == 4); + + CHECK(std::is_sorted(iset.begin(), iset.end(), cmp)); + + iit = iset.find(11); + CHECK(iit == iset.end()); + + iit = iset.find(6); + CHECK(iit != iset.end()); + iset.erase(iit); + + CHECK(iset.size() == 3); + CHECK(std::is_sorted(iset.begin(), iset.end(), cmp)); + iit = iset.find(6); + CHECK(iit == iset.end()); + + // + + flat_set sset; + + CHECK(sset.find("123") == sset.end()); + sset.emplace("123"); + CHECK(*sset.begin() == "123"); + + sset.emplace("asd"); + + auto sit = sset.find("asd"); + CHECK(sit != sset.end()); + CHECK(sit == sset.begin() + 1); + + CHECK(sset.count("bababa") == 0); + CHECK(sset.count("asd") == 1); + + std::string asd = "asd"; + CHECK(sset.find(asd) == sset.find("asd")); + + sset.emplace("0The quick brown fox jumps over the lazy dog"); + CHECK(sset.begin()->at(1) == 'T'); + const void* cstr = sset.begin()->c_str(); + + auto sset2 = std::move(sset); + CHECK(sset.empty()); + CHECK(sset2.begin()->c_str() == cstr); + + sset = std::move(sset2); + CHECK(sset2.empty()); + CHECK(sset.begin()->c_str() == cstr); + + CHECK(sset2 != sset); + sset2 = sset; + CHECK(sset2 == sset); + + // no == comparable tests + flat_set iwset; + iwset.emplace(5); + iwset.emplace(20); + iwset.emplace(10); + + auto iwi = iwset.emplace(3); + CHECK(iwi.second == true); + CHECK(iwi.first == iwset.begin()); + + CHECK(iwset.begin()->val == 3); + CHECK(iwset.rbegin()->val == 20); + + iwi = iwset.insert(int_wrap(11)); + CHECK(iwi.second == true); + CHECK(iwi.first + 2 == iwset.end()); + + iwi = iwset.emplace(int_wrap(10)); + CHECK(iwi.second == false); + + CHECK(iwset.find(18) == iwset.end()); + CHECK(iwset.find(11) != iwset.end()); + + const auto ciwset = iwset; + + CHECK(ciwset.begin()->val == 3); + CHECK(ciwset.rbegin()->val == 20); + + CHECK(ciwset.find(18) == ciwset.end()); + CHECK(ciwset.find(11) != ciwset.end()); + + // swap + flat_set m1, m2; + m1.reserve(10); + m1.emplace(1); + m1.emplace(2); + auto m1c = m1.capacity(); + + CHECK(m2.capacity() == 0); + m1.swap(m2); + + CHECK(m2.size() == 2); + CHECK(m2.capacity() == m1c); + CHECK(m1.capacity() == 0); + + // self usurp + m2 = m2; + CHECK(m2.size() == 2); + CHECK(m2.capacity() == m1c); + + + // initializer list + flat_set ilset = { "hello", "great", "magnificent", "world", "hello", "again" }; + CHECK(ilset.size() == 5); + CHECK(std::is_sorted(ilset.begin(), ilset.end())); + + ilset = { "b", "a" }; + CHECK(ilset.size() == 2); + CHECK(std::is_sorted(ilset.begin(), ilset.end())); +} + +#if defined(CHOBO_FLAT_SET_TEST_STATIC_VECTOR_WITH_DOCTEST) + +TEST_CASE("[flat_set] static_vector test") +{ + using namespace chobo; + + // Not implemented +} + +#endif + +#if defined(CHOBO_FLAT_SET_TEST_VECTOR_PTR_WITH_DOCTEST) + +TEST_CASE("[flat_set] vector_ptr test") +{ + using namespace chobo; + + // Not implemented +} + +#endif + + +#endif + diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Containers/robin_hood.h b/thirdparty/RmlUi/Include/RmlUi/Core/Containers/robin_hood.h new file mode 100644 index 000000000..4e93d6817 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Containers/robin_hood.h @@ -0,0 +1,2194 @@ +// ______ _____ ______ _________ +// ______________ ___ /_ ___(_)_______ ___ /_ ______ ______ ______ / +// __ ___/_ __ \__ __ \__ / __ __ \ __ __ \_ __ \_ __ \_ __ / +// _ / / /_/ /_ /_/ /_ / _ / / / _ / / // /_/ // /_/ // /_/ / +// /_/ \____/ /_.___/ /_/ /_/ /_/ ________/_/ /_/ \____/ \____/ \__,_/ +// _/_____/ +// +// Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20 +// version 3.5.0 +// https://github.com/martinus/robin-hood-hashing +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2018-2020 Martin Ankerl +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef ROBIN_HOOD_H_INCLUDED +#define ROBIN_HOOD_H_INCLUDED + +// see https://semver.org/ +#define ROBIN_HOOD_VERSION_MAJOR 3 // for incompatible API changes +#define ROBIN_HOOD_VERSION_MINOR 5 // for adding functionality in a backwards-compatible manner +#define ROBIN_HOOD_VERSION_PATCH 0 // for backwards-compatible bug fixes + +#include +#include +#include +#include +#include +#include +#include +#include + +// #define ROBIN_HOOD_LOG_ENABLED +#ifdef ROBIN_HOOD_LOG_ENABLED +# include +# define ROBIN_HOOD_LOG(x) std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl +#else +# define ROBIN_HOOD_LOG(x) +#endif + +// #define ROBIN_HOOD_TRACE_ENABLED +#ifdef ROBIN_HOOD_TRACE_ENABLED +# include +# define ROBIN_HOOD_TRACE(x) \ + std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << x << std::endl +#else +# define ROBIN_HOOD_TRACE(x) +#endif + +// #define ROBIN_HOOD_COUNT_ENABLED +#ifdef ROBIN_HOOD_COUNT_ENABLED +# include +# define ROBIN_HOOD_COUNT(x) ++counts().x; +namespace robin_hood { +struct Counts { + uint64_t shiftUp{}; + uint64_t shiftDown{}; +}; +inline std::ostream& operator<<(std::ostream& os, Counts const& c) { + return os << c.shiftUp << " shiftUp" << std::endl << c.shiftDown << " shiftDown" << std::endl; +} + +static Counts& counts() { + static Counts counts{}; + return counts; +} +} // namespace robin_hood +#else +# define ROBIN_HOOD_COUNT(x) +#endif + +// all non-argument macros should use this facility. See +// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/ +#define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x() + +// mark unused members with this macro +#define ROBIN_HOOD_UNUSED(identifier) + +// bitness +#if SIZE_MAX == UINT32_MAX +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32 +#elif SIZE_MAX == UINT64_MAX +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64 +#else +# error Unsupported bitness +#endif + +// endianess +#ifdef _MSC_VER +# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1 +# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0 +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#endif + +// inline +#ifdef _MSC_VER +# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline) +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline)) +#endif + +// exceptions +#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND) +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0 +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1 +#endif + +// count leading/trailing bits +#ifdef _MSC_VER +# if ROBIN_HOOD(BITNESS) == 32 +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward +# else +# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64 +# endif +# include +# pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD)) +# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \ + [](size_t mask) noexcept -> int { \ + unsigned long index; \ + return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast(index) \ + : ROBIN_HOOD(BITNESS); \ + }(x) +#else +# if ROBIN_HOOD(BITNESS) == 32 +# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl +# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl +# else +# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll +# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll +# endif +# define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS)) +# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS)) +#endif + +// fallthrough +#ifndef __has_cpp_attribute // For backwards compatibility +# define __has_cpp_attribute(x) 0 +#endif +#if __has_cpp_attribute(clang::fallthrough) +# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]] +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() +#endif + +// likely/unlikely +#ifdef _MSC_VER +# define ROBIN_HOOD_LIKELY(condition) condition +# define ROBIN_HOOD_UNLIKELY(condition) condition +#else +# define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1) +# define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0) +#endif + +// workaround missing "is_trivially_copyable" in g++ < 5.0 +// See https://stackoverflow.com/a/31798726/48181 +#if defined(__GNUC__) && __GNUC__ < 5 +# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__) +#else +# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value +#endif + +// helpers for C++ versions, see https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L +#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L + +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17) +# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]] +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() +#endif + +namespace robin_hood { + +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14) +# define ROBIN_HOOD_STD std +#else + +// c++11 compatibility layer +namespace ROBIN_HOOD_STD { +template +struct alignment_of + : std::integral_constant::type)> {}; + +template +class integer_sequence { +public: + using value_type = T; + static_assert(std::is_integral::value, "not integral type"); + static constexpr std::size_t size() noexcept { + return sizeof...(Ints); + } +}; +template +using index_sequence = integer_sequence; + +namespace detail_ { +template +struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)"); + + template + struct IntSeqCombiner; + + template + struct IntSeqCombiner, integer_sequence> { + using TResult = integer_sequence; + }; + + using TResult = + typename IntSeqCombiner::TResult, + typename IntSeqImpl::TResult>::TResult; +}; + +template +struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence; +}; + +template +struct IntSeqImpl { + using TValue = T; + static_assert(std::is_integral::value, "not integral type"); + static_assert(Begin >= 0, "unexpected argument (Begin<0)"); + using TResult = integer_sequence; +}; +} // namespace detail_ + +template +using make_integer_sequence = typename detail_::IntSeqImpl::TResult; + +template +using make_index_sequence = make_integer_sequence; + +template +using index_sequence_for = make_index_sequence; + +} // namespace ROBIN_HOOD_STD + +#endif + +namespace detail { + +// umul +#if defined(__SIZEOF_INT128__) +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_UMUL128() 1 +# if defined(__GNUC__) || defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +using uint128_t = unsigned __int128; +# pragma GCC diagnostic pop +# endif +inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high) noexcept { + auto result = static_cast(a) * static_cast(b); + *high = static_cast(result >> 64U); + return static_cast(result); +} +#elif (defined(_MSC_VER) && ROBIN_HOOD(BITNESS) == 64) +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_UMUL128() 1 +# include // for __umulh +# pragma intrinsic(__umulh) +# ifndef _M_ARM64 +# pragma intrinsic(_umul128) +# endif +inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high) noexcept { +# ifdef _M_ARM64 + *high = __umulh(a, b); + return ((uint64_t)(a)) * (b); +# else + return _umul128(a, b, high); +# endif +} +#else +# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_UMUL128() 0 +#endif + +// This cast gets rid of warnings like "cast from 'uint8_t*' {aka 'unsigned char*'} to +// 'uint64_t*' {aka 'long unsigned int*'} increases required alignment of target type". Use with +// care! +template +inline T reinterpret_cast_no_cast_align_warning(void* ptr) noexcept { + return reinterpret_cast(ptr); +} + +template +inline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept { + return reinterpret_cast(ptr); +} + +// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other +// inlinings more difficult. Throws are also generally the slow path. +template +ROBIN_HOOD(NOINLINE) +#if ROBIN_HOOD(HAS_EXCEPTIONS) +void doThrow(Args&&... args) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) + throw E(std::forward(args)...); +} +#else +void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) { + abort(); +} // namespace Rml +#endif + +template +T* assertNotNull(T* t, Args&&... args) { + if (ROBIN_HOOD_UNLIKELY(nullptr == t)) { + doThrow(std::forward(args)...); + } + return t; +} + +template +inline T unaligned_load(void const* ptr) noexcept { + // using memcpy so we don't get into unaligned load problems. + // compiler should optimize this very well anyways. + T t; + std::memcpy(&t, ptr, sizeof(T)); + return t; +} + +// Allocates bulks of memory for objects of type T. This deallocates the memory in the destructor, +// and keeps a linked list of the allocated memory around. Overhead per allocation is the size of a +// pointer. +template +class BulkPoolAllocator { +public: + BulkPoolAllocator() noexcept = default; + + // does not copy anything, just creates a new allocator. + BulkPoolAllocator(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept + : mHead(nullptr) + , mListForFree(nullptr) {} + + BulkPoolAllocator(BulkPoolAllocator&& o) noexcept + : mHead(o.mHead) + , mListForFree(o.mListForFree) { + o.mListForFree = nullptr; + o.mHead = nullptr; + } + + BulkPoolAllocator& operator=(BulkPoolAllocator&& o) noexcept { + reset(); + mHead = o.mHead; + mListForFree = o.mListForFree; + o.mListForFree = nullptr; + o.mHead = nullptr; + return *this; + } + + BulkPoolAllocator& + // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp) + operator=(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept { + // does not do anything + return *this; + } + + ~BulkPoolAllocator() noexcept { + reset(); + } + + // Deallocates all allocated memory. + void reset() noexcept { + while (mListForFree) { + T* tmp = *mListForFree; + free(mListForFree); + mListForFree = reinterpret_cast_no_cast_align_warning(tmp); + } + mHead = nullptr; + } + + // allocates, but does NOT initialize. Use in-place new constructor, e.g. + // T* obj = pool.allocate(); + // ::new (static_cast(obj)) T(); + T* allocate() { + T* tmp = mHead; + if (!tmp) { + tmp = performAllocation(); + } + + mHead = *reinterpret_cast_no_cast_align_warning(tmp); + return tmp; + } + + // does not actually deallocate but puts it in store. + // make sure you have already called the destructor! e.g. with + // obj->~T(); + // pool.deallocate(obj); + void deallocate(T* obj) noexcept { + *reinterpret_cast_no_cast_align_warning(obj) = mHead; + mHead = obj; + } + + // Adds an already allocated block of memory to the allocator. This allocator is from now on + // responsible for freeing the data (with free()). If the provided data is not large enough to + // make use of, it is immediately freed. Otherwise it is reused and freed in the destructor. + void addOrFree(void* ptr, const size_t numBytes) noexcept { + // calculate number of available elements in ptr + if (numBytes < ALIGNMENT + ALIGNED_SIZE) { + // not enough data for at least one element. Free and return. + free(ptr); + } else { + add(ptr, numBytes); + } + } + + void swap(BulkPoolAllocator& other) noexcept { + using std::swap; + swap(mHead, other.mHead); + swap(mListForFree, other.mListForFree); + } + +private: + // iterates the list of allocated memory to calculate how many to alloc next. + // Recalculating this each time saves us a size_t member. + // This ignores the fact that memory blocks might have been added manually with addOrFree. In + // practice, this should not matter much. + ROBIN_HOOD(NODISCARD) size_t calcNumElementsToAlloc() const noexcept { + auto tmp = mListForFree; + size_t numAllocs = MinNumAllocs; + + while (numAllocs * 2 <= MaxNumAllocs && tmp) { + auto x = reinterpret_cast(tmp); + tmp = *x; + numAllocs *= 2; + } + + return numAllocs; + } + + // WARNING: Underflow if numBytes < ALIGNMENT! This is guarded in addOrFree(). + void add(void* ptr, const size_t numBytes) noexcept { + const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE; + + auto data = reinterpret_cast(ptr); + + // link free list + auto x = reinterpret_cast(data); + *x = mListForFree; + mListForFree = data; + + // create linked list for newly allocated data + auto const headT = + reinterpret_cast_no_cast_align_warning(reinterpret_cast(ptr) + ALIGNMENT); + + auto const head = reinterpret_cast(headT); + + // Visual Studio compiler automatically unrolls this loop, which is pretty cool + for (size_t i = 0; i < numElements; ++i) { + *reinterpret_cast_no_cast_align_warning(head + i * ALIGNED_SIZE) = + head + (i + 1) * ALIGNED_SIZE; + } + + // last one points to 0 + *reinterpret_cast_no_cast_align_warning(head + (numElements - 1) * ALIGNED_SIZE) = + mHead; + mHead = headT; + } + + // Called when no memory is available (mHead == 0). + // Don't inline this slow path. + ROBIN_HOOD(NOINLINE) T* performAllocation() { + size_t const numElementsToAlloc = calcNumElementsToAlloc(); + + // alloc new memory: [prev |T, T, ... T] + // std::cout << (sizeof(T*) + ALIGNED_SIZE * numElementsToAlloc) << " bytes" << std::endl; + size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc; + add(assertNotNull(malloc(bytes)), bytes); + return mHead; + } + + // enforce byte alignment of the T's +#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14) + static constexpr size_t ALIGNMENT = + (std::max)(std::alignment_of::value, std::alignment_of::value); +#else + static const size_t ALIGNMENT = + (ROBIN_HOOD_STD::alignment_of::value > ROBIN_HOOD_STD::alignment_of::value) + ? ROBIN_HOOD_STD::alignment_of::value + : +ROBIN_HOOD_STD::alignment_of::value; // the + is for walkarround +#endif + + static constexpr size_t ALIGNED_SIZE = ((sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT; + + static_assert(MinNumAllocs >= 1, "MinNumAllocs"); + static_assert(MaxNumAllocs >= MinNumAllocs, "MaxNumAllocs"); + static_assert(ALIGNED_SIZE >= sizeof(T*), "ALIGNED_SIZE"); + static_assert(0 == (ALIGNED_SIZE % sizeof(T*)), "ALIGNED_SIZE mod"); + static_assert(ALIGNMENT >= sizeof(T*), "ALIGNMENT"); + + T* mHead{nullptr}; + T** mListForFree{nullptr}; +}; + +template +struct NodeAllocator; + +// dummy allocator that does nothing +template +struct NodeAllocator { + + // we are not using the data, so just free it. + void addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept { + free(ptr); + } +}; + +template +struct NodeAllocator : public BulkPoolAllocator {}; + +// dummy hash, unsed as mixer when robin_hood::hash is already used +template +struct identity_hash { + constexpr size_t operator()(T const& obj) const noexcept { + return static_cast(obj); + } +}; + +// c++14 doesn't have is_nothrow_swappable, and clang++ 6.0.1 doesn't like it either, so I'm making +// my own here. +namespace swappable { +using std::swap; +template +struct nothrow { + static const bool value = noexcept(swap(std::declval(), std::declval())); +}; + +} // namespace swappable + +} // namespace detail + +struct is_transparent_tag {}; + +// A custom pair implementation is used in the map because std::pair is not is_trivially_copyable, +// which means it would not be allowed to be used in std::memcpy. This struct is copyable, which is +// also tested. +template +struct pair { + using first_type = T1; + using second_type = T2; + + template ::value && + std::is_default_constructible::value>::type> + constexpr pair() noexcept(noexcept(U1()) && noexcept(U2())) + : first() + , second() {} + + // pair constructors are explicit so we don't accidentally call this ctor when we don't have to. + explicit constexpr pair(std::pair const& o) noexcept( + noexcept(T1(std::declval())) && noexcept(T2(std::declval()))) + : first(o.first) + , second(o.second) {} + + // pair constructors are explicit so we don't accidentally call this ctor when we don't have to. + explicit constexpr pair(std::pair&& o) noexcept( + noexcept(T1(std::move(std::declval()))) && + noexcept(T2(std::move(std::declval())))) + : first(std::move(o.first)) + , second(std::move(o.second)) {} + + constexpr pair(T1&& a, T2&& b) noexcept(noexcept(T1(std::move(std::declval()))) && + noexcept(T2(std::move(std::declval())))) + : first(std::move(a)) + , second(std::move(b)) {} + + template + constexpr pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward(std::declval()))) && + noexcept(T2(std::forward(std::declval())))) + : first(std::forward(a)) + , second(std::forward(b)) {} + + template + constexpr pair( + std::piecewise_construct_t /*unused*/, std::tuple a, + std::tuple b) noexcept(noexcept(pair(std::declval&>(), + std::declval&>(), + ROBIN_HOOD_STD::index_sequence_for(), + ROBIN_HOOD_STD::index_sequence_for()))) + : pair(a, b, ROBIN_HOOD_STD::index_sequence_for(), + ROBIN_HOOD_STD::index_sequence_for()) {} + + // constructor called from the std::piecewise_construct_t ctor + template + pair(std::tuple& a, std::tuple& b, + ROBIN_HOOD_STD::index_sequence /*unused*/, + ROBIN_HOOD_STD::index_sequence< + I2...> /*unused*/) noexcept(noexcept(T1(std:: + forward(std::get( + std::declval< + std::tuple&>()))...)) && + noexcept(T2(std::forward( + std::get(std::declval&>()))...))) + : first(std::forward(std::get(a))...) + , second(std::forward(std::get(b))...) { + // make visual studio compiler happy about warning about unused a & b. + // Visual studio's pair implementation disables warning 4100. + (void)a; + (void)b; + } + + ROBIN_HOOD(NODISCARD) first_type& getFirst() noexcept { + return first; + } + ROBIN_HOOD(NODISCARD) first_type const& getFirst() const noexcept { + return first; + } + ROBIN_HOOD(NODISCARD) second_type& getSecond() noexcept { + return second; + } + ROBIN_HOOD(NODISCARD) second_type const& getSecond() const noexcept { + return second; + } + + void swap(pair& o) noexcept((detail::swappable::nothrow::value) && + (detail::swappable::nothrow::value)) { + using std::swap; + swap(first, o.first); + swap(second, o.second); + } + + T1 first; // NOLINT(misc-non-private-member-variables-in-classes) + T2 second; // NOLINT(misc-non-private-member-variables-in-classes) +}; + +template +void swap(pair& a, pair& b) noexcept( + noexcept(std::declval&>().swap(std::declval&>()))) { + a.swap(b); +} + +// Hash an arbitrary amount of bytes. This is basically Murmur2 hash without caring about big +// endianness. TODO(martinus) add a fallback for very large strings? +static size_t hash_bytes(void const* ptr, size_t const len) noexcept { + static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995); + static constexpr uint64_t seed = UINT64_C(0xe17a1465); + static constexpr unsigned int r = 47; + + auto const data64 = static_cast(ptr); + uint64_t h = seed ^ (len * m); + + size_t const n_blocks = len / 8; + for (size_t i = 0; i < n_blocks; ++i) { + auto k = detail::unaligned_load(data64 + i); + + k *= m; + k ^= k >> r; + k *= m; + + h ^= k; + h *= m; + } + + auto const data8 = reinterpret_cast(data64 + n_blocks); + switch (len & 7U) { + case 7: + h ^= static_cast(data8[6]) << 48U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 6: + h ^= static_cast(data8[5]) << 40U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 5: + h ^= static_cast(data8[4]) << 32U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 4: + h ^= static_cast(data8[3]) << 24U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 3: + h ^= static_cast(data8[2]) << 16U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 2: + h ^= static_cast(data8[1]) << 8U; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + case 1: + h ^= static_cast(data8[0]); + h *= m; + ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH + default: + break; + } + + h ^= h >> r; + h *= m; + h ^= h >> r; + return static_cast(h); +} + +inline size_t hash_int(uint64_t obj) noexcept { +#if ROBIN_HOOD(HAS_UMUL128) + // 167079903232 masksum, 120428523 ops best: 0xde5fb9d2630458e9 + static constexpr uint64_t k = UINT64_C(0xde5fb9d2630458e9); + uint64_t h; + uint64_t l = detail::umul128(obj, k, &h); + return h + l; +#elif ROBIN_HOOD(BITNESS) == 32 + uint64_t const r = obj * UINT64_C(0xca4bcaa75ec3f625); + auto h = static_cast(r >> 32U); + auto l = static_cast(r); + return h + l; +#else + // murmurhash 3 finalizer + uint64_t h = obj; + h ^= h >> 33; + h *= 0xff51afd7ed558ccd; + h ^= h >> 33; + h *= 0xc4ceb9fe1a85ec53; + h ^= h >> 33; + return static_cast(h); +#endif +} + +// A thin wrapper around std::hash, performing an additional simple mixing step of the result. +template +struct hash : public std::hash { + size_t operator()(T const& obj) const + noexcept(noexcept(std::declval>().operator()(std::declval()))) { + // call base hash + auto result = std::hash::operator()(obj); + // return mixed of that, to be save against identity has + return hash_int(static_cast(result)); + } +}; + +template <> +struct hash { + size_t operator()(std::string const& str) const noexcept { + return hash_bytes(str.data(), str.size()); + } +}; + +template +struct hash { + size_t operator()(T* ptr) const noexcept { + return hash_int(reinterpret_cast(ptr)); + } +}; + +#define ROBIN_HOOD_HASH_INT(T) \ + template <> \ + struct hash { \ + size_t operator()(T obj) const noexcept { \ + return hash_int(static_cast(obj)); \ + } \ + } + +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wuseless-cast" +#endif +// see https://en.cppreference.com/w/cpp/utility/hash +ROBIN_HOOD_HASH_INT(bool); +ROBIN_HOOD_HASH_INT(char); +ROBIN_HOOD_HASH_INT(signed char); +ROBIN_HOOD_HASH_INT(unsigned char); +ROBIN_HOOD_HASH_INT(char16_t); +ROBIN_HOOD_HASH_INT(char32_t); +ROBIN_HOOD_HASH_INT(wchar_t); +ROBIN_HOOD_HASH_INT(short); +ROBIN_HOOD_HASH_INT(unsigned short); +ROBIN_HOOD_HASH_INT(int); +ROBIN_HOOD_HASH_INT(unsigned int); +ROBIN_HOOD_HASH_INT(long); +ROBIN_HOOD_HASH_INT(long long); +ROBIN_HOOD_HASH_INT(unsigned long); +ROBIN_HOOD_HASH_INT(unsigned long long); +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic pop +#endif +namespace detail { + +// using wrapper classes for hash and key_equal prevents the diamond problem when the same type is +// used. see https://stackoverflow.com/a/28771920/48181 +template +struct WrapHash : public T { + WrapHash() = default; + explicit WrapHash(T const& o) noexcept(noexcept(T(std::declval()))) + : T(o) {} +}; + +template +struct WrapKeyEqual : public T { + WrapKeyEqual() = default; + explicit WrapKeyEqual(T const& o) noexcept(noexcept(T(std::declval()))) + : T(o) {} +}; + +// A highly optimized hashmap implementation, using the Robin Hood algorithm. +// +// In most cases, this map should be usable as a drop-in replacement for std::unordered_map, but be +// about 2x faster in most cases and require much less allocations. +// +// This implementation uses the following memory layout: +// +// [Node, Node, ... Node | info, info, ... infoSentinel ] +// +// * Node: either a DataNode that directly has the std::pair as member, +// or a DataNode with a pointer to std::pair. Which DataNode representation to use +// depends on how fast the swap() operation is. Heuristically, this is automatically choosen based +// on sizeof(). there are always 2^n Nodes. +// +// * info: Each Node in the map has a corresponding info byte, so there are 2^n info bytes. +// Each byte is initialized to 0, meaning the corresponding Node is empty. Set to 1 means the +// corresponding node contains data. Set to 2 means the corresponding Node is filled, but it +// actually belongs to the previous position and was pushed out because that place is already +// taken. +// +// * infoSentinel: Sentinel byte set to 1, so that iterator's ++ can stop at end() without the need +// for a idx +// variable. +// +// According to STL, order of templates has effect on throughput. That's why I've moved the boolean +// to the front. +// https://www.reddit.com/r/cpp/comments/ahp6iu/compile_time_binary_size_reductions_and_cs_future/eeguck4/ +template +class Table : public WrapHash, + public WrapKeyEqual, + detail::NodeAllocator< + typename std::conditional< + std::is_void::value, Key, + robin_hood::pair::type, + T>>::type, + 4, 16384, IsFlatMap> { +public: + using key_type = Key; + using mapped_type = T; + using value_type = typename std::conditional< + std::is_void::value, Key, + robin_hood::pair::type, T>>::type; + using size_type = size_t; + using hasher = Hash; + using key_equal = KeyEqual; + using Self = Table; + static constexpr bool is_flat_map = IsFlatMap; + +private: + static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100, + "MaxLoadFactor100 needs to be >10 && < 100"); + + using WHash = WrapHash; + using WKeyEqual = WrapKeyEqual; + + // configuration defaults + + // make sure we have 8 elements, needed to quickly rehash mInfo + static constexpr size_t InitialNumElements = sizeof(uint64_t); + static constexpr uint32_t InitialInfoNumBits = 5; + static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits; + static constexpr uint8_t InitialInfoHashShift = sizeof(size_t) * 8 - InitialInfoNumBits; + using DataPool = detail::NodeAllocator; + + // type needs to be wider than uint8_t. + using InfoType = uint32_t; + + // DataNode //////////////////////////////////////////////////////// + + // Primary template for the data node. We have special implementations for small and big + // objects. For large objects it is assumed that swap() is fairly slow, so we allocate these on + // the heap so swap merely swaps a pointer. + template + class DataNode {}; + + // Small: just allocate on the stack. + template + class DataNode final { + public: + template + explicit DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, Args&&... args) noexcept( + noexcept(value_type(std::forward(args)...))) + : mData(std::forward(args)...) {} + + DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode&& n) noexcept( + std::is_nothrow_move_constructible::value) + : mData(std::move(n.mData)) {} + + // doesn't do anything + void destroy(M& ROBIN_HOOD_UNUSED(map) /*unused*/) noexcept {} + void destroyDoNotDeallocate() noexcept {} + + value_type const* operator->() const noexcept { + return &mData; + } + value_type* operator->() noexcept { + return &mData; + } + + const value_type& operator*() const noexcept { + return mData; + } + + value_type& operator*() noexcept { + return mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, typename V::first_type&>::type + getFirst() noexcept { + return mData.first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, V&>::type getFirst() noexcept { + return mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, typename V::first_type const&>::type + getFirst() const noexcept { + return mData.first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, V const&>::type getFirst() const noexcept { + return mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, Q&>::type getSecond() noexcept { + return mData.second; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, Q const&>::type getSecond() const + noexcept { + return mData.second; + } + + void swap(DataNode& o) noexcept( + noexcept(std::declval().swap(std::declval()))) { + mData.swap(o.mData); + } + + private: + value_type mData; + }; + + // big object: allocate on heap. + template + class DataNode { + public: + template + explicit DataNode(M& map, Args&&... args) + : mData(map.allocate()) { + ::new (static_cast(mData)) value_type(std::forward(args)...); + } + + DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode&& n) noexcept + : mData(std::move(n.mData)) {} + + void destroy(M& map) noexcept { + // don't deallocate, just put it into list of datapool. + mData->~value_type(); + map.deallocate(mData); + } + + void destroyDoNotDeallocate() noexcept { + mData->~value_type(); + } + + value_type const* operator->() const noexcept { + return mData; + } + + value_type* operator->() noexcept { + return mData; + } + + const value_type& operator*() const { + return *mData; + } + + value_type& operator*() { + return *mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, typename V::first_type&>::type + getFirst() noexcept { + return mData->first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, V&>::type getFirst() noexcept { + return *mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, typename V::first_type const&>::type + getFirst() const noexcept { + return mData->first; + } + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, V const&>::type getFirst() const noexcept { + return *mData; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, Q&>::type getSecond() noexcept { + return mData->second; + } + + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, Q const&>::type getSecond() const + noexcept { + return mData->second; + } + + void swap(DataNode& o) noexcept { + using std::swap; + swap(mData, o.mData); + } + + private: + value_type* mData; + }; + + using Node = DataNode; + + // helpers for doInsert: extract first entry (only const required) + ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(Node const& n) const noexcept { + return n.getFirst(); + } + + // in case we have void mapped_type, we are not using a pair, thus we just route k through. + // No need to disable this because it's just not used if not applicable. + ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(key_type const& k) const noexcept { + return k; + } + + // in case we have non-void mapped_type, we have a standard robin_hood::pair + template + ROBIN_HOOD(NODISCARD) + typename std::enable_if::value, key_type const&>::type + getFirstConst(value_type const& vt) const noexcept { + return vt.first; + } + + // Cloner ////////////////////////////////////////////////////////// + + template + struct Cloner; + + // fast path: Just copy data, without allocating anything. + template + struct Cloner { + void operator()(M const& source, M& target) const { + auto src = reinterpret_cast(source.mKeyVals); + auto tgt = reinterpret_cast(target.mKeyVals); + auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1); + std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt); + } + }; + + template + struct Cloner { + void operator()(M const& s, M& t) const { + auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1); + std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo); + + for (size_t i = 0; i < numElementsWithBuffer; ++i) { + if (t.mInfo[i]) { + ::new (static_cast(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]); + } + } + } + }; + + // Destroyer /////////////////////////////////////////////////////// + + template + struct Destroyer {}; + + template + struct Destroyer { + void nodes(M& m) const noexcept { + m.mNumElements = 0; + } + + void nodesDoNotDeallocate(M& m) const noexcept { + m.mNumElements = 0; + } + }; + + template + struct Destroyer { + void nodes(M& m) const noexcept { + m.mNumElements = 0; + // clear also resets mInfo to 0, that's sometimes not necessary. + auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1); + + for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) { + if (0 != m.mInfo[idx]) { + Node& n = m.mKeyVals[idx]; + n.destroy(m); + n.~Node(); + } + } + } + + void nodesDoNotDeallocate(M& m) const noexcept { + m.mNumElements = 0; + // clear also resets mInfo to 0, that's sometimes not necessary. + auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1); + for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) { + if (0 != m.mInfo[idx]) { + Node& n = m.mKeyVals[idx]; + n.destroyDoNotDeallocate(); + n.~Node(); + } + } + } + }; + + // Iter //////////////////////////////////////////////////////////// + + struct fast_forward_tag {}; + + // generic iterator for both const_iterator and iterator. + template + // NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions) + class Iter { + private: + using NodePtr = typename std::conditional::type; + + public: + using difference_type = std::ptrdiff_t; + using value_type = typename Self::value_type; + using reference = typename std::conditional::type; + using pointer = typename std::conditional::type; + using iterator_category = std::forward_iterator_tag; + + // default constructed iterator can be compared to itself, but WON'T return true when + // compared to end(). + Iter() = default; + + // Rule of zero: nothing specified. The conversion constructor is only enabled for iterator + // to const_iterator, so it doesn't accidentally work as a copy ctor. + + // Conversion constructor from iterator to const_iterator. + template ::type> + // NOLINTNEXTLINE(hicpp-explicit-conversions) + Iter(Iter const& other) noexcept + : mKeyVals(other.mKeyVals) + , mInfo(other.mInfo) {} + + Iter(NodePtr valPtr, uint8_t const* infoPtr) noexcept + : mKeyVals(valPtr) + , mInfo(infoPtr) {} + + Iter(NodePtr valPtr, uint8_t const* infoPtr, + fast_forward_tag ROBIN_HOOD_UNUSED(tag) /*unused*/) noexcept + : mKeyVals(valPtr) + , mInfo(infoPtr) { + fastForward(); + } + + template ::type> + Iter& operator=(Iter const& other) noexcept { + mKeyVals = other.mKeyVals; + mInfo = other.mInfo; + return *this; + } + + // prefix increment. Undefined behavior if we are at end()! + Iter& operator++() noexcept { + mInfo++; + mKeyVals++; + fastForward(); + return *this; + } + + reference operator*() const { + return **mKeyVals; + } + + pointer operator->() const { + return &**mKeyVals; + } + + template + bool operator==(Iter const& o) const noexcept { + return mKeyVals == o.mKeyVals; + } + + template + bool operator!=(Iter const& o) const noexcept { + return mKeyVals != o.mKeyVals; + } + + private: + // fast forward to the next non-free info byte + void fastForward() noexcept { + int inc; + do { + auto const n = detail::unaligned_load(mInfo); +#if ROBIN_HOOD(LITTLE_ENDIAN) + inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8; +#else + inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8; +#endif + mInfo += inc; + mKeyVals += inc; + } while (inc == static_cast(sizeof(size_t))); + } + + friend class Table; + NodePtr mKeyVals{nullptr}; + uint8_t const* mInfo{nullptr}; + }; + + //////////////////////////////////////////////////////////////////// + + // highly performance relevant code. + // Lower bits are used for indexing into the array (2^n size) + // The upper 1-5 bits need to be a reasonable good hash, to save comparisons. + template + void keyToIdx(HashKey&& key, size_t* idx, InfoType* info) const { + // for a user-specified hash that is *not* robin_hood::hash, apply robin_hood::hash as an + // additional mixing step. This serves as a bad hash prevention, if the given data is badly + // mixed. + using Mix = + typename std::conditional, hasher>::value, + ::robin_hood::detail::identity_hash, + ::robin_hood::hash>::type; + *idx = Mix{}(WHash::operator()(key)); + + *info = mInfoInc + static_cast(*idx >> mInfoHashShift); + *idx &= mMask; + } + + // forwards the index by one, wrapping around at the end + void next(InfoType* info, size_t* idx) const noexcept { + *idx = *idx + 1; + *info += mInfoInc; + } + + void nextWhileLess(InfoType* info, size_t* idx) const noexcept { + // unrolling this by hand did not bring any speedups. + while (*info < mInfo[*idx]) { + next(info, idx); + } + } + + // Shift everything up by one element. Tries to move stuff around. + void + shiftUp(size_t startIdx, + size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable::value) { + auto idx = startIdx; + ::new (static_cast(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1])); + while (--idx != insertion_idx) { + mKeyVals[idx] = std::move(mKeyVals[idx - 1]); + } + + idx = startIdx; + while (idx != insertion_idx) { + ROBIN_HOOD_COUNT(shiftUp); + mInfo[idx] = static_cast(mInfo[idx - 1] + mInfoInc); + if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + --idx; + } + } + + void shiftDown(size_t idx) noexcept(std::is_nothrow_move_assignable::value) { + // until we find one that is either empty or has zero offset. + // TODO(martinus) we don't need to move everything, just the last one for the same bucket. + mKeyVals[idx].destroy(*this); + + // until we find one that is either empty or has zero offset. + while (mInfo[idx + 1] >= 2 * mInfoInc) { + ROBIN_HOOD_COUNT(shiftDown); + mInfo[idx] = static_cast(mInfo[idx + 1] - mInfoInc); + mKeyVals[idx] = std::move(mKeyVals[idx + 1]); + ++idx; + } + + mInfo[idx] = 0; + // don't destroy, we've moved it + // mKeyVals[idx].destroy(*this); + mKeyVals[idx].~Node(); + } + + // copy of find(), except that it returns iterator instead of const_iterator. + template + ROBIN_HOOD(NODISCARD) + size_t findIdx(Other const& key) const { + size_t idx; + InfoType info; + keyToIdx(key, &idx, &info); + + do { + // unrolling this twice gives a bit of a speedup. More unrolling did not help. + if (info == mInfo[idx] && + ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) { + return idx; + } + next(&info, &idx); + if (info == mInfo[idx] && + ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) { + return idx; + } + next(&info, &idx); + } while (info <= mInfo[idx]); + + // nothing found! + return mMask == 0 ? 0 + : static_cast(std::distance( + mKeyVals, reinterpret_cast_no_cast_align_warning(mInfo))); + } + + void cloneData(const Table& o) { + Cloner()(o, *this); + } + + // inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized. + // @return index where the element was created + size_t insert_move(Node&& keyval) { + // we don't retry, fail if overflowing + // don't need to check max num elements + if (0 == mMaxNumElementsAllowed && !try_increase_info()) { + throwOverflowError(); // impossible to reach LCOV_EXCL_LINE + } + + size_t idx; + InfoType info; + keyToIdx(keyval.getFirst(), &idx, &info); + + // skip forward. Use <= because we are certain that the element is not there. + while (info <= mInfo[idx]) { + idx = idx + 1; + info += mInfoInc; + } + + // key not found, so we are now exactly where we want to insert it. + auto const insertion_idx = idx; + auto const insertion_info = static_cast(info); + if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + + // find an empty spot + while (0 != mInfo[idx]) { + next(&info, &idx); + } + + auto& l = mKeyVals[insertion_idx]; + if (idx == insertion_idx) { + ::new (static_cast(&l)) Node(std::move(keyval)); + } else { + shiftUp(idx, insertion_idx); + l = std::move(keyval); + } + + // put at empty spot + mInfo[insertion_idx] = insertion_info; + + ++mNumElements; + return insertion_idx; + } + +public: + using iterator = Iter; + using const_iterator = Iter; + + // Creates an empty hash map. Nothing is allocated yet, this happens at the first insert. This + // tremendously speeds up ctor & dtor of a map that never receives an element. The penalty is + // payed at the first insert, and not before. Lookup of this empty map works because everybody + // points to DummyInfoByte::b. parameter bucket_count is dictated by the standard, but we can + // ignore it. + explicit Table(size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{}, + const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && + noexcept(KeyEqual(equal))) + : WHash(h) + , WKeyEqual(equal) { + ROBIN_HOOD_TRACE(this); + } + + template + Table(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, + const Hash& h = Hash{}, const KeyEqual& equal = KeyEqual{}) + : WHash(h) + , WKeyEqual(equal) { + ROBIN_HOOD_TRACE(this); + insert(first, last); + } + + Table(std::initializer_list initlist, + size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{}, + const KeyEqual& equal = KeyEqual{}) + : WHash(h) + , WKeyEqual(equal) { + ROBIN_HOOD_TRACE(this); + insert(initlist.begin(), initlist.end()); + } + + Table(Table&& o) noexcept + : WHash(std::move(static_cast(o))) + , WKeyEqual(std::move(static_cast(o))) + , DataPool(std::move(static_cast(o))) { + ROBIN_HOOD_TRACE(this); + if (o.mMask) { + mKeyVals = std::move(o.mKeyVals); + mInfo = std::move(o.mInfo); + mNumElements = std::move(o.mNumElements); + mMask = std::move(o.mMask); + mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed); + mInfoInc = std::move(o.mInfoInc); + mInfoHashShift = std::move(o.mInfoHashShift); + // set other's mask to 0 so its destructor won't do anything + o.init(); + } + } + + Table& operator=(Table&& o) noexcept { + ROBIN_HOOD_TRACE(this); + if (&o != this) { + if (o.mMask) { + // only move stuff if the other map actually has some data + destroy(); + mKeyVals = std::move(o.mKeyVals); + mInfo = std::move(o.mInfo); + mNumElements = std::move(o.mNumElements); + mMask = std::move(o.mMask); + mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed); + mInfoInc = std::move(o.mInfoInc); + mInfoHashShift = std::move(o.mInfoHashShift); + WHash::operator=(std::move(static_cast(o))); + WKeyEqual::operator=(std::move(static_cast(o))); + DataPool::operator=(std::move(static_cast(o))); + + o.init(); + + } else { + // nothing in the other map => just clear us. + clear(); + } + } + return *this; + } + + Table(const Table& o) + : WHash(static_cast(o)) + , WKeyEqual(static_cast(o)) + , DataPool(static_cast(o)) { + ROBIN_HOOD_TRACE(this); + if (!o.empty()) { + // not empty: create an exact copy. it is also possible to just iterate through all + // elements and insert them, but copying is probably faster. + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1); + mKeyVals = static_cast(detail::assertNotNull( + malloc(calcNumBytesTotal(numElementsWithBuffer)))); + // no need for calloc because clonData does memcpy + mInfo = reinterpret_cast(mKeyVals + numElementsWithBuffer); + mNumElements = o.mNumElements; + mMask = o.mMask; + mMaxNumElementsAllowed = o.mMaxNumElementsAllowed; + mInfoInc = o.mInfoInc; + mInfoHashShift = o.mInfoHashShift; + cloneData(o); + } + } + + // Creates a copy of the given map. Copy constructor of each entry is used. + Table& operator=(Table const& o) { + ROBIN_HOOD_TRACE(this); + if (&o == this) { + // prevent assigning of itself + return *this; + } + + // we keep using the old allocator and not assign the new one, because we want to keep the + // memory available. when it is the same size. + if (o.empty()) { + if (0 == mMask) { + // nothing to do, we are empty too + return *this; + } + + // not empty: destroy what we have there + // clear also resets mInfo to 0, that's sometimes not necessary. + destroy(); + init(); + WHash::operator=(static_cast(o)); + WKeyEqual::operator=(static_cast(o)); + DataPool::operator=(static_cast(o)); + + return *this; + } + + // clean up old stuff + Destroyer::value>{}.nodes(*this); + + if (mMask != o.mMask) { + // no luck: we don't have the same array size allocated, so we need to realloc. + if (0 != mMask) { + // only deallocate if we actually have data! + free(mKeyVals); + } + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1); + mKeyVals = static_cast(detail::assertNotNull( + malloc(calcNumBytesTotal(numElementsWithBuffer)))); + + // no need for calloc here because cloneData performs a memcpy. + mInfo = reinterpret_cast(mKeyVals + numElementsWithBuffer); + // sentinel is set in cloneData + } + WHash::operator=(static_cast(o)); + WKeyEqual::operator=(static_cast(o)); + DataPool::operator=(static_cast(o)); + mNumElements = o.mNumElements; + mMask = o.mMask; + mMaxNumElementsAllowed = o.mMaxNumElementsAllowed; + mInfoInc = o.mInfoInc; + mInfoHashShift = o.mInfoHashShift; + cloneData(o); + + return *this; + } + + // Swaps everything between the two maps. + void swap(Table& o) { + ROBIN_HOOD_TRACE(this); + using std::swap; + swap(o, *this); + } + + // Clears all data, without resizing. + void clear() { + ROBIN_HOOD_TRACE(this); + if (empty()) { + // don't do anything! also important because we don't want to write to DummyInfoByte::b, + // even though we would just write 0 to it. + return; + } + + Destroyer::value>{}.nodes(*this); + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1); + // clear everything, then set the sentinel again + uint8_t const z = 0; + std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z); + mInfo[numElementsWithBuffer] = 1; + + mInfoInc = InitialInfoInc; + mInfoHashShift = InitialInfoHashShift; + } + + // Destroys the map and all it's contents. + ~Table() { + ROBIN_HOOD_TRACE(this); + destroy(); + } + + // Checks if both maps contain the same entries. Order is irrelevant. + bool operator==(const Table& other) const { + ROBIN_HOOD_TRACE(this); + if (other.size() != size()) { + return false; + } + for (auto const& otherEntry : other) { + auto const myIt = find(otherEntry.first); + if (myIt == end() || !(myIt->second == otherEntry.second)) { + return false; + } + } + + return true; + } + + bool operator!=(const Table& other) const { + ROBIN_HOOD_TRACE(this); + return !operator==(other); + } + + template + typename std::enable_if::value, Q&>::type operator[](const key_type& key) { + ROBIN_HOOD_TRACE(this); + return doCreateByKey(key); + } + + template + typename std::enable_if::value, Q&>::type operator[](key_type&& key) { + ROBIN_HOOD_TRACE(this); + return doCreateByKey(std::move(key)); + } + + template + void insert(Iter first, Iter last) { + for (; first != last; ++first) { + // value_type ctor needed because this might be called with std::pair's + insert(value_type(*first)); + } + } + + template + std::pair emplace(Args&&... args) { + ROBIN_HOOD_TRACE(this); + Node n{*this, std::forward(args)...}; + auto r = doInsert(std::move(n)); + if (!r.second) { + // insertion not possible: destroy node + // NOLINTNEXTLINE(bugprone-use-after-move) + n.destroy(*this); + } + return r; + } + + std::pair insert(const value_type& keyval) { + ROBIN_HOOD_TRACE(this); + return doInsert(keyval); + } + + std::pair insert(value_type&& keyval) { + return doInsert(std::move(keyval)); + } + + // Returns 1 if key is found, 0 otherwise. + size_t count(const key_type& key) const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + auto kv = mKeyVals + findIdx(key); + if (kv != reinterpret_cast_no_cast_align_warning(mInfo)) { + return 1; + } + return 0; + } + + // Returns a reference to the value found for key. + // Throws std::out_of_range if element cannot be found + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + typename std::enable_if::value, Q&>::type at(key_type const& key) { + ROBIN_HOOD_TRACE(this); + auto kv = mKeyVals + findIdx(key); + if (kv == reinterpret_cast_no_cast_align_warning(mInfo)) { + doThrow("key not found"); + } + return kv->getSecond(); + } + + // Returns a reference to the value found for key. + // Throws std::out_of_range if element cannot be found + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + typename std::enable_if::value, Q const&>::type at(key_type const& key) const { + ROBIN_HOOD_TRACE(this); + auto kv = mKeyVals + findIdx(key); + if (kv == reinterpret_cast_no_cast_align_warning(mInfo)) { + doThrow("key not found"); + } + return kv->getSecond(); + } + + const_iterator find(const key_type& key) const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + const size_t idx = findIdx(key); + return const_iterator{mKeyVals + idx, mInfo + idx}; + } + + template + const_iterator find(const OtherKey& key, is_transparent_tag /*unused*/) const { + ROBIN_HOOD_TRACE(this); + const size_t idx = findIdx(key); + return const_iterator{mKeyVals + idx, mInfo + idx}; + } + + iterator find(const key_type& key) { + ROBIN_HOOD_TRACE(this); + const size_t idx = findIdx(key); + return iterator{mKeyVals + idx, mInfo + idx}; + } + + template + iterator find(const OtherKey& key, is_transparent_tag /*unused*/) { + ROBIN_HOOD_TRACE(this); + const size_t idx = findIdx(key); + return iterator{mKeyVals + idx, mInfo + idx}; + } + + iterator begin() { + ROBIN_HOOD_TRACE(this); + if (empty()) { + return end(); + } + return iterator(mKeyVals, mInfo, fast_forward_tag{}); + } + const_iterator begin() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return cbegin(); + } + const_iterator cbegin() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + if (empty()) { + return cend(); + } + return const_iterator(mKeyVals, mInfo, fast_forward_tag{}); + } + + iterator end() { + ROBIN_HOOD_TRACE(this); + // no need to supply valid info pointer: end() must not be dereferenced, and only node + // pointer is compared. + return iterator{reinterpret_cast_no_cast_align_warning(mInfo), nullptr}; + } + const_iterator end() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return cend(); + } + const_iterator cend() const { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return const_iterator{reinterpret_cast_no_cast_align_warning(mInfo), nullptr}; + } + + iterator erase(const_iterator pos) { + ROBIN_HOOD_TRACE(this); + // its safe to perform const cast here + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + return erase(iterator{const_cast(pos.mKeyVals), const_cast(pos.mInfo)}); + } + + // Erases element at pos, returns iterator to the next element. + iterator erase(iterator pos) { + ROBIN_HOOD_TRACE(this); + // we assume that pos always points to a valid entry, and not end(). + auto const idx = static_cast(pos.mKeyVals - mKeyVals); + + shiftDown(idx); + --mNumElements; + + if (*pos.mInfo) { + // we've backward shifted, return this again + return pos; + } + + // no backward shift, return next element + return ++pos; + } + + size_t erase(const key_type& key) { + ROBIN_HOOD_TRACE(this); + size_t idx; + InfoType info; + keyToIdx(key, &idx, &info); + + // check while info matches with the source idx + do { + if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) { + shiftDown(idx); + --mNumElements; + return 1; + } + next(&info, &idx); + } while (info <= mInfo[idx]); + + // nothing found to delete + return 0; + } + + // reserves space for the specified number of elements. Makes sure the old data fits. + // exactly the same as reserve(c). + void rehash(size_t c) { + reserve(c); + } + + // reserves space for the specified number of elements. Makes sure the old data fits. + // Exactly the same as resize(c). Use resize(0) to shrink to fit. + void reserve(size_t c) { + ROBIN_HOOD_TRACE(this); + auto const minElementsAllowed = (std::max)(c, mNumElements); + auto newSize = InitialNumElements; + while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) { + newSize *= 2; + } + if (ROBIN_HOOD_UNLIKELY(newSize == 0)) { + throwOverflowError(); + } + + rehashPowerOfTwo(newSize); + } + + size_type size() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return mNumElements; + } + + size_type max_size() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return static_cast(-1); + } + + ROBIN_HOOD(NODISCARD) bool empty() const noexcept { + ROBIN_HOOD_TRACE(this); + return 0 == mNumElements; + } + + float max_load_factor() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return MaxLoadFactor100 / 100.0F; + } + + // Average number of elements per bucket. Since we allow only 1 per bucket + float load_factor() const noexcept { // NOLINT(modernize-use-nodiscard) + ROBIN_HOOD_TRACE(this); + return static_cast(size()) / static_cast(mMask + 1); + } + + ROBIN_HOOD(NODISCARD) size_t mask() const noexcept { + ROBIN_HOOD_TRACE(this); + return mMask; + } + + ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept { + if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits::max)() / 100)) { + return maxElements * MaxLoadFactor100 / 100; + } + + // we might be a bit inprecise, but since maxElements is quite large that doesn't matter + return (maxElements / 100) * MaxLoadFactor100; + } + + ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept { + // we add a uint64_t, which houses the sentinel (first byte) and padding so we can load + // 64bit types. + return numElements + sizeof(uint64_t); + } + + ROBIN_HOOD(NODISCARD) + size_t calcNumElementsWithBuffer(size_t numElements) const noexcept { + auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements); + return numElements + (std::min)(maxNumElementsAllowed, (static_cast(0xFF))); + } + + // calculation only allowed for 2^n values + ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const { +#if ROBIN_HOOD(BITNESS) == 64 + return numElements * sizeof(Node) + calcNumBytesInfo(numElements); +#else + // make sure we're doing 64bit operations, so we are at least safe against 32bit overflows. + auto const ne = static_cast(numElements); + auto const s = static_cast(sizeof(Node)); + auto const infos = static_cast(calcNumBytesInfo(numElements)); + + auto const total64 = ne * s + infos; + auto const total = static_cast(total64); + + if (ROBIN_HOOD_UNLIKELY(static_cast(total) != total64)) { + throwOverflowError(); + } + return total; +#endif + } + +private: + // reserves space for at least the specified number of elements. + // only works if numBuckets if power of two + void rehashPowerOfTwo(size_t numBuckets) { + ROBIN_HOOD_TRACE(this); + + Node* const oldKeyVals = mKeyVals; + uint8_t const* const oldInfo = mInfo; + + const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1); + + // resize operation: move stuff + init_data(numBuckets); + if (oldMaxElementsWithBuffer > 1) { + for (size_t i = 0; i < oldMaxElementsWithBuffer; ++i) { + if (oldInfo[i] != 0) { + insert_move(std::move(oldKeyVals[i])); + // destroy the node but DON'T destroy the data. + oldKeyVals[i].~Node(); + } + } + + // don't destroy old data: put it into the pool instead + DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer)); + } + } + + ROBIN_HOOD(NOINLINE) void throwOverflowError() const { +#if ROBIN_HOOD(HAS_EXCEPTIONS) + throw std::overflow_error("robin_hood::map overflow"); +#else + abort(); +#endif + } + + void init_data(size_t max_elements) { + mNumElements = 0; + mMask = max_elements - 1; + mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements); + + auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements); + + // calloc also zeroes everything + mKeyVals = reinterpret_cast(detail::assertNotNull( + calloc(1, calcNumBytesTotal(numElementsWithBuffer)))); + mInfo = reinterpret_cast(mKeyVals + numElementsWithBuffer); + + // set sentinel + mInfo[numElementsWithBuffer] = 1; + + mInfoInc = InitialInfoInc; + mInfoHashShift = InitialInfoHashShift; + } + + template + typename std::enable_if::value, Q&>::type doCreateByKey(Arg&& key) { + while (true) { + size_t idx; + InfoType info; + keyToIdx(key, &idx, &info); + nextWhileLess(&info, &idx); + + // while we potentially have a match. Can't do a do-while here because when mInfo is 0 + // we don't want to skip forward + while (info == mInfo[idx]) { + if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) { + // key already exists, do not insert. + return mKeyVals[idx].getSecond(); + } + next(&info, &idx); + } + + // unlikely that this evaluates to true + if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) { + increase_size(); + continue; + } + + // key not found, so we are now exactly where we want to insert it. + auto const insertion_idx = idx; + auto const insertion_info = info; + if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + + // find an empty spot + while (0 != mInfo[idx]) { + next(&info, &idx); + } + + auto& l = mKeyVals[insertion_idx]; + if (idx == insertion_idx) { + // put at empty spot. This forwards all arguments into the node where the object is + // constructed exactly where it is needed. + ::new (static_cast(&l)) + Node(*this, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), std::forward_as_tuple()); + } else { + shiftUp(idx, insertion_idx); + l = Node(*this, std::piecewise_construct, + std::forward_as_tuple(std::forward(key)), std::forward_as_tuple()); + } + + // mKeyVals[idx].getFirst() = std::move(key); + mInfo[insertion_idx] = static_cast(insertion_info); + + ++mNumElements; + return mKeyVals[insertion_idx].getSecond(); + } + } + + // This is exactly the same code as operator[], except for the return values + template + std::pair doInsert(Arg&& keyval) { + while (true) { + size_t idx; + InfoType info; + keyToIdx(getFirstConst(keyval), &idx, &info); + nextWhileLess(&info, &idx); + + // while we potentially have a match + while (info == mInfo[idx]) { + if (WKeyEqual::operator()(getFirstConst(keyval), mKeyVals[idx].getFirst())) { + // key already exists, do NOT insert. + // see http://en.cppreference.com/w/cpp/container/unordered_map/insert + return std::make_pair(iterator(mKeyVals + idx, mInfo + idx), + false); + } + next(&info, &idx); + } + + // unlikely that this evaluates to true + if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) { + increase_size(); + continue; + } + + // key not found, so we are now exactly where we want to insert it. + auto const insertion_idx = idx; + auto const insertion_info = info; + if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) { + mMaxNumElementsAllowed = 0; + } + + // find an empty spot + while (0 != mInfo[idx]) { + next(&info, &idx); + } + + auto& l = mKeyVals[insertion_idx]; + if (idx == insertion_idx) { + ::new (static_cast(&l)) Node(*this, std::forward(keyval)); + } else { + shiftUp(idx, insertion_idx); + l = Node(*this, std::forward(keyval)); + } + + // put at empty spot + mInfo[insertion_idx] = static_cast(insertion_info); + + ++mNumElements; + return std::make_pair(iterator(mKeyVals + insertion_idx, mInfo + insertion_idx), true); + } + } + + bool try_increase_info() { + ROBIN_HOOD_LOG("mInfoInc=" << mInfoInc << ", numElements=" << mNumElements + << ", maxNumElementsAllowed=" + << calcMaxNumElementsAllowed(mMask + 1)); + if (mInfoInc <= 2) { + // need to be > 2 so that shift works (otherwise undefined behavior!) + return false; + } + // we got space left, try to make info smaller + mInfoInc = static_cast(mInfoInc >> 1U); + + // remove one bit of the hash, leaving more space for the distance info. + // This is extremely fast because we can operate on 8 bytes at once. + ++mInfoHashShift; + auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1); + + for (size_t i = 0; i < numElementsWithBuffer; i += 8) { + auto val = unaligned_load(mInfo + i); + val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f); + std::memcpy(mInfo + i, &val, sizeof(val)); + } + // update sentinel, which might have been cleared out! + mInfo[numElementsWithBuffer] = 1; + + mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1); + return true; + } + + void increase_size() { + // nothing allocated yet? just allocate InitialNumElements + if (0 == mMask) { + init_data(InitialNumElements); + return; + } + + auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1); + if (mNumElements < maxNumElementsAllowed && try_increase_info()) { + return; + } + + ROBIN_HOOD_LOG("mNumElements=" << mNumElements << ", maxNumElementsAllowed=" + << maxNumElementsAllowed << ", load=" + << (static_cast(mNumElements) * 100.0 / + (static_cast(mMask) + 1))); + // it seems we have a really bad hash function! don't try to resize again + if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) { + throwOverflowError(); + } + + rehashPowerOfTwo((mMask + 1) * 2); + } + + void destroy() { + if (0 == mMask) { + // don't deallocate! + return; + } + + Destroyer::value>{} + .nodesDoNotDeallocate(*this); + + // This protection against not deleting mMask shouldn't be needed as it's sufficiently + // protected with the 0==mMask check, but I have this anyways because g++ 7 otherwise + // reports a compile error: attempt to free a non-heap object ‘fm’ + // [-Werror=free-nonheap-object] + if (mKeyVals != reinterpret_cast(&mMask)) { + free(mKeyVals); + } + } + + void init() noexcept { + mKeyVals = reinterpret_cast(&mMask); + mInfo = reinterpret_cast(&mMask); + mNumElements = 0; + mMask = 0; + mMaxNumElementsAllowed = 0; + mInfoInc = InitialInfoInc; + mInfoHashShift = InitialInfoHashShift; + } + + // members are sorted so no padding occurs + Node* mKeyVals = reinterpret_cast(&mMask); // 8 byte 8 + uint8_t* mInfo = reinterpret_cast(&mMask); // 8 byte 16 + size_t mNumElements = 0; // 8 byte 24 + size_t mMask = 0; // 8 byte 32 + size_t mMaxNumElementsAllowed = 0; // 8 byte 40 + InfoType mInfoInc = InitialInfoInc; // 4 byte 44 + InfoType mInfoHashShift = InitialInfoHashShift; // 4 byte 48 + // 16 byte 56 if NodeAllocator +}; + +} // namespace detail + +// map + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_flat_map = detail::Table; + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_node_map = detail::Table; + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_map = + detail::Table) <= sizeof(size_t) * 6 && + std::is_nothrow_move_constructible>::value && + std::is_nothrow_move_assignable>::value, + MaxLoadFactor100, Key, T, Hash, KeyEqual>; + +// set + +template , typename KeyEqual = std::equal_to, + size_t MaxLoadFactor100 = 80> +using unordered_flat_set = detail::Table; + +template , typename KeyEqual = std::equal_to, + size_t MaxLoadFactor100 = 80> +using unordered_node_set = detail::Table; + +template , + typename KeyEqual = std::equal_to, size_t MaxLoadFactor100 = 80> +using unordered_set = detail::Table::value && + std::is_nothrow_move_assignable::value, + MaxLoadFactor100, Key, void, Hash, KeyEqual>; + +} // namespace robin_hood + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Context.h b/thirdparty/RmlUi/Include/RmlUi/Core/Context.h new file mode 100644 index 000000000..8d46602da --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Context.h @@ -0,0 +1,363 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_CONTEXT_H +#define RMLUI_CORE_CONTEXT_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" +#include "Input.h" +#include "ScriptInterface.h" + +namespace Rml { + +class Stream; +class ContextInstancer; +class ElementDocument; +class EventListener; +class RenderInterface; +class DataModel; +class DataModelConstructor; +class DataTypeRegister; +enum class EventId : uint16_t; + +/** + A context for storing, rendering and processing RML documents. Multiple contexts can exist simultaneously. + + @author Peter Curry + */ + +class RMLUICORE_API Context : public ScriptInterface +{ +public: + /// Constructs a new, uninitialised context. This should not be called directly, use CreateContext() + /// instead. + /// @param[in] name The name of the context. + Context(const String& name); + /// Destroys a context. + virtual ~Context(); + + /// Returns the name of the context. + /// @return The context's name. + const String& GetName() const; + + /// Changes the dimensions of the context. + /// @param[in] dimensions The new dimensions of the context. + void SetDimensions(const Vector2i& dimensions); + /// Returns the dimensions of the context. + /// @return The current dimensions of the context. + const Vector2i& GetDimensions() const; + + /// Changes the size ratio of 'dp' unit to 'px' unit + /// @param[in] dp_ratio The new density-independent pixel ratio of the context. + void SetDensityIndependentPixelRatio(float density_independent_pixel_ratio); + /// Returns the size ratio of 'dp' unit to 'px' unit + /// @return The current density-independent pixel ratio of the context. + float GetDensityIndependentPixelRatio() const; + + /// Updates all elements in the context's documents. + /// This must be called before Context::Render, but after any elements have been changed, added or removed. + bool Update(); + /// Renders all visible elements in the context's documents. + bool Render(); + + /// Creates a new, empty document and places it into this context. + /// @param[in] instancer_name The name of the instancer used to create the document. + /// @return The new document, or nullptr if no document could be created. + ElementDocument* CreateDocument(const String& instancer_name = "body"); + /// Load a document into the context. + /// @param[in] document_path The path to the document to load. + /// @return The loaded document, or nullptr if no document was loaded. + ElementDocument* LoadDocument(const String& document_path); + /// Load a document into the context. + /// @param[in] document_stream The opened stream, ready to read. + /// @return The loaded document, or nullptr if no document was loaded. + ElementDocument* LoadDocument(Stream* document_stream); + /// Load a document into the context. + /// @param[in] string The string containing the document RML. + /// @return The loaded document, or nullptr if no document was loaded. + ElementDocument* LoadDocumentFromMemory(const String& string); + /// Unload the given document. + /// @param[in] document The document to unload. + void UnloadDocument(ElementDocument* document); + /// Unloads all loaded documents. + void UnloadAllDocuments(); + + /// Enable or disable handling of the mouse cursor from this context. + /// When enabled, changes to the cursor name is transmitted through the system interface. + /// @param[in] show True to enable mouse cursor handling, false to disable. + void EnableMouseCursor(bool enable); + + /// Returns the first document in the context with the given id. + /// @param[in] id The id of the desired document. + /// @return The document (if it was found), or nullptr if no document exists with the ID. + ElementDocument* GetDocument(const String& id); + /// Returns a document in the context by index. + /// @param[in] index The index of the desired document. + /// @return The document (if one exists with this index), or nullptr if the index was invalid. + ElementDocument* GetDocument(int index); + /// Returns the number of documents in the context. + int GetNumDocuments() const; + + /// Returns the hover element. + /// @return The element the mouse cursor is hovering over. + Element* GetHoverElement(); + /// Returns the focus element. + /// @return The element with input focus. + Element* GetFocusElement(); + /// Returns the root element that holds all the documents + /// @return The root element. + Element* GetRootElement(); + + // Returns the youngest descendent of the given element which is under the given point in screen coordinates. + // @param[in] point The point to test. + // @param[in] ignore_element If set, this element and its descendents will be ignored. + // @param[in] element Used internally. + // @return The element under the point, or nullptr if nothing is. + Element* GetElementAtPoint(Vector2f point, const Element* ignore_element = nullptr, Element* element = nullptr) const; + + /// Brings the document to the front of the document stack. + /// @param[in] document The document to pull to the front of the stack. + void PullDocumentToFront(ElementDocument* document); + /// Sends the document to the back of the document stack. + /// @param[in] document The document to push to the bottom of the stack. + void PushDocumentToBack(ElementDocument* document); + /// Remove the document from the focus history and focus the previous document. + /// @param[in] document The document to unfocus. + void UnfocusDocument(ElementDocument* document); + + /// Adds an event listener to the context's root element. + /// @param[in] event The name of the event to attach to. + /// @param[in] listener Listener object to be attached. + /// @param[in] in_capture_phase True if the listener is to be attached to the capture phase, false for the bubble phase. + void AddEventListener(const String& event, EventListener* listener, bool in_capture_phase = false); + /// Removes an event listener from the context's root element. + /// @param[in] event The name of the event to detach from. + /// @param[in] listener Listener object to be detached. + /// @param[in] in_capture_phase True to detach from the capture phase, false from the bubble phase. + void RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase = false); + + /// Sends a key down event into this context. + /// @param[in] key_identifier The key pressed. + /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together members of the Input::KeyModifier enumeration. + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + bool ProcessKeyDown(Input::KeyIdentifier key_identifier, int key_modifier_state); + /// Sends a key up event into this context. + /// @param[in] key_identifier The key released. + /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together members of the Input::KeyModifier enumeration. + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + bool ProcessKeyUp(Input::KeyIdentifier key_identifier, int key_modifier_state); + + /// Sends a single unicode character as text input into this context. + /// @param[in] character The unicode code point to send into this context. + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + bool ProcessTextInput(Character character); + /// Sends a single ascii character as text input into this context. + bool ProcessTextInput(char character); + /// Sends a string of text as text input into this context. + /// @param[in] string The UTF-8 string to send into this context. + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + bool ProcessTextInput(const String& string); + + /// Sends a mouse movement event into this context. + /// @param[in] x The x-coordinate of the mouse cursor, in window-coordinates (ie, 0 should be the left of the client area). + /// @param[in] y The y-coordinate of the mouse cursor, in window-coordinates (ie, 0 should be the top of the client area). + /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together members of the Input::KeyModifier enumeration. + void ProcessMouseMove(int x, int y, int key_modifier_state); + /// Sends a mouse-button down event into this context. + /// @param[in] button_index The index of the button that was pressed; 0 for the left button, 1 for right, and any others from 2 onwards. + /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together members of the Input::KeyModifier enumeration. + void ProcessMouseButtonDown(int button_index, int key_modifier_state); + /// Sends a mouse-button up event into this context. + /// @param[in] button_index The index of the button that was release; 0 for the left button, 1 for right, and any others from 2 onwards. + /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together members of the Input::KeyModifier enumeration. + void ProcessMouseButtonUp(int button_index, int key_modifier_state); + /// Sends a mouse-wheel movement event into this context. + /// @param[in] wheel_delta The mouse-wheel movement this frame. RmlUi treats a negative delta as up movement (away from the user), positive as down. + /// @param[in] key_modifier_state The state of key modifiers (shift, control, caps-lock, etc) keys; this should be generated by ORing together members of the Input::KeyModifier enumeration. + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + bool ProcessMouseWheel(float wheel_delta, int key_modifier_state); + + /// Gets the context's render interface. + /// @return The render interface the context renders through. + RenderInterface* GetRenderInterface() const; + /// Gets the current clipping region for the render traversal + /// @param[out] origin The clipping origin + /// @param[out] dimensions The clipping dimensions + bool GetActiveClipRegion(Vector2i& origin, Vector2i& dimensions) const; + /// Sets the current clipping region for the render traversal + /// @param[out] origin The clipping origin + /// @param[out] dimensions The clipping dimensions + void SetActiveClipRegion(const Vector2i& origin, const Vector2i& dimensions); + + /// Sets the instancer to use for releasing this object. + /// @param[in] instancer The context's instancer. + void SetInstancer(ContextInstancer* instancer); + + /// Creates a data model. + /// The returned constructor can be used to bind data variables. Elements can bind to the model using the attribute 'data-model="name"'. + /// @param[in] name The name of the data model. + /// @return A constructor for the data model, or empty if it could not be created. + DataModelConstructor CreateDataModel(const String& name); + + /// Retrieves the constructor for an existing data model. + /// The returned constructor can be used to add additional bindings to an existing model. + /// @param[in] name The name of the data model. + /// @return A constructor for the data model, or empty if it could not be found. + DataModelConstructor GetDataModel(const String& name); + + /// Removes the given data model. + /// This also removes all data views, controllers and bindings contained by the data model. + /// @warning Invalidates all handles and constructors pointing to the data model. + /// @param[in] name The name of the data model. + /// @return True if succesfully removed, false if no data model was found. + bool RemoveDataModel(const String& name); + + /// This will set the documents base before creation. Default = "body" + /// @param[in] tag The name of the base tag. Example: "html" + void SetDocumentsBaseTag(const String& tag); + + /// Gets the name of the documents base tag. + /// @return The current documents base tag name. + const String& GetDocumentsBaseTag(); + +protected: + void Release() override; + +private: + String name; + Vector2i dimensions; + float density_independent_pixel_ratio; + String documents_base_tag = "body"; + + ContextInstancer* instancer; + + using ElementSet = SmallOrderedSet< Element* > ; + using ElementList = Vector< Element* >; + // Set of elements that are currently in hover state. + ElementSet hover_chain; + // List of elements that are currently in active state. + ElementList active_chain; + // History of windows that have had focus + ElementList document_focus_history; + + // Documents that have been unloaded from the context but not yet released. + OwnedElementList unloaded_documents; + + // Root of the element tree. + ElementPtr root; + // The element that current has input focus. + Element* focus; + // The top-most element being hovered over. + Element* hover; + // The element that was being hovered over when the primary mouse button was pressed most recently. + Element* active; + + // The element that was clicked on last. + Element* last_click_element; + // The time the last click occured. + double last_click_time; + // Mouse position during the last mouse_down event. + Vector2i last_click_mouse_position; + + // Enables cursor handling. + bool enable_cursor; + String cursor_name; + // Document attached to cursor (e.g. while dragging). + ElementPtr cursor_proxy; + + // The element that is currently being dragged (or about to be dragged). + Element* drag; + // True if a drag has begun (ie, the ondragstart event has been fired for the drag element), false otherwise. + bool drag_started; + // True if the current drag is a verbose drag (ie, sends ondragover, ondragout, ondragdrop, etc, events). + bool drag_verbose; + // Used when dragging a cloned object. + Element* drag_clone; + + // The element currently being dragged over; this is equivalent to hover, but only set while an element is being + // dragged, and excludes the dragged element. + Element* drag_hover; + // Set of elements that are currently being dragged over; this differs from the hover state as the dragged element + // itself can't be part of it. + ElementSet drag_hover_chain; + + // Input state; stored from the most recent input events we receive from the application. + Vector2i mouse_position; + + // The render interface this context renders through. + RenderInterface* render_interface; + Vector2i clip_origin; + Vector2i clip_dimensions; + + using DataModels = UnorderedMap>; + DataModels data_models; + + UniquePtr data_type_register; + + // Internal callback for when an element is detached or removed from the hierarchy. + void OnElementDetach(Element* element); + // Internal callback for when a new element gains focus. + bool OnFocusChange(Element* element); + + // Generates an event for faking clicks on an element. + void GenerateClickEvent(Element* element); + + // Updates the current hover elements, sending required events. + void UpdateHoverChain(const Dictionary& parameters, const Dictionary& drag_parameters, const Vector2i& old_mouse_position); + + // Creates the drag clone from the given element. The old drag clone will be released if necessary. + void CreateDragClone(Element* element); + // Releases the drag clone, if one exists. + void ReleaseDragClone(); + + // Returns the data model with the provided name, or nullptr if it does not exist. + DataModel* GetDataModelPtr(const String& name) const; + + // Builds the parameters for a generic key event. + void GenerateKeyEventParameters(Dictionary& parameters, Input::KeyIdentifier key_identifier); + // Builds the parameters for a generic mouse event. + void GenerateMouseEventParameters(Dictionary& parameters, int button_index = -1); + // Builds the parameters for the key modifier state. + void GenerateKeyModifierEventParameters(Dictionary& parameters, int key_modifier_state); + // Builds the parameters for a drag event. + void GenerateDragEventParameters(Dictionary& parameters); + + // Releases all unloaded documents pending destruction. + void ReleaseUnloadedDocuments(); + + // Sends the specified event to all elements in new_items that don't appear in old_items. + static void SendEvents(const ElementSet& old_items, const ElementSet& new_items, EventId id, const Dictionary& parameters); + + friend class Element; + friend RMLUICORE_API Context* CreateContext(const String&, const Vector2i&, RenderInterface*); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ContextInstancer.h b/thirdparty/RmlUi/Include/RmlUi/Core/ContextInstancer.h new file mode 100644 index 000000000..a97549e63 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ContextInstancer.h @@ -0,0 +1,67 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_CONTEXTINSTANCER_H +#define RMLUI_CORE_CONTEXTINSTANCER_H + +#include "Header.h" +#include "Traits.h" +#include "Types.h" + +namespace Rml { + +class Context; +class Event; + +/** + Abstract instancer interface for instancing contexts. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API ContextInstancer : public Releasable +{ +public: + virtual ~ContextInstancer(); + + /// Instances a context. + /// @param[in] name Name of this context. + /// @return The instanced context. + virtual ContextPtr InstanceContext(const String& name) = 0; + + /// Releases a context previously created by this context. + /// @param[in] context The context to release. + virtual void ReleaseContext(Context* context) = 0; + +protected: + /// Releases this context instancer + virtual void Release() = 0; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ConvolutionFilter.h b/thirdparty/RmlUi/Include/RmlUi/Core/ConvolutionFilter.h new file mode 100644 index 000000000..af2cf6c00 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ConvolutionFilter.h @@ -0,0 +1,99 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_CONVOLUTIONFILTER_H +#define RMLUI_CORE_CONVOLUTIONFILTER_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +enum class FilterOperation { + // The result is the sum of all the filtered pixels. + Sum, + // The result is the largest value of all filtered pixels. + Dilation, + // The result is the smallest value of all the filtered pixels. + Erosion +}; + +enum class ColorFormat { + RGBA8, + A8 +}; + + +/** + A programmable convolution filter, designed to aid in the generation of texture data by custom + FontEffect types. + + @author Peter Curry + */ + +class RMLUICORE_API ConvolutionFilter +{ +public: + ConvolutionFilter(); + ~ConvolutionFilter(); + + /// Initialises a square kernel filter with the given radius. + bool Initialise(int kernel_radius, FilterOperation operation); + + /// Initialises the filter. A filter must be initialised and populated with values before use. + /// @param[in] kernel_radii The size of the filter's kernel on each side of the origin along both axes. So, for example, a filter initialised with radii (1,1) will store 9 values. + /// @param[in] operation The operation the filter conducts to determine the result. + bool Initialise(Vector2i kernel_radii, FilterOperation operation); + + /// Returns a reference to one of the rows of the filter kernel. + /// @param[in] kernel_y_index The index of the desired row. + /// @return Pointer to the first value in the kernel row. + float* operator[](int kernel_y_index); + + /// Runs the convolution filter. The filter will operate on each pixel in the destination + /// surface, setting its opacity to the result the filter on the source opacity values. The + /// colour values will remain unchanged. + /// @param[in] destination The RGBA-encoded destination buffer. + /// @param[in] destination_dimensions The size of the destination region (in pixels). + /// @param[in] destination_stride The stride (in bytes) of the destination region. + /// @param[in] destination_color_format Determines the representation of the bytes in the destination texture, only the alpha channel will be written to. + /// @param[in] source The opacity information for the source buffer. + /// @param[in] source_dimensions The size of the source region (in pixels). The stride is assumed to be equivalent to the horizontal width. + /// @param[in] source_offset The offset of the source region from the destination region. This is usually the same as the kernel size. + void Run(byte* destination, Vector2i destination_dimensions, int destination_stride, ColorFormat destination_color_format, const byte* source, Vector2i source_dimensions, Vector2i source_offset) const; + +private: + Vector2i kernel_size; + UniquePtr kernel; + + FilterOperation operation = FilterOperation::Sum; +}; + +} // namespace Rml +#endif + diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Core.h b/thirdparty/RmlUi/Include/RmlUi/Core/Core.h new file mode 100644 index 000000000..5dc0cbf29 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Core.h @@ -0,0 +1,152 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_CORE_H +#define RMLUI_CORE_CORE_H + +#include "Header.h" +#include "Types.h" +#include "Event.h" +#include "ComputedValues.h" + +namespace Rml { + +class Plugin; +class Context; +class FileInterface; +class FontEngineInterface; +class RenderInterface; +class SystemInterface; +enum class DefaultActionPhase; + + +/** + RmlUi library core API. + + @author Peter Curry + */ + +/// Initialises RmlUi. +RMLUICORE_API bool Initialise(); +/// Shutdown RmlUi. +RMLUICORE_API void Shutdown(); + +/// Returns the version of this RmlUi library. +/// @return The version number. +RMLUICORE_API String GetVersion(); + +/// Sets the interface through which all system requests are made. This must be called before Initialise(). +/// @param[in] system_interface A non-owning pointer to the application-specified logging interface. +/// @lifetime The interface must be kept alive until after the call to Rml::Shutdown. +RMLUICORE_API void SetSystemInterface(SystemInterface* system_interface); +/// Returns RmlUi's system interface. +RMLUICORE_API SystemInterface* GetSystemInterface(); + +/// Sets the interface through which all rendering requests are made. This is not required to be called, but if it is +/// it must be called before Initialise(). If no render interface is specified, then all contexts must have a custom +/// render interface. +/// @param[in] render_interface A non-owning pointer to the render interface implementation. +/// @lifetime The interface must be kept alive until after the call to Rml::Shutdown. +RMLUICORE_API void SetRenderInterface(RenderInterface* render_interface); +/// Returns RmlUi's default's render interface. +RMLUICORE_API RenderInterface* GetRenderInterface(); + +/// Sets the interface through which all file I/O requests are made. This is not required to be called, but if it is it +/// must be called before Initialise(). +/// @param[in] file_interface A non-owning pointer to the application-specified file interface. +/// @lifetime The interface must be kept alive until after the call to Rml::Shutdown. +RMLUICORE_API void SetFileInterface(FileInterface* file_interface); +/// Returns RmlUi's file interface. +RMLUICORE_API FileInterface* GetFileInterface(); + +/// Sets the interface through which all font requests are made. This is not required to be called, but if it is +/// it must be called before Initialise(). +/// @param[in] font_interface A non-owning pointer to the application-specified font engine interface. +/// @lifetime The interface must be kept alive until after the call to Rml::Shutdown. +RMLUICORE_API void SetFontEngineInterface(FontEngineInterface* font_interface); +/// Returns RmlUi's font interface. +RMLUICORE_API FontEngineInterface* GetFontEngineInterface(); + +/// Creates a new element context. +/// @param[in] name The new name of the context. This must be unique. +/// @param[in] dimensions The initial dimensions of the new context. +/// @param[in] render_interface The custom render interface to use, or nullptr to use the default. +/// @lifetime If specified, the render interface must be kept alive until after the context is destroyed or the call to Rml::Shutdown. +/// @return A non-owning pointer to the new context, or nullptr if the context could not be created. +RMLUICORE_API Context* CreateContext(const String& name, const Vector2i& dimensions, RenderInterface* render_interface = nullptr); +/// Removes and destroys a context. +/// @param[in] name The name of the context to remove. +/// @return True if name is a valid context, false otherwise. +RMLUICORE_API bool RemoveContext(const String& name); +/// Fetches a previously constructed context by name. +/// @param[in] name The name of the desired context. +/// @return The desired context, or nullptr if no context exists with the given name. +RMLUICORE_API Context* GetContext(const String& name); +/// Fetches a context by index. +/// @param[in] index The index of the desired context. If this is outside of the valid range of contexts, it will be clamped. +/// @return The requested context, or nullptr if no contexts exist. +RMLUICORE_API Context* GetContext(int index); +/// Returns the number of active contexts. +/// @return The total number of active RmlUi contexts. +RMLUICORE_API int GetNumContexts(); + +/// Adds a new font face to the font engine. The face's family, style and weight will be determined from the face itself. +/// @param[in] file_name The file to load the face from. +/// @param[in] fallback_face True to use this font face for unknown characters in other font faces. +/// @return True if the face was loaded successfully, false otherwise. +RMLUICORE_API bool LoadFontFace(const String& file_name, bool fallback_face = false); +/// Adds a new font face from memory to the font engine. The face's family, style and weight is given by the parameters. +/// @param[in] data A pointer to the data. +/// @param[in] data_size Size of the data in bytes. +/// @param[in] family The family to register the font as. +/// @param[in] style The style to register the font as. +/// @param[in] weight The weight to register the font as. +/// @param[in] fallback_face True to use this font face for unknown characters in other font faces. +/// @return True if the face was loaded successfully, false otherwise. +/// @lifetime The pointed to 'data' must remain available until after the call to Rml::Shutdown. +RMLUICORE_API bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face = false); + +/// Registers a generic RmlUi plugin. +RMLUICORE_API void RegisterPlugin(Plugin* plugin); + +/// Registers a new event type. If the type already exists, it will replace custom event types, but not internal types. +/// @param[in] type The new event type. +/// @param[in] interruptible Whether the event can be interrupted during dispatch. +/// @param[in] bubbles Whether the event executes the bubble phase. If false, only capture and target phase is executed. +/// @param[in] default_action_phase Defines during which phase(s) the 'Element::ProcessDefaultAction' method is called. +/// @return The EventId of the newly created type, or existing type if 'type' is an internal type. +RMLUICORE_API EventId RegisterEventType(const String& type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase = DefaultActionPhase::None); + +/// Forces all texture handles loaded and generated by RmlUi to be released. +RMLUICORE_API void ReleaseTextures(); +/// Forces all compiled geometry handles generated by RmlUi to be released. +RMLUICORE_API void ReleaseCompiledGeometry(); + +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DataController.h b/thirdparty/RmlUi/Include/RmlUi/Core/DataController.h new file mode 100644 index 000000000..17742aea8 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DataController.h @@ -0,0 +1,119 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATACONTROLLER_H +#define RMLUI_CORE_DATACONTROLLER_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" + +namespace Rml { + +class Element; +class DataModel; + + +class RMLUICORE_API DataControllerInstancer : public NonCopyMoveable { +public: + DataControllerInstancer() {} + virtual ~DataControllerInstancer() {} + virtual DataControllerPtr InstanceController(Element* element) = 0; +}; + +template +class DataControllerInstancerDefault final : public DataControllerInstancer { +public: + DataControllerPtr InstanceController(Element* element) override { + return DataControllerPtr(new T(element)); + } +}; + + +/** + Data controller. + + Data controllers are used to respond to some change in the document, + usually by setting data variables. Such document changes are usually + a result of user input. + A data controller is declared in the document by the element attribute: + + data-[type]-[modifier]="[assignment_expression]" + + This is similar to declaration of data views, except that controllers + instead take an assignment expression to set a variable. Note that, as + opposed to views, controllers only respond to certain changes in the + document, not to changed data variables. + + The modifier may or may not be required depending on the data controller. + + */ + +class RMLUICORE_API DataController : public Releasable { +public: + virtual ~DataController(); + + // Initialize the data controller. + // @param[in] model The data model the controller will be attached to. + // @param[in] element The element which spawned the controller. + // @param[in] expression The value of the element's 'data-' attribute which spawned the controller (see above). + // @param[in] modifier The modifier for the given controller type (see above). + // @return True on success. + virtual bool Initialize(DataModel& model, Element* element, const String& expression, const String& modifier) = 0; + + // Returns the attached element if it still exists. + Element* GetElement() const; + + // Returns true if the element still exists. + bool IsValid() const; + +protected: + DataController(Element* element); + +private: + ObserverPtr attached_element; +}; + + +class RMLUICORE_API DataControllers : NonCopyMoveable { +public: + DataControllers(); + ~DataControllers(); + + void Add(DataControllerPtr controller); + + void OnElementRemove(Element* element); + +private: + using ElementControllersMap = UnorderedMultimap; + ElementControllersMap controllers; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h b/thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h new file mode 100644 index 000000000..063c6b012 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DataModel.h @@ -0,0 +1,194 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATAMODEL_H +#define RMLUI_CORE_DATAMODEL_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" +#include "DataTypes.h" +#include "DataTypeRegister.h" + +namespace Rml { + +class DataViews; +class DataControllers; +class Element; + + +class RMLUICORE_API DataModel : NonCopyMoveable { +public: + DataModel(const TransformFuncRegister* transform_register = nullptr); + ~DataModel(); + + void AddView(DataViewPtr view); + void AddController(DataControllerPtr controller); + + bool BindVariable(const String& name, DataVariable variable); + bool BindFunc(const String& name, DataGetFunc get_func, DataSetFunc set_func); + + bool BindEventCallback(const String& name, DataEventFunc event_func); + + bool InsertAlias(Element* element, const String& alias_name, DataAddress replace_with_address); + bool EraseAliases(Element* element); + + DataAddress ResolveAddress(const String& address_str, Element* element) const; + const DataEventFunc* GetEventCallback(const String& name); + + DataVariable GetVariable(const DataAddress& address) const; + bool GetVariableInto(const DataAddress& address, Variant& out_value) const; + + void DirtyVariable(const String& variable_name); + bool IsVariableDirty(const String& variable_name) const; + + bool CallTransform(const String& name, Variant& inout_result, const VariantList& arguments) const; + + // Elements declaring 'data-model' need to be attached. + void AttachModelRootElement(Element* element); + ElementList GetAttachedModelRootElements() const; + + void OnElementRemove(Element* element); + + bool Update(); + +private: + UniquePtr views; + UniquePtr controllers; + + UnorderedMap variables; + DirtyVariables dirty_variables; + + UnorderedMap> function_variable_definitions; + UnorderedMap event_callbacks; + + using ScopedAliases = UnorderedMap>; + ScopedAliases aliases; + + const TransformFuncRegister* transform_register; + + SmallUnorderedSet attached_elements; +}; + + + +class RMLUICORE_API DataModelHandle { +public: + DataModelHandle(DataModel* model = nullptr) : model(model) + {} + + void Update() { + model->Update(); + } + + bool IsVariableDirty(const String& variable_name) { + return model->IsVariableDirty(variable_name); + } + void DirtyVariable(const String& variable_name) { + model->DirtyVariable(variable_name); + } + + explicit operator bool() { return model; } + +private: + DataModel* model; +}; + + +class RMLUICORE_API DataModelConstructor { +public: + template + using DataEventMemberFunc = void(T::*)(DataModelHandle, Event&, const VariantList&); + + DataModelConstructor() : model(nullptr), type_register(nullptr) {} + DataModelConstructor(DataModel* model, DataTypeRegister* type_register) : model(model), type_register(type_register) { + RMLUI_ASSERT(model && type_register); + } + + // Return a handle to the data model being constructed, which can later be used to synchronize variables and update the model. + DataModelHandle GetModelHandle() const { + return DataModelHandle(model); + } + + // Bind a data variable. + // @note For non-scalar types make sure they first have been registered with the appropriate 'Register...()' functions. + template bool Bind(const String& name, T* ptr) { + RMLUI_ASSERTMSG(ptr, "Invalid pointer to data variable"); + return model->BindVariable(name, DataVariable(type_register->GetOrAddScalar(), ptr)); + } + + // Bind a get/set function pair. + bool BindFunc(const String& name, DataGetFunc get_func, DataSetFunc set_func = {}) { + return model->BindFunc(name, std::move(get_func), std::move(set_func)); + } + + // Bind an event callback. + bool BindEventCallback(const String& name, DataEventFunc event_func) { + return model->BindEventCallback(name, std::move(event_func)); + } + // Convenience wrapper around BindEventCallback for member functions. + template + bool BindEventCallback(const String& name, DataEventMemberFunc member_func, T* object_pointer) { + return BindEventCallback(name, [member_func, object_pointer](DataModelHandle handle, Event& event, const VariantList& arguments) { + (object_pointer->*member_func)(handle, event, arguments); + }); + } + + // Register a struct type. + // @note The type applies to every data model associated with the current Context. + // @return A handle which can be used to register struct members. + template + StructHandle RegisterStruct() { + return type_register->RegisterStruct(); + } + + // Register an array type. + // @note The type applies to every data model associated with the current Context. + // @note If 'Container::value_type' represents a non-scalar type, that type must already have been registered with the appropriate 'Register...()' functions. + // @note Container requires the following functions to be implemented: size() and begin(). This is satisfied by several containers such as std::vector and std::array. + template + bool RegisterArray() { + return type_register->RegisterArray(); + } + + // Register a transform function. + // A transform function modifies a variant with optional arguments. It can be called in data expressions using the pipe '|' operator. + // @note The transform function applies to every data model associated with the current Context. + void RegisterTransformFunc(const String& name, DataTransformFunc transform_func) { + type_register->GetTransformFuncRegister()->Register(name, std::move(transform_func)); + } + + explicit operator bool() { return model && type_register; } + +private: + DataModel* model; + DataTypeRegister* type_register; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DataTypeRegister.h b/thirdparty/RmlUi/Include/RmlUi/Core/DataTypeRegister.h new file mode 100644 index 000000000..e91930998 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DataTypeRegister.h @@ -0,0 +1,204 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATATYPEREGISTER_H +#define RMLUI_CORE_DATATYPEREGISTER_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" +#include "Variant.h" +#include "DataTypes.h" +#include "DataVariable.h" + + +namespace Rml { + +template +struct is_valid_data_scalar { + static constexpr bool value = std::is_arithmetic::value + || std::is_same::type, String>::value; +}; + + +template +class StructHandle { +public: + StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : type_register(type_register), struct_definition(struct_definition) {} + + template + StructHandle& RegisterMember(const String& name, MemberType Object::* member_ptr); + + StructHandle& RegisterMemberFunc(const String& name, MemberGetFunc get_func, MemberSetFunc set_func = nullptr); + + explicit operator bool() const { + return type_register && struct_definition; + } + +private: + DataTypeRegister* type_register; + StructDefinition* struct_definition; +}; + + +class RMLUICORE_API TransformFuncRegister { +public: + void Register(const String& name, DataTransformFunc transform_func); + + bool Call(const String& name, Variant& inout_result, const VariantList& arguments) const; + +private: + UnorderedMap transform_functions; +}; + + + +class RMLUICORE_API DataTypeRegister : NonCopyMoveable { +public: + DataTypeRegister(); + ~DataTypeRegister(); + + template + StructHandle RegisterStruct() + { + static_assert(std::is_class::value, "Type must be a struct or class type."); + FamilyId id = Family::Id(); + + auto struct_variable = MakeUnique(); + StructDefinition* struct_variable_raw = struct_variable.get(); + + bool inserted = type_register.emplace(id, std::move(struct_variable)).second; + if (!inserted) + { + RMLUI_ERRORMSG("Type already declared"); + return StructHandle(nullptr, nullptr); + } + + return StructHandle(this, struct_variable_raw); + } + + template + bool RegisterArray() + { + using value_type = typename Container::value_type; + VariableDefinition* value_variable = GetOrAddScalar(); + RMLUI_ASSERTMSG(value_variable, "Underlying value type of array has not been registered."); + if (!value_variable) + return false; + + FamilyId container_id = Family::Id(); + + auto array_variable = MakeUnique>(value_variable); + + bool inserted = type_register.emplace(container_id, std::move(array_variable)).second; + if (!inserted) + { + RMLUI_ERRORMSG("Array type already declared."); + return false; + } + + return true; + } + + template + VariableDefinition* RegisterMemberFunc(MemberGetFunc get_func, MemberSetFunc set_func) + { + FamilyId id = Family>::Id(); + + auto result = type_register.emplace(id, nullptr); + auto& it = result.first; + bool inserted = result.second; + + if (inserted) + it->second = MakeUnique>(get_func, set_func); + + return it->second.get(); + } + + template::value, int>::type = 0> + VariableDefinition* GetOrAddScalar() + { + FamilyId id = Family::Id(); + + auto result = type_register.emplace(id, nullptr); + bool inserted = result.second; + UniquePtr& definition = result.first->second; + + if (inserted) + definition = MakeUnique>(); + + return definition.get(); + } + + template::value, int>::type = 0> + VariableDefinition* GetOrAddScalar() + { + return Get(); + } + + template + VariableDefinition* Get() + { + FamilyId id = Family::Id(); + auto it = type_register.find(id); + if (it == type_register.end()) + { + RMLUI_ERRORMSG("Desired data type T not registered with the type register, please use the 'Register...()' functions before binding values, adding members, or registering arrays of non-scalar types.") + return nullptr; + } + + return it->second.get(); + } + + TransformFuncRegister* GetTransformFuncRegister() { + return &transform_register; + } + +private: + UnorderedMap> type_register; + + TransformFuncRegister transform_register; + +}; + +template +template +inline StructHandle& StructHandle::RegisterMember(const String& name, MemberType Object::* member_ptr) { + VariableDefinition* member_type = type_register->GetOrAddScalar(); + struct_definition->AddMember(name, MakeUnique>(member_type, member_ptr)); + return *this; +} +template +inline StructHandle& StructHandle::RegisterMemberFunc(const String& name, MemberGetFunc get_func, MemberSetFunc set_func) { + VariableDefinition* definition = type_register->RegisterMemberFunc(get_func, set_func); + struct_definition->AddMember(name, MakeUnique(definition)); + return *this; +} + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DataTypes.h b/thirdparty/RmlUi/Include/RmlUi/Core/DataTypes.h new file mode 100644 index 000000000..c2d092f3c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DataTypes.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATADEFINITIONS_H +#define RMLUI_CORE_DATADEFINITIONS_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +class VariableDefinition; +class DataTypeRegister; +class TransformFuncRegister; +class DataModelHandle; +class DataVariable; + +using DataGetFunc = Function; +using DataSetFunc = Function; +using DataTransformFunc = Function; +using DataEventFunc = Function; + +template using MemberGetFunc = void(T::*)(Variant&); +template using MemberSetFunc = void(T::*)(const Variant&); + +using DirtyVariables = SmallUnorderedSet; + +struct DataAddressEntry { + DataAddressEntry(String name) : name(name), index(-1) { } + DataAddressEntry(int index) : index(index) { } + String name; + int index; +}; +using DataAddress = Vector; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DataVariable.h b/thirdparty/RmlUi/Include/RmlUi/Core/DataVariable.h new file mode 100644 index 000000000..413247723 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DataVariable.h @@ -0,0 +1,265 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATAVARIABLE_H +#define RMLUI_CORE_DATAVARIABLE_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" +#include "Variant.h" +#include "DataTypes.h" +#include + +namespace Rml { + +enum class DataVariableType { Scalar, Array, Struct, Function, MemberFunction }; + + +class RMLUICORE_API DataVariable { +public: + DataVariable() {} + DataVariable(VariableDefinition* definition, void* ptr) : definition(definition), ptr(ptr) {} + + explicit operator bool() const { return definition; } + + bool Get(Variant& variant); + bool Set(const Variant& variant); + int Size(); + DataVariable Child(const DataAddressEntry& address); + DataVariableType Type(); + +private: + VariableDefinition* definition = nullptr; + void* ptr = nullptr; +}; + + + +class RMLUICORE_API VariableDefinition { +public: + virtual ~VariableDefinition() = default; + DataVariableType Type() const { return type; } + + virtual bool Get(void* ptr, Variant& variant); + virtual bool Set(void* ptr, const Variant& variant); + + virtual int Size(void* ptr); + virtual DataVariable Child(void* ptr, const DataAddressEntry& address); + +protected: + VariableDefinition(DataVariableType type) : type(type) {} + +private: + DataVariableType type; +}; + + +RMLUICORE_API DataVariable MakeLiteralIntVariable(int value); + + +template +class ScalarDefinition final : public VariableDefinition { +public: + ScalarDefinition() : VariableDefinition(DataVariableType::Scalar) {} + + bool Get(void* ptr, Variant& variant) override + { + variant = *static_cast(ptr); + return true; + } + bool Set(void* ptr, const Variant& variant) override + { + return variant.GetInto(*static_cast(ptr)); + } +}; + + +class FuncDefinition final : public VariableDefinition { +public: + + FuncDefinition(DataGetFunc get, DataSetFunc set) : VariableDefinition(DataVariableType::Function), get(std::move(get)), set(std::move(set)) {} + + bool Get(void* /*ptr*/, Variant& variant) override + { + if (!get) + return false; + get(variant); + return true; + } + bool Set(void* /*ptr*/, const Variant& variant) override + { + if (!set) + return false; + set(variant); + return true; + } +private: + DataGetFunc get; + DataSetFunc set; +}; + + +template +class ArrayDefinition final : public VariableDefinition { +public: + ArrayDefinition(VariableDefinition* underlying_definition) : VariableDefinition(DataVariableType::Array), underlying_definition(underlying_definition) {} + + int Size(void* ptr) override { + return int(static_cast(ptr)->size()); + } + +protected: + DataVariable Child(void* void_ptr, const DataAddressEntry& address) override + { + Container* ptr = static_cast(void_ptr); + const int index = address.index; + + const int container_size = int(ptr->size()); + if (index < 0 || index >= container_size) + { + if (address.name == "size") + return MakeLiteralIntVariable(container_size); + + Log::Message(Log::LT_WARNING, "Data array index out of bounds."); + return DataVariable(); + } + + auto it = ptr->begin(); + std::advance(it, index); + + void* next_ptr = &(*it); + return DataVariable(underlying_definition, next_ptr); + } + +private: + VariableDefinition* underlying_definition; +}; + + +class StructMember { +public: + StructMember(VariableDefinition* definition) : definition(definition) {} + virtual ~StructMember() = default; + + VariableDefinition* GetDefinition() const { return definition; } + + virtual void* GetPointer(void* base_ptr) = 0; + +private: + VariableDefinition* definition; +}; + +template +class StructMemberObject final : public StructMember { +public: + StructMemberObject(VariableDefinition* definition, MemberType Object::* member_ptr) : StructMember(definition), member_ptr(member_ptr) {} + + void* GetPointer(void* base_ptr) override { + return &(static_cast(base_ptr)->*member_ptr); + } + +private: + MemberType Object::* member_ptr; +}; + +class StructMemberFunc final : public StructMember { +public: + StructMemberFunc(VariableDefinition* definition) : StructMember(definition) {} + void* GetPointer(void* base_ptr) override { + return base_ptr; + } +}; + + +class StructDefinition final : public VariableDefinition { +public: + StructDefinition() : VariableDefinition(DataVariableType::Struct) + {} + + DataVariable Child(void* ptr, const DataAddressEntry& address) override + { + const String& name = address.name; + if (name.empty()) + { + Log::Message(Log::LT_WARNING, "Expected a struct member name but none given."); + return DataVariable(); + } + + auto it = members.find(name); + if (it == members.end()) + { + Log::Message(Log::LT_WARNING, "Member %s not found in data struct.", name.c_str()); + return DataVariable(); + } + + void* next_ptr = it->second->GetPointer(ptr); + VariableDefinition* next_definition = it->second->GetDefinition(); + + return DataVariable(next_definition, next_ptr); + } + + void AddMember(const String& name, UniquePtr member) + { + RMLUI_ASSERT(member); + bool inserted = members.emplace(name, std::move(member)).second; + RMLUI_ASSERTMSG(inserted, "Member name already exists."); + (void)inserted; + } + +private: + SmallUnorderedMap> members; +}; + + +template +class MemberFuncDefinition final : public VariableDefinition { +public: + MemberFuncDefinition(MemberGetFunc get, MemberSetFunc set) : VariableDefinition(DataVariableType::MemberFunction), get(get), set(set) {} + + bool Get(void* ptr, Variant& variant) override + { + if (!get) + return false; + (static_cast(ptr)->*get)(variant); + return true; + } + bool Set(void* ptr, const Variant& variant) override + { + if (!set) + return false; + (static_cast(ptr)->*set)(variant); + return true; + } +private: + MemberGetFunc get; + MemberSetFunc set; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DataView.h b/thirdparty/RmlUi/Include/RmlUi/Core/DataView.h new file mode 100644 index 000000000..cf5b8b4a7 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DataView.h @@ -0,0 +1,131 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATAVIEW_H +#define RMLUI_CORE_DATAVIEW_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" +#include "DataTypes.h" + +namespace Rml { + +class Element; +class DataModel; + + +class RMLUICORE_API DataViewInstancer : public NonCopyMoveable { +public: + DataViewInstancer() {} + virtual ~DataViewInstancer() {} + virtual DataViewPtr InstanceView(Element* element) = 0; +}; + +template +class DataViewInstancerDefault final : public DataViewInstancer { +public: + DataViewPtr InstanceView(Element* element) override { + return DataViewPtr(new T(element)); + } +}; + +/** + Data view. + + Data views are used to present a data variable in the document by different means. + A data view is declared in the document by the element attribute: + + data-[type]-[modifier]="[expression]" + + The modifier may or may not be required depending on the data view. + */ + +class RMLUICORE_API DataView : public Releasable { +public: + virtual ~DataView(); + + // Initialize the data view. + // @param[in] model The data model the view will be attached to. + // @param[in] element The element which spawned the view. + // @param[in] expression The value of the element's 'data-' attribute which spawned the view (see above). + // @param[in] modifier_or_inner_rml The modifier for the given view type (see above), or the inner rml contents for structural data views. + // @return True on success. + virtual bool Initialize(DataModel& model, Element* element, const String& expression, const String& modifier_or_inner_rml) = 0; + + // Update the data view. + // Returns true if the update resulted in a document change. + virtual bool Update(DataModel& model) = 0; + + // Returns the list of data variable name(s) which can modify this view. + virtual StringList GetVariableNameList() const = 0; + + // Returns the attached element if it still exists. + Element* GetElement() const; + + // Returns the depth of the attached element in the document tree. + int GetElementDepth() const; + + // Returns true if the element still exists. + bool IsValid() const; + +protected: + DataView(Element* element); + +private: + ObserverPtr attached_element; + int element_depth; +}; + + + +class RMLUICORE_API DataViews : NonCopyMoveable { +public: + DataViews(); + ~DataViews(); + + void Add(DataViewPtr view); + + void OnElementRemove(Element* element); + + bool Update(DataModel& model, const DirtyVariables& dirty_variables); + +private: + using DataViewList = Vector; + + DataViewList views; + + DataViewList views_to_add; + DataViewList views_to_remove; + + using NameViewMap = UnorderedMultimap; + NameViewMap name_view_map; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Debug.h b/thirdparty/RmlUi/Include/RmlUi/Core/Debug.h new file mode 100644 index 000000000..354e33a5a --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Debug.h @@ -0,0 +1,114 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DEBUG_H +#define RMLUI_CORE_DEBUG_H + +#include "Header.h" + +// Define for breakpointing. +#if defined (RMLUI_PLATFORM_WIN32) + #if defined (__MINGW32__) + #define RMLUI_BREAK {asm("int $0x03");} + #elif defined (_MSC_VER) + #define RMLUI_BREAK {__debugbreak();} + #else + #define RMLUI_BREAK + #endif +#elif defined (RMLUI_PLATFORM_LINUX) + #if defined __GNUC__ + #define RMLUI_BREAK {__builtin_trap();} + #else + #define RMLUI_BREAK + #endif +#elif defined (RMLUI_PLATFORM_MACOSX) + #define RMLUI_BREAK {__builtin_trap();} // namespace Rml +#endif + + + +// Define the LT_ASSERT and RMLUI_VERIFY macros. +#if !defined RMLUI_DEBUG +#define RMLUI_ASSERT(x) +#define RMLUI_ASSERTMSG(x, m) +#define RMLUI_ERROR +#define RMLUI_ERRORMSG(m) +#define RMLUI_VERIFY(x) x +#define RMLUI_ASSERT_NONRECURSIVE +#else +namespace Rml { + +bool RMLUICORE_API Assert(const char* message, const char* file, int line); +#define RMLUI_ASSERT(x) \ +if (!(x)) \ +{ \ + if (!(::Rml::Assert("RMLUI_ASSERT("#x")", __FILE__, __LINE__ ))) \ + { \ + RMLUI_BREAK; \ + } \ +} +#define RMLUI_ASSERTMSG(x, m) \ +if (!(x)) \ +{ \ + if (!(::Rml::Assert(m, __FILE__, __LINE__ ))) \ + { \ + RMLUI_BREAK; \ + } \ +} +#define RMLUI_ERROR \ +if (!(::Rml::Assert("RMLUI_ERROR", __FILE__, __LINE__))) \ +{ \ + RMLUI_BREAK; \ +} +#define RMLUI_ERRORMSG(m) \ +if (!(::Rml::Assert(m, __FILE__, __LINE__))) \ +{ \ + RMLUI_BREAK; \ +} +#define RMLUI_VERIFY(x) RMLUI_ASSERT(x) + +struct RmlUiAssertNonrecursive { + bool& entered; + RmlUiAssertNonrecursive(bool& entered) : entered(entered) { + RMLUI_ASSERTMSG(!entered, "A method defined as non-recursive was entered twice!"); + entered = true; + } + ~RmlUiAssertNonrecursive() { + entered = false; + } +}; + +#define RMLUI_ASSERT_NONRECURSIVE \ +static bool rmlui_nonrecursive_entered = false; \ +RmlUiAssertNonrecursive rmlui_nonrecursive(rmlui_nonrecursive_entered) + +} // namespace Rml +#endif + + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Decorator.h b/thirdparty/RmlUi/Include/RmlUi/Core/Decorator.h new file mode 100644 index 000000000..559ba9ce4 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Decorator.h @@ -0,0 +1,97 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATOR_H +#define RMLUI_CORE_DECORATOR_H + +#include "Header.h" +#include "Texture.h" +#include "Types.h" + +namespace Rml { + +class DecoratorInstancer; +class Element; +class PropertyDictionary; +class Property; +struct Texture; + +/** + The abstract base class for any visual object that can be attached to any element. + + @author Peter Curry + */ + +class RMLUICORE_API Decorator +{ +public: + Decorator(); + virtual ~Decorator(); + + /// Called on a decorator to generate any required per-element data for a newly decorated element. + /// @param[in] element The newly decorated element. + /// @return A handle to a decorator-defined data handle, or nullptr if none is needed for the element. + virtual DecoratorDataHandle GenerateElementData(Element* element) const = 0; + /// Called to release element data generated by this decorator. + /// @param[in] element_data The element data handle to release. + virtual void ReleaseElementData(DecoratorDataHandle element_data) const = 0; + + /// Called to render the decorator on an element. + /// @param[in] element The element to render the decorator on. + /// @param[in] element_data The handle to the data generated by the decorator for the element. + virtual void RenderElement(Element* element, DecoratorDataHandle element_data) const = 0; + + /// Value specifying an invalid or non-existent Decorator data handle. + static const DecoratorDataHandle INVALID_DECORATORDATAHANDLE = 0; + +protected: + /// Attempts to load a texture into the list of textures in use by the decorator. + /// @param[in] texture_name The name of the texture to load. + /// @param[in] rcss_path The RCSS file the decorator definition was loaded from; this is used to resolve relative paths. + /// @return The index of the texture if the load was successful, or -1 if the load failed. + int LoadTexture(const String& texture_name, const String& rcss_path); + /// Adds a texture if it is valid into the list of textures in use by the decorator. + /// @param[in] texture The texture to add. + /// @return The index of the texture if it is successful, or -1 if it is invalid. + int AddTexture(const Texture& texture); + /// Get number of textures in use by the decorator. + int GetNumTextures() const; + /// Returns one of the decorator's previously loaded textures. + /// @param[in] index The index of the desired texture. + /// @return The texture at the appropriate index, or nullptr if the index was invalid. + const Texture* GetTexture(int index = 0) const; + +private: + // Stores a list of textures in use by this decorator. + // Optimized for the common case of a single texture. + Texture first_texture; + Vector< Texture > additional_textures; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/DecoratorInstancer.h b/thirdparty/RmlUi/Include/RmlUi/Core/DecoratorInstancer.h new file mode 100644 index 000000000..08656d7c2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/DecoratorInstancer.h @@ -0,0 +1,99 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORINSTANCER_H +#define RMLUI_CORE_DECORATORINSTANCER_H + +#include "Header.h" +#include "PropertyDictionary.h" +#include "PropertySpecification.h" + +namespace Rml { + +struct Sprite; +class StyleSheet; +class Decorator; +class DecoratorInstancerInterface; +class PropertyDefinition; + +/** + An element instancer provides a method for allocating and deallocating decorators. + + It is important at the same instancer that allocated a decorator releases it. This ensures there are no issues with + memory from different DLLs getting mixed up. + + @author Peter Curry + */ + +class RMLUICORE_API DecoratorInstancer +{ +public: + DecoratorInstancer(); + virtual ~DecoratorInstancer(); + + /// Instances a decorator given the property tag and attributes from the RCSS file. + /// @param[in] name The type of decorator desired. For example, "decorator: simple(...);" is declared as type "simple". + /// @param[in] properties All RCSS properties associated with the decorator. + /// @param[in] interface An interface for querying the active style sheet. + /// @return A shared_ptr to the decorator if it was instanced successfully. + virtual SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) = 0; + + /// Returns the property specification associated with the instancer. + const PropertySpecification& GetPropertySpecification() const; + +protected: + /// Registers a property for the decorator. + /// @param[in] property_name The name of the new property (how it is specified through RCSS). + /// @param[in] default_value The default value to be used. + /// @return The new property definition, ready to have parsers attached. + PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value); + /// Registers a shorthand property definition. Specify a shorthand name of 'decorator' to parse anonymous decorators. + /// @param[in] shorthand_name The name to register the new shorthand property under. + /// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed. + /// @param[in] type The type of shorthand to declare. + /// @param True if all the property names exist, false otherwise. + ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type); + +private: + PropertySpecification properties; +}; + + +class RMLUICORE_API DecoratorInstancerInterface { +public: + DecoratorInstancerInterface(const StyleSheet& style_sheet) : style_sheet(style_sheet) {} + + /// Get a sprite from any @spritesheet in the style sheet the decorator is being instanced on. + const Sprite* GetSprite(const String& name) const; + +private: + const StyleSheet& style_sheet; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Dictionary.h b/thirdparty/RmlUi/Include/RmlUi/Core/Dictionary.h new file mode 100644 index 000000000..d5c12407c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Dictionary.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DICTIONARY_H +#define RMLUI_CORE_DICTIONARY_H + +#include "Header.h" +#include "Variant.h" + +namespace Rml { + +inline Variant* GetIf(Dictionary& dictionary, const String& key) +{ + auto it = dictionary.find(key); + if (it != dictionary.end()) + return &(it->second); + return nullptr; +} +inline const Variant* GetIf(const Dictionary& dictionary, const String& key) +{ + auto it = dictionary.find(key); + if (it != dictionary.end()) + return &(it->second); + return nullptr; +} +template +inline T Get(const Dictionary& dictionary, const String& key, const T& default_value) +{ + T result = default_value; + auto it = dictionary.find(key); + if (it != dictionary.end()) + it->second.GetInto(result); + return result; +} + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Element.h b/thirdparty/RmlUi/Include/RmlUi/Core/Element.h new file mode 100644 index 000000000..bb86b805c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Element.h @@ -0,0 +1,758 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENT_H +#define RMLUI_CORE_ELEMENT_H + +#include "ScriptInterface.h" +#include "Header.h" +#include "Box.h" +#include "ComputedValues.h" +#include "Event.h" +#include "ObserverPtr.h" +#include "Property.h" +#include "Types.h" +#include "Transform.h" +#include "Tween.h" + +namespace Rml { + +class Context; +class DataModel; +class Decorator; +class ElementInstancer; +class EventDispatcher; +class EventListener; +class ElementBackground; +class ElementBorder; +class ElementDecoration; +class ElementDefinition; +class ElementDocument; +class ElementScroll; +class ElementStyle; +class PropertiesIteratorView; +class FontFaceHandleDefault; +class PropertyDictionary; +class RenderInterface; +class TransformState; +class StyleSheet; +struct ElementMeta; + +/** + A generic element in the DOM tree. + + @author Peter Curry + */ + +class RMLUICORE_API Element : public ScriptInterface, public EnableObserverPtr +{ +public: + RMLUI_RTTI_DefineWithParent(Element, ScriptInterface) + + /// Constructs a new RmlUi element. This should not be called directly; use the Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + Element(const String& tag); + virtual ~Element(); + + /// Clones this element, returning a new, unparented element. + ElementPtr Clone() const; + + /** @name Classes + */ + //@{ + /// Sets or removes a class on the element. + /// @param[in] class_name The name of the class to add or remove from the class list. + /// @param[in] activate True if the class is to be added, false to be removed. + void SetClass(const String& class_name, bool activate); + /// Checks if a class is set on the element. + /// @param[in] class_name The name of the class to check for. + /// @return True if the class is set on the element, false otherwise. + bool IsClassSet(const String& class_name) const; + /// Specifies the entire list of classes for this element. This will replace any others specified. + /// @param[in] class_names The list of class names to set on the style, separated by spaces. + void SetClassNames(const String& class_names); + /// Return the active class list. + /// @return The space-separated list of classes active on the element. + String GetClassNames() const; + //@} + + /// Returns the active style sheet for this element. This may be nullptr. + /// @return The element's style sheet. + virtual const SharedPtr& GetStyleSheet() const; + + /// Returns the element's definition. + /// @return The element's definition. + const ElementDefinition* GetDefinition(); + + /// Fills a string with the full address of this element. + /// @param[in] include_pseudo_classes True if the address is to include the pseudo-classes of the leaf element. + /// @return The address of the element, including its full parentage. + String GetAddress(bool include_pseudo_classes = false, bool include_parents = true) const; + + /// Sets the position of this element, as a two-dimensional offset from another element. + /// @param[in] offset The offset (in pixels) of our primary box's top-left border corner from our offset parent's top-left border corner. + /// @param[in] offset_parent The element this element is being positioned relative to. + /// @param[in] offset_fixed True if the element is fixed in place (and will not scroll), false if not. + void SetOffset(const Vector2f& offset, Element* offset_parent, bool offset_fixed = false); + /// Returns the position of the top-left corner of one of the areas of this element's primary box, relative to its + /// offset parent's top-left border corner. + /// @param[in] area The desired area position. + /// @return The relative offset. + Vector2f GetRelativeOffset(Box::Area area = Box::CONTENT); + /// Returns the position of the top-left corner of one of the areas of this element's primary box, relative to + /// the element root. + /// @param[in] area The desired area position. + /// @return The absolute offset. + Vector2f GetAbsoluteOffset(Box::Area area = Box::CONTENT); + + /// Sets an alternate area to use as the client area. + /// @param[in] client_area The box area to use as the element's client area. + void SetClientArea(Box::Area client_area); + /// Returns the area the element uses as its client area. + /// @return The box area used as the element's client area. + Box::Area GetClientArea() const; + + /// Sets the dimensions of the element's internal content. This is the tightest fitting box surrounding all of + /// this element's logical children, plus the element's padding. + /// @param[in] content_offset The offset of the box's internal content. + /// @param[in] content_box The dimensions of the box's internal content. + void SetContentBox(const Vector2f& content_offset, const Vector2f& content_box); + /// Sets the box describing the size of the element, and removes all others. + /// @param[in] box The new dimensions box for the element. + void SetBox(const Box& box); + /// Adds a box to the end of the list describing this element's geometry. + /// @param[in] box The auxiliary box for the element. + void AddBox(const Box& box); + /// Returns the main box describing the size of the element. + /// @return The box. + const Box& GetBox(); + /// Returns one of the boxes describing the size of the element. + /// @param[in] index The index of the desired box, with 0 being the main box. If outside of bounds, the main box will be returned. + /// @return The requested box. + const Box& GetBox(int index); + /// Returns the number of boxes making up this element's geometry. + /// @return the number of boxes making up this element's geometry. + int GetNumBoxes(); + + /// Returns the baseline of the element, in pixels offset from the bottom of the element's content area. + /// @return The element's baseline. A negative baseline will be further 'up' the element, a positive on further 'down'. The default element will return 0. + virtual float GetBaseline() const; + /// Gets the intrinsic dimensions of this element, if it is of a type that has an inherent size. This size will + /// only be overriden by a styled width or height. + /// @param[in] dimensions The dimensions to size, if appropriate. + /// @return True if the element has intrinsic dimensions, false otherwise. The default element will return false. + virtual bool GetIntrinsicDimensions(Vector2f& dimensions); + + /// Checks if a given point in screen coordinates lies within the bordered area of this element. + /// @param[in] point The point to test. + /// @return True if the element is within this element, false otherwise. + virtual bool IsPointWithinElement(const Vector2f& point); + + /// Returns the visibility of the element. + /// @return True if the element is visible, false otherwise. + bool IsVisible() const; + /// Returns the z-index of the element. + /// @return The element's z-index. + float GetZIndex() const; + + /// Returns the element's font face handle. + /// @return The element's font face handle. + FontFaceHandle GetFontFaceHandle() const; + + /** @name Properties + */ + //@{ + /// Sets a local property override on the element. + /// @param[in] name The name of the new property. + /// @param[in] value The new property to set. + /// @return True if the property parsed successfully, false otherwise. + bool SetProperty(const String& name, const String& value); + /// Sets a local property override on the element to a pre-parsed value. + /// @param[in] name The name of the new property. + /// @param[in] property The parsed property to set. + /// @return True if the property was set successfully, false otherwise. + bool SetProperty(PropertyId id, const Property& property); + /// Removes a local property override on the element; its value will revert to that defined in the style sheet. + /// @param[in] name The name of the local property definition to remove. + void RemoveProperty(const String& name); + void RemoveProperty(PropertyId id); + /// Returns one of this element's properties. If the property is not defined for this element and not inherited + /// from an ancestor, the default value will be returned. + /// @param[in] name The name of the property to fetch the value for. + /// @return The value of this property for this element, or nullptr if no property exists with the given name. + const Property* GetProperty(const String& name); + const Property* GetProperty(PropertyId id); + /// Returns the values of one of this element's properties. + /// @param[in] name The name of the property to get. + /// @return The value of this property. + template < typename T > + T GetProperty(const String& name); + /// Returns one of this element's properties. If this element is not defined this property, nullptr will be + /// returned. + /// @param[in] name The name of the property to fetch the value for. + /// @return The value of this property for this element, or nullptr if this property has not been explicitly defined for this element. + const Property* GetLocalProperty(const String& name); + const Property* GetLocalProperty(PropertyId id); + /// Returns the local style properties, excluding any properties from local class. + /// @return The local properties for this element, or nullptr if no properties defined + const PropertyMap& GetLocalStyleProperties(); + + /// Resolves a property with units of number, percentage, length, or angle to their canonical unit (unit-less, 'px', or 'rad'). + /// Numbers and percentages are scaled by the base value and returned. + /// @param[in] property The property to resolve the value for. + /// @param[in] base_value The value that is scaled by the number or percentage value, if applicable. + /// @return The resolved value in their canonical unit, or zero if it could not be resolved. + float ResolveNumericProperty(const Property *property, float base_value); + /// Resolves a property with units of number, percentage, length, or angle to their canonical unit (unit-less, 'px', or 'rad'). + /// Numbers and percentages are scaled according to the relative target of the property definition. + /// @param[in] name The property to resolve the value for. + /// @return The resolved value in their canonical unit, or zero if it could not be resolved. + float ResolveNumericProperty(const String& property_name); + + /// Returns the size of the containing block. Often percentages are scaled relative to this. + Vector2f GetContainingBlock(); + /// Returns 'position' property value from element's computed values. + Style::Position GetPosition(); + /// Returns 'float' property value from element's computed values. + Style::Float GetFloat(); + /// Returns 'display' property value from element's computed values. + Style::Display GetDisplay(); + /// Returns 'line-height' property value from element's computed values. + float GetLineHeight(); + + /// Project a 2D point in pixel coordinates onto the element's plane. + /// @param[in-out] point The point to project in, and the resulting projected point out. + /// @return True on success, false if transformation matrix is singular. + bool Project(Vector2f& point) const noexcept; + + /// Start an animation of the given property on this element. + /// If an animation of the same property name exists, it will be replaced. + /// If start_value is null, the current property value on this element is used. + /// @return True if a new animation was added. + bool Animate(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{}, int num_iterations = 1, bool alternate_direction = true, float delay = 0.0f, const Property* start_value = nullptr); + + /// Add a key to an animation, extending its duration. + /// If no animation exists for the given property name, the call will be ignored. + /// @return True if a new animation key was added. + bool AddAnimationKey(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{}); + + /// Iterator for the local (non-inherited) properties defined on this element. + /// @warning Modifying the element's properties or classes invalidates the iterator. + /// @return Iterator to the first property defined on this element. + PropertiesIteratorView IterateLocalProperties() const; + ///@} + + /** @name Pseudo-classes + */ + //@{ + /// Sets or removes a pseudo-class on the element. + /// @param[in] pseudo_class The pseudo class to activate or deactivate. + /// @param[in] activate True if the pseudo-class is to be activated, false to be deactivated. + void SetPseudoClass(const String& pseudo_class, bool activate); + /// Checks if a specific pseudo-class has been set on the element. + /// @param[in] pseudo_class The name of the pseudo-class to check for. + /// @return True if the pseudo-class is set on the element, false if not. + bool IsPseudoClassSet(const String& pseudo_class) const; + /// Checks if a complete set of pseudo-classes are set on the element. + /// @param[in] pseudo_classes The set of pseudo-classes to check for. + /// @return True if all of the pseudo-classes are set, false if not. + bool ArePseudoClassesSet(const PseudoClassList& pseudo_classes) const; + /// Gets a list of the current active pseudo-classes. + /// @return The list of active pseudo-classes. + const PseudoClassList& GetActivePseudoClasses() const; + //@} + + /** @name Attributes + */ + //@{ + /// Sets an attribute on the element. + /// @param[in] name Name of the attribute. + /// @param[in] value Value of the attribute. + template< typename T > + void SetAttribute(const String& name, const T& value); + /// Gets the specified attribute. + /// @param[in] name Name of the attribute to retrieve. + /// @return A variant representing the attribute, or nullptr if the attribute doesn't exist. + Variant* GetAttribute(const String& name); + /// Gets the specified attribute, with default value. + /// @param[in] name Name of the attribute to retrieve. + /// @param[in] default_value Value to return if the attribute doesn't exist. + template< typename T > + T GetAttribute(const String& name, const T& default_value) const; + /// Checks if the element has a certain attribute. + /// @param[in] name The name of the attribute to check for. + /// @return True if the element has the given attribute, false if not. + bool HasAttribute(const String& name) const; + /// Removes the attribute from the element. + /// @param[in] name Name of the attribute. + void RemoveAttribute(const String& name); + /// Set a group of attributes. + /// @param[in] attributes Attributes to set. + void SetAttributes(const ElementAttributes& attributes); + /// Get the attributes of the element. + /// @return The attributes + const ElementAttributes& GetAttributes() const { return attributes; } + /// Returns the number of attributes on the element. + /// @return The number of attributes on the element. + int GetNumAttributes() const; + //@} + + /// Gets the outer-most focus element down the tree from this node. + /// @return Outer-most focus element. + Element* GetFocusLeafNode(); + + /// Returns the element's context. + /// @return The context this element's document exists within. + Context* GetContext() const; + + /** @name DOM Properties + */ + //@{ + + /// Gets the name of the element. + /// @return The name of the element. + const String& GetTagName() const; + + /// Gets the id of the element. + /// @return The element's id. + const String& GetId() const; + /// Sets the id of the element. + /// @param[in] id The new id of the element. + void SetId(const String& id); + + /// Gets the horizontal offset from the context's left edge to element's left border edge. + /// @return The horizontal offset of the element within its context, in pixels. + float GetAbsoluteLeft(); + /// Gets the vertical offset from the context's top edge to element's top border edge. + /// @return The vertical offset of the element within its context, in pixels. + float GetAbsoluteTop(); + + /// Gets the horizontal offset from the element's left border edge to the left edge of its client area. This is + /// usually the edge of the padding, but may be the content area for some replaced elements. + /// @return The horizontal offset of the element's client area, in pixels. + float GetClientLeft(); + /// Gets the vertical offset from the element's top border edge to the top edge of its client area. This is + /// usually the edge of the padding, but may be the content area for some replaced elements. + /// @return The vertical offset of the element's client area, in pixels. + float GetClientTop(); + /// Gets the width of the element's client area. This is usually the padded area less the vertical scrollbar + /// width, but may be the content area for some replaced elements. + /// @return The width of the element's client area, usually including padding but not the vertical scrollbar width, border or margin. + float GetClientWidth(); + /// Gets the height of the element's client area. This is usually the padded area less the horizontal scrollbar + /// height, but may be the content area for some replaced elements. + /// @return The inner height of the element, usually including padding but not the horizontal scrollbar height, border or margin. + float GetClientHeight(); + + /// Returns the element from which all offset calculations are currently computed. + /// @return This element's offset parent. + Element* GetOffsetParent(); + /// Gets the distance from this element's left border to its offset parent's left border. + /// @return The horizontal distance (in pixels) from this element's offset parent to itself. + float GetOffsetLeft(); + /// Gets the distance from this element's top border to its offset parent's top border. + /// @return The vertical distance (in pixels) from this element's offset parent to itself. + float GetOffsetTop(); + /// Gets the width of the element, including the client area, padding, borders and scrollbars, but not margins. + /// @return The width of the rendered element, in pixels. + float GetOffsetWidth(); + /// Gets the height of the element, including the client area, padding, borders and scrollbars, but not margins. + /// @return The height of the rendered element, in pixels. + float GetOffsetHeight(); + + /// Gets the left scroll offset of the element. + /// @return The element's left scroll offset. + float GetScrollLeft(); + /// Sets the left scroll offset of the element. + /// @param[in] scroll_left The element's new left scroll offset. + void SetScrollLeft(float scroll_left); + /// Gets the top scroll offset of the element. + /// @return The element's top scroll offset. + float GetScrollTop(); + /// Sets the top scroll offset of the element. + /// @param[in] scroll_top The element's new top scroll offset. + void SetScrollTop(float scroll_top); + /// Gets the width of the scrollable content of the element; it includes the element padding but not its margin. + /// @return The width (in pixels) of the of the scrollable content of the element. + float GetScrollWidth(); + /// Gets the height of the scrollable content of the element; it includes the element padding but not its margin. + /// @return The height (in pixels) of the of the scrollable content of the element. + float GetScrollHeight(); + + /// Gets the object representing the declarations of an element's style attributes. + /// @return The element's style. + ElementStyle* GetStyle() const; + + /// Gets the document this element belongs to. + /// @return This element's document. + ElementDocument* GetOwnerDocument() const; + + /// Gets this element's parent node. + /// @return This element's parent. + Element* GetParentNode() const; + + /// Gets the element immediately following this one in the tree. + /// @return This element's next sibling element, or nullptr if there is no sibling element. + Element* GetNextSibling() const; + /// Gets the element immediately preceding this one in the tree. + /// @return This element's previous sibling element, or nullptr if there is no sibling element. + Element* GetPreviousSibling() const; + + /// Returns the first child of this element. + /// @return This element's first child, or nullptr if it contains no children. + Element* GetFirstChild() const; + /// Gets the last child of this element. + /// @return This element's last child, or nullptr if it contains no children. + Element* GetLastChild() const; + /// Get the child element at the given index. + /// @param[in] index Index of child to get. + /// @return The child element at the given index. + Element* GetChild(int index) const; + /// Get the current number of children in this element + /// @param[in] include_non_dom_elements True if the caller wants to include the non DOM children. Only set this to true if you know what you're doing! + /// @return The number of children. + int GetNumChildren(bool include_non_dom_elements = false) const; + + /// Gets the markup and content of the element. + /// @param[out] content The content of the element. + virtual void GetInnerRML(String& content) const; + /// Gets the markup and content of the element. + /// @return The content of the element. + String GetInnerRML() const; + /// Sets the markup and content of the element. All existing children will be replaced. + /// @param[in] rml The new content of the element. + void SetInnerRML(const String& rml); + + //@} + + /** @name DOM Methods + */ + //@{ + + /// Gives focus to the current element. + /// @return True if the change focus request was successful + bool Focus(); + /// Removes focus from from this element. + void Blur(); + /// Fakes a mouse click on this element. + void Click(); + + /// Adds an event listener to this element. + /// @param[in] event Event to attach to. + /// @param[in] listener The listener object to be attached. + /// @param[in] in_capture_phase True to attach in the capture phase, false in bubble phase. + void AddEventListener(const String& event, EventListener* listener, bool in_capture_phase = false); + /// Adds an event listener to this element by id. + void AddEventListener(EventId id, EventListener* listener, bool in_capture_phase = false); + /// Removes an event listener from this element. + /// @param[in] event Event to detach from. + /// @param[in] listener The listener object to be detached. + /// @param[in] in_capture_phase True to detach from the capture phase, false from the bubble phase. + void RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase = false); + /// Removes an event listener from this element by id. + void RemoveEventListener(EventId id, EventListener* listener, bool in_capture_phase = false); + /// Sends an event to this element. + /// @param[in] type Event type in string form. + /// @param[in] parameters The event parameters. + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + bool DispatchEvent(const String& type, const Dictionary& parameters); + /// Sends an event to this element, overriding the default behavior for the given event type. + bool DispatchEvent(const String& type, const Dictionary& parameters, bool interruptible, bool bubbles = true); + /// Sends an event to this element by event id. + bool DispatchEvent(EventId id, const Dictionary& parameters); + + /// Scrolls the parent element's contents so that this element is visible. + /// @param[in] align_with_top If true, the element will align itself to the top of the parent element's window. If false, the element will be aligned to the bottom of the parent element's window. + void ScrollIntoView(bool align_with_top = true); + + /// Append a child to this element. + /// @param[in] element The element to append as a child. + /// @param[in] dom_element True if the element is to be part of the DOM, false otherwise. Only set this to false if you know what you're doing! + Element* AppendChild(ElementPtr element, bool dom_element = true); + /// Adds a child to this element, directly after the adjacent element. The new element inherits the DOM/non-DOM + /// status from the adjacent element. + /// @param[in] element Element to insert into the this element. + /// @param[in] adjacent_element The element to insert directly before. + Element* InsertBefore(ElementPtr element, Element* adjacent_element); + /// Replaces the second node with the first node. + /// @param[in] inserted_element The element that will be inserted and replace the other element. + /// @param[in] replaced_element The existing element that will be replaced. If this doesn't exist, inserted_element will be appended. + /// @return A unique pointer to the replaced element if found, discard the result to immediately destroy. + ElementPtr ReplaceChild(ElementPtr inserted_element, Element* replaced_element); + /// Remove a child element from this element. + /// @param[in] The element to remove. + /// @returns A unique pointer to the element if found, discard the result to immediately destroy. + ElementPtr RemoveChild(Element* element); + /// Returns whether or not this element has any DOM children. + /// @return True if the element has at least one DOM child, false otherwise. + bool HasChildNodes() const; + + /// Get a child element by its ID. + /// @param[in] id Id of the the child element + /// @return The child of this element with the given ID, or nullptr if no such child exists. + Element* GetElementById(const String& id); + /// Get all descendant elements with the given tag. + /// @param[out] elements Resulting elements. + /// @param[in] tag Tag to search for. + void GetElementsByTagName(ElementList& elements, const String& tag); + /// Get all descendant elements with the given class set on them. + /// @param[out] elements Resulting elements. + /// @param[in] tag Tag to search for. + void GetElementsByClassName(ElementList& elements, const String& class_name); + /// Returns the first descendent element matching the RCSS selector query. + /// @param[in] selectors The selector or comma-separated selectors to match against. + /// @return The first matching element during a depth-first traversal. + /// @performance Prefer GetElementById/TagName/ClassName whenever possible. + Element* QuerySelector(const String& selector); + /// Returns all descendent elements matching the RCSS selector query. + /// @param[out] elements The list of matching elements. + /// @param[in] selectors The selector or comma-separated selectors to match against. + /// @performance Prefer GetElementById/TagName/ClassName whenever possible. + void QuerySelectorAll(ElementList& elements, const String& selectors); + + + //@} + + /** + @name Internal Functions + */ + //@{ + /// Access the event dispatcher for this element. + EventDispatcher* GetEventDispatcher() const; + /// Returns event types with number of listeners for debugging. + String GetEventDispatcherSummary() const; + /// Access the element background. + ElementBackground* GetElementBackground() const; + /// Access the element border. + ElementBorder* GetElementBorder() const; + /// Access the element decorators. + ElementDecoration* GetElementDecoration() const; + /// Returns the element's scrollbar functionality. + ElementScroll* GetElementScroll() const; + /// Returns the element's transform state. + const TransformState* GetTransformState() const noexcept; + /// Returns the data model of this element. + DataModel* GetDataModel() const; + //@} + + /// Returns true if this element requires clipping + int GetClippingIgnoreDepth(); + /// Returns true if this element has clipping enabled + bool IsClippingEnabled(); + + /// Gets the render interface owned by this element's context. + /// @return The element's context's render interface. + RenderInterface* GetRenderInterface(); + + /// Sets the instancer to use for releasing this element. + /// @param[in] instancer Instancer to set on this element. + void SetInstancer(ElementInstancer* instancer); + + /// Called when an emitted event propagates to this element, for event types with default actions. + /// Note: See 'EventSpecification' for the events that call this function and during which phase. + /// @param[in] event The event to process. + virtual void ProcessDefaultAction(Event& event); + + /// Return the computed values of the element's properties. These values are updated as appropriate on every Context::Update. + const ComputedValues& GetComputedValues() const; + +protected: + void Update(float dp_ratio); + void Render(); + + /// Updates definition, computed values, and runs OnPropertyChange on this element. + void UpdateProperties(); + + /// Forces the element to generate a local stacking context, regardless of the value of its z-index property. + void ForceLocalStackingContext(); + + /// Called during the update loop after children are updated. + virtual void OnUpdate(); + /// Called during render after backgrounds, borders, decorators, but before children, are rendered. + virtual void OnRender(); + /// Called during update if the element size has been changed. + virtual void OnResize(); + /// Called during a layout operation, when the element is being positioned and sized. + virtual void OnLayout(); + + /// Called when attributes on the element are changed. + /// @param[in] changed_attributes Dictionary of attributes changed on the element. Attribute value will be empty if it was unset. + virtual void OnAttributeChange(const ElementAttributes& changed_attributes); + /// Called when properties on the element are changed. + /// @param[in] changed_properties The properties changed on the element. + virtual void OnPropertyChange(const PropertyIdSet& changed_properties); + + /// Called when a child node has been added up to two levels below us in the hierarchy. + /// @param[in] child The element that has been added. This may be this element. + virtual void OnChildAdd(Element* child); + /// Called when a child node has been removed up to two levels below us in the hierarchy. + /// @param[in] child The element that has been removed. This may be this element. + virtual void OnChildRemove(Element* child); + + /// Forces a re-layout of this element, and any other elements required. + virtual void DirtyLayout(); + + /// Returns true if the element has been marked as needing a re-layout. + virtual bool IsLayoutDirty(); + + /// Returns the RML of this element and all children. + /// @param[out] content The content of this element and those under it, in XML form. + virtual void GetRML(String& content); + + void SetOwnerDocument(ElementDocument* document); + + void Release() override; + +private: + void SetParent(Element* parent); + + void SetDataModel(DataModel* new_data_model); + + void DirtyOffset(); + void UpdateOffset(); + + void BuildLocalStackingContext(); + void BuildStackingContext(ElementList* stacking_context); + void DirtyStackingContext(); + + void DirtyStructure(); + void UpdateStructure(); + + void DirtyTransformState(bool perspective_dirty, bool transform_dirty); + void UpdateTransformState(); + + /// Start an animation, replacing any existing animations of the same property name. If start_value is null, the element's current value is used. + ElementAnimationList::iterator StartAnimation(PropertyId property_id, const Property * start_value, int num_iterations, bool alternate_direction, float delay, bool initiated_by_animation_property); + + /// Add a key to an animation, extending its duration. If target_value is null, the element's current value is used. + bool AddAnimationKeyTime(PropertyId property_id, const Property * target_value, float time, Tween tween); + + /// Start a transition of the given property on this element. + /// If an animation exists for the property, the call will be ignored. If a transition exists for this property, it will be replaced. + /// @return True if the transition was added or replaced. + bool StartTransition(const Transition& transition, const Property& start_value, const Property& target_value); + + /// Removes all transitions that are no longer part of the element's 'transition' property. + void HandleTransitionProperty(); + + /// Starts new animations and removes animations no longer part of the element's 'animation' property. + void HandleAnimationProperty(); + + /// Advances the animations (including transitions) forward in time. + void AdvanceAnimations(); + + // Original tag this element came from. + String tag; + + // The optional, unique ID of this object. + String id; + + // Instancer that created us, used for destruction. + ElementInstancer* instancer; + + // Parent element. + Element* parent; + // Currently focused child object + Element* focus; + // The owning document + ElementDocument* owner_document; + + // Active data model for this element. + DataModel* data_model; + // Attributes on this element. + ElementAttributes attributes; + + // The offset of the element, and the element it is offset from. + Element* offset_parent; + Vector2f relative_offset_base; // the base offset from the parent + Vector2f relative_offset_position; // the offset of a relatively positioned element + bool offset_fixed; + + mutable Vector2f absolute_offset; + mutable bool offset_dirty; + + // The offset this element adds to its logical children due to scrolling content. + Vector2f scroll_offset; + + // The size of the element. + using BoxList = Vector< Box >; + Box main_box; + BoxList additional_boxes; + + // And of the element's internal content. + Vector2f content_offset; + Vector2f content_box; + + // Defines what box area represents the element's client area; this is usually padding, but may be content. + Box::Area client_area; + + // True if the element is visible and active. + bool visible; + + OwnedElementList children; + int num_non_dom_children; + + float z_index; + bool local_stacking_context; + bool local_stacking_context_forced; + + ElementList stacking_context; + bool stacking_context_dirty; + + bool structure_dirty; + + bool computed_values_are_default_initialized; + + // Cached rendering information + int clipping_ignore_depth; + bool clipping_enabled; + bool clipping_state_dirty; + + // Transform state + UniquePtr< TransformState > transform_state; + bool dirty_transform; + bool dirty_perspective; + + ElementAnimationList animations; + bool dirty_animation; + bool dirty_transition; + + ElementMeta* meta; + + friend class Context; + friend class ElementStyle; + friend class LayoutEngine; + friend class LayoutInlineBox; + friend class ElementScroll; +}; + +} // namespace Rml + +#include "Element.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Element.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Element.inl new file mode 100644 index 000000000..832138e21 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Element.inl @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { + +// Returns the values of one of this element's properties. +template < typename T > +T Element::GetProperty(const String& name) +{ + const Property* property = GetProperty(name); + if (!property) + { + Log::Message(Log::LT_WARNING, "Invalid property name %s.", name.c_str()); + return T{}; + } + return property->Get< T >(); +} + +// Sets an attribute on the element. +template< typename T > +void Element::SetAttribute(const String& name, const T& value) +{ + Variant variant(value); + attributes[name] = variant; + ElementAttributes changed_attributes; + changed_attributes.emplace(name, std::move(variant)); + OnAttributeChange(changed_attributes); +} + +// Gets the specified attribute, with default value. +template< typename T > +T Element::GetAttribute(const String& name, const T& default_value) const +{ + return Get(attributes, name, default_value); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ElementDocument.h b/thirdparty/RmlUi/Include/RmlUi/Core/ElementDocument.h new file mode 100644 index 000000000..c035dc9fd --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ElementDocument.h @@ -0,0 +1,184 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTDOCUMENT_H +#define RMLUI_CORE_ELEMENTDOCUMENT_H + +#include "Element.h" + +namespace Rml { + +class Context; +class Stream; +class DocumentHeader; +class ElementText; +class StyleSheet; + +/** + ModalFlag used for controlling the modal state of the document. + None: Remove modal state. + Modal: Set modal state, other documents cannot receive focus. + Keep: Modal state unchanged. + + FocusFlag used for displaying the document. + None: No focus. + Document: Focus the document. + Keep: Focus the element in the document which last had focus. + Auto: Focus the first tab element with the 'autofocus' attribute or else the document. +*/ +enum class ModalFlag { None, Modal, Keep }; +enum class FocusFlag { None, Document, Keep, Auto }; + + +/** + Represents a document in the dom tree. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API ElementDocument : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementDocument, Element) + + ElementDocument(const String& tag); + virtual ~ElementDocument(); + + /// Process given document header + void ProcessHeader(const DocumentHeader* header); + + /// Returns the document's context. + Context* GetContext(); + + /// Sets the document's title. + void SetTitle(const String& title); + /// Returns the title of this document. + const String& GetTitle() const; + + /// Returns the source address of this document. + const String& GetSourceURL() const; + + /// Sets the style sheet this document, and all of its children, uses. + void SetStyleSheet(SharedPtr style_sheet); + /// Returns the document's style sheet. + const SharedPtr& GetStyleSheet() const override; + + /// Brings the document to the front of the document stack. + void PullToFront(); + /// Sends the document to the back of the document stack. + void PushToBack(); + + /// Show the document. + /// @param[in] modal_flag Flags controlling the modal state of the document, see the 'ModalFlag' description for details. + /// @param[in] focus_flag Flags controlling the focus, see the 'FocusFlag' description for details. + void Show(ModalFlag modal_flag = ModalFlag::None, FocusFlag focus_flag = FocusFlag::Auto); + /// Hide the document. + void Hide(); + /// Close the document. + void Close(); + + /// Creates the named element. + /// @param[in] name The tag name of the element. + ElementPtr CreateElement(const String& name); + /// Create a text element with the given text content. + /// @param[in] text The text content of the text element. + ElementPtr CreateTextNode(const String& text); + + /// Does the document have modal display set. + /// @return True if the document is hogging focus. + bool IsModal() const; + + /// Load a script into the document. Note that the base implementation does nothing, scripting language addons hook + /// this method. + /// @param[in] stream Stream of code to process. + /// @param[in] source_name Name of the the script the source comes from, useful for debug information. + virtual void LoadScript(Stream* stream, const String& source_name); + + /// Updates the document, including its layout. Users must call this manually before requesting information such as + /// size or position of an element if any element in the document was recently changed, unless Context::Update has + /// already been called after the change. This has a perfomance penalty, only call when necessary. + void UpdateDocument(); + +protected: + /// Repositions the document if necessary. + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + + /// Processes the 'onpropertychange' event, checking for a change in position or size. + void ProcessDefaultAction(Event& event) override; + + /// Called during update if the element size has been changed. + void OnResize() override; + +private: + /// Find the next element to focus, starting at the current element + Element* FindNextTabElement(Element* current_element, bool forward); + /// Searches forwards or backwards for a focusable element in the given substree + Element* SearchFocusSubtree(Element* element, bool forward); + + /// Sets the dirty flag on the layout so the document will format its children before the next render. + void DirtyLayout() override; + /// Returns true if the document has been marked as needing a re-layout. + bool IsLayoutDirty() override; + + /// Updates all sizes defined by the 'lp' unit. + void DirtyDpProperties(); + + /// Updates the layout if necessary. + void UpdateLayout(); + + /// Updates the position of the document based on the style properties. + void UpdatePosition(); + /// Sets the dirty flag for document positioning + void DirtyPosition(); + + // Title of the document + String title; + + // The original path this document came from + String source_url; + + // The document's style sheet. + SharedPtr style_sheet; + + Context* context; + + // Is the current display modal + bool modal; + + // Is the layout dirty? + bool layout_dirty; + + bool position_dirty; + + friend class Context; + friend class Factory; + +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ElementInstancer.h b/thirdparty/RmlUi/Include/RmlUi/Core/ElementInstancer.h new file mode 100644 index 000000000..6fce5fbc7 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ElementInstancer.h @@ -0,0 +1,130 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTINSTANCER_H +#define RMLUI_CORE_ELEMENTINSTANCER_H + +#include "Traits.h" +#include "Types.h" +#include "Header.h" +#include "Element.h" +#include "Profiling.h" + +namespace Rml { + +class Element; + +/** + An element instancer provides a method for allocating + and deallocating elements. + + It is important at the same instancer that allocated + the element releases it. This ensures there are no + issues with memory from different DLLs getting mixed up. + + The returned element is a unique pointer. When this is + destroyed, it will call ReleaseElement on the instancer + in which it was instanced. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API ElementInstancer : public NonCopyMoveable +{ +public: + virtual ~ElementInstancer(); + + /// Instances an element given the tag name and attributes. + /// @param[in] parent The element the new element is destined to be parented to. + /// @param[in] tag The tag of the element to instance. + /// @param[in] attributes Dictionary of attributes. + /// @return A unique pointer to the instanced element. + virtual ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) = 0; + /// Releases an element instanced by this instancer. + /// @param[in] element The element to release. + virtual void ReleaseElement(Element* element) = 0; +}; + + + +/** + The element instancer constructs a plain Element, and is used for most elements. + This is a slightly faster version of the generic instancer, making use of a memory + pool for allocations. + */ + +class RMLUICORE_API ElementInstancerElement : public ElementInstancer +{ +public: + ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override; + void ReleaseElement(Element* element) override; + ~ElementInstancerElement(); +}; + +/** + The element text default instancer constructs ElementTextDefault. + This is a slightly faster version of the generic instancer, making use of a memory + pool for allocations. + */ + +class RMLUICORE_API ElementInstancerTextDefault : public ElementInstancer +{ +public: + ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override; + void ReleaseElement(Element* element) override; +}; + + +/** + Generic Instancer that creates the provided element type using new and delete. This instancer + is typically used specialized element types. + */ + +template +class ElementInstancerGeneric : public ElementInstancer +{ +public: + virtual ~ElementInstancerGeneric() {} + + ElementPtr InstanceElement(Element* RMLUI_UNUSED_PARAMETER(parent), const String& tag, const XMLAttributes& RMLUI_UNUSED_PARAMETER(attributes)) override + { + RMLUI_UNUSED(parent); + RMLUI_UNUSED(attributes); + RMLUI_ZoneScopedN("ElementGenericInstance"); + return ElementPtr(new T(tag)); + } + + void ReleaseElement(Element* element) override + { + RMLUI_ZoneScopedN("ElementGenericRelease"); + delete element; + } +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ElementScroll.h b/thirdparty/RmlUi/Include/RmlUi/Core/ElementScroll.h new file mode 100644 index 000000000..f9ace26e2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ElementScroll.h @@ -0,0 +1,111 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTSCROLL_H +#define RMLUI_CORE_ELEMENTSCROLL_H + +#include "Header.h" + +namespace Rml { + +class Element; +class WidgetScroll; + +/** + Manages an element's scrollbars and scrolling state. + + @author Peter Curry + */ + +class RMLUICORE_API ElementScroll +{ +public: + enum Orientation + { + VERTICAL = 0, + HORIZONTAL = 1 + }; + + ElementScroll(Element* element); + ~ElementScroll(); + + /// Updates the increment / decrement arrows. + void Update(); + + /// Enables and sizes one of the scrollbars. + /// @param[in] orientation Which scrollbar (vertical or horizontal) to enable. + /// @param[in] element_width The current computed width of the element, used only to resolve percentage properties. + void EnableScrollbar(Orientation orientation, float element_width); + /// Disables and hides one of the scrollbars. + /// @param[in] orientation Which scrollbar (vertical or horizontal) to disable. + void DisableScrollbar(Orientation orientation); + + /// Updates the position of the scrollbar. + /// @param[in] orientation Which scrollbar (vertical or horizontal) to update). + void UpdateScrollbar(Orientation orientation); + + /// Returns one of the scrollbar elements. + /// @param[in] orientation Which scrollbar to return. + /// @return The requested scrollbar, or nullptr if it does not exist. + Element* GetScrollbar(Orientation orientation); + /// Returns the size, in pixels, of one of the scrollbars; for a vertical scrollbar, this is width, for a horizontal scrollbar, this is height. + /// @param[in] orientation Which scrollbar (vertical or horizontal) to query. + /// @return The size of the scrollbar, or 0 if the scrollbar is disabled. + float GetScrollbarSize(Orientation orientation); + + /// Formats the enabled scrollbars based on the current size of the host element. + void FormatScrollbars(); + + /// Clears the scrollbars, resetting it to initial conditions. + void ClearScrollbars(); + +private: + struct Scrollbar + { + Scrollbar(); + ~Scrollbar(); + + Element* element; + WidgetScroll* widget; + bool enabled; + float size; + }; + + // Creates one of the scroll component's scrollbar. + bool CreateScrollbar(Orientation orientation); + // Creates the scrollbar corner. + bool CreateCorner(); + + Element* element; + + Scrollbar scrollbars[2]; + Element* corner; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ElementText.h b/thirdparty/RmlUi/Include/RmlUi/Core/ElementText.h new file mode 100644 index 000000000..5743e403b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ElementText.h @@ -0,0 +1,89 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTTEXT_H +#define RMLUI_CORE_ELEMENTTEXT_H + +#include "Header.h" +#include "Types.h" +#include "Element.h" + +namespace Rml { + +/** + RmlUi's text-element interface. + + @author Peter Curry + */ + +class RMLUICORE_API ElementText : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementText, Element) + + ElementText(const String& tag); + virtual ~ElementText(); + + /// Sets the raw string this text element contains. The actual rendered text may be different due to whitespace + /// formatting. + /// @param[in] text The new string to set on this element. + virtual void SetText(const String& text) = 0; + /// Returns the raw string this text element contains. + /// @return This element's raw text. + virtual const String& GetText() const = 0; + + /// Generates a token of text from this element, returning only the width. + /// @param[out] token_width The window (in pixels) of the token. + /// @param[in] token_begin The first character to be included in the token. + /// @return True if the token is the end of the element's text, false if not. + virtual bool GenerateToken(float& token_width, int token_begin) = 0; + /// Generates a line of text rendered from this element. + /// @param[out] line The characters making up the line, with white-space characters collapsed and endlines processed appropriately. + /// @param[out] line_length The number of characters from the source string consumed making up this string; this may very well be different from line.size()! + /// @param[out] line_width The width (in pixels) of the generated line. + /// @param[in] line_begin The index of the first character to be rendered in the line. + /// @param[in] maximum_line_width The width (in pixels) of space allowed for the line, or -1 for unlimited space. + /// @param[in] right_spacing_width The width (in pixels) of the spacing (consisting of margins, padding, etc) that must be remaining on the right of the line if the last of the text is rendered onto this line. + /// @param[in] trim_whitespace_prefix If we're collapsing whitespace, whether or not to remove all prefixing whitespace or collapse it down to a single space. + /// @param[in] decode_escape_characters Decode escaped characters such as & into &. + /// @return True if the line reached the end of the element's text, false if not. + virtual bool GenerateLine(String& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix, bool decode_escape_characters) = 0; + + /// Clears all lines of generated text and prepares the element for generating new lines. + virtual void ClearLines() = 0; + /// Adds a new line into the text element. + /// @param[in] line_position The position of this line, as an offset from the first line. + /// @param[in] line The contents of the line. + virtual void AddLine(const Vector2f& line_position, const String& line) = 0; + + /// Prevents the element from dirtying its document's layout when its text is changed. + virtual void SuppressAutoLayout() = 0; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ElementUtilities.h b/thirdparty/RmlUi/Include/RmlUi/Core/ElementUtilities.h new file mode 100644 index 000000000..9986f5b11 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ElementUtilities.h @@ -0,0 +1,147 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTUTILITIES_H +#define RMLUI_CORE_ELEMENTUTILITIES_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +class Box; +class Context; +class RenderInterface; +namespace Style { struct ComputedValues; } + +/** + Utility functions for dealing with elements. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API ElementUtilities +{ +public: + enum PositionAnchor + { + TOP = 1 << 0, + BOTTOM = 1 << 1, + LEFT = 1 << 2, + RIGHT = 1 << 3, + + TOP_LEFT = TOP | LEFT, + TOP_RIGHT = TOP | RIGHT, + BOTTOM_LEFT = BOTTOM | LEFT, + BOTTOM_RIGHT = BOTTOM | RIGHT + }; + + /// Get the element with the given id. + /// @param[in] root_element First element to check. + /// @param[in] id ID of the element to look for. + static Element* GetElementById(Element* root_element, const String& id); + /// Get all elements with the given tag. + /// @param[out] elements Resulting elements. + /// @param[in] root_element First element to check. + /// @param[in] tag Tag to search for. + static void GetElementsByTagName(ElementList& elements, Element* root_element, const String& tag); + /// Get all elements with the given class set on them. + /// @param[out] elements Resulting elements. + /// @param[in] root_element First element to check. + /// @param[in] tag Class name to search for. + static void GetElementsByClassName(ElementList& elements, Element* root_element, const String& class_name); + + /// Returns an element's density-independent pixel ratio, defined by it's context + /// @param[in] element The element to determine the density-independent pixel ratio for. + /// @return The density-independent pixel ratio of the context, or 1.0 if no context assigned. + static float GetDensityIndependentPixelRatio(Element* element); + /// Returns the width of a string rendered within the context of the given element. + /// @param[in] element The element to measure the string from. + /// @param[in] string The string to measure. + /// @return The string width, in pixels. + static int GetStringWidth(Element* element, const String& string); + + /// Bind and instance all event attributes on the given element onto the element + /// @param element Element to bind events on + static void BindEventAttributes(Element* element); + + /// Generates the clipping region for an element. + /// @param[out] clip_origin The origin, in context coordinates, of the origin of the element's clipping window. + /// @param[out] clip_dimensions The size, in context coordinates, of the element's clipping window. + /// @param[in] element The element to generate the clipping region for. + /// @return True if a clipping region exists for the element and clip_origin and clip_window were set, false if not. + static bool GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_dimensions, Element* element); + /// Sets the clipping region from an element and its ancestors. + /// @param[in] element The element to generate the clipping region from. + /// @param[in] context The context of the element; if this is not supplied, it will be derived from the element. + /// @return The visibility of the given element within its clipping region. + static bool SetClippingRegion(Element* element, Context* context = nullptr); + /// Applies the clip region from the render interface to the renderer + /// @param[in] context The context to read the clip region from + /// @param[in] render_interface The render interface to update. + static void ApplyActiveClipRegion(Context* context, RenderInterface* render_interface); + + /// Formats the contents of an element. This does not need to be called for ordinary elements, but can be useful + /// for non-DOM elements of custom elements. + /// @param[in] element The element to lay out. + /// @param[in] containing_block The size of the element's containing block. + static bool FormatElement(Element* element, const Vector2f& containing_block); + + /// Generates the box for an element. + /// @param[out] box The box to be built. + /// @param[in] containing_block The dimensions of the content area of the block containing the element. + /// @param[in] element The element to build the box for. + /// @param[in] inline_element True if the element is placed in an inline context, false if not. + static void BuildBox(Box& box, const Vector2f& containing_block, Element* element, bool inline_element = false); + + /// Sizes an element, and positions it within its parent offset from the borders of its content area. Any relative + /// values will be evaluated against the size of the element parent's content area. + /// @param element[in] The element to size and position. + /// @param offset[in] The offset from the parent's borders. + /// @param anchor[in] Defines which corner or edge the border is to be positioned relative to. + static bool PositionElement(Element* element, const Vector2f& offset, PositionAnchor anchor); + + /// Applies an element's accumulated transform matrix, determined from its and ancestor's `perspective' and `transform' properties. + /// Note: All calls to RenderInterface::SetTransform must go through here. + /// @param[in] element The element whose transform to apply. + /// @return true if a render interface is available to set the transform. + static bool ApplyTransform(Element& element); + + /// Creates data views and data controllers if a data model applies to the element. + /// Attributes such as 'data-' are used to create the views and controllers. + /// @return True if a data view or controller was constructed. + static bool ApplyDataViewsControllers(Element* element); + + /// Creates data views that use a raw inner xml content string to construct child elements. + /// Right now, this only applies to the 'data-for' view. + /// @return True if a data view was constructed. + static bool ApplyStructuralDataViews(Element* element, const String& inner_rml); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataFormatter.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataFormatter.h new file mode 100644 index 000000000..495104c92 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataFormatter.h @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_DATAFORMATTER_H +#define RMLUI_CORE_ELEMENTS_DATAFORMATTER_H + +#include "../Types.h" +#include "../ScriptInterface.h" +#include "../Header.h" + +namespace Rml { + +/** + Abstract base class for a data formatter. A data formatter takes raw data + and processes it into a final string. They are usually used in conjunction + with a data source and a datagrid. + + @author Robert Curry + */ + +class RMLUICORE_API DataFormatter +{ +public: + DataFormatter(const String& name = ""); + virtual ~DataFormatter(); + + /// Returns the name by which this data formatter is referenced by. + /// @return The name of this data formatter. + const String& GetDataFormatterName(); + /// Returns a data formatter with the given name. + /// @parameter [in] data_formatter_name The name of the data formatter to + /// be returned. + /// @return If the data formatter with the specified name has been + /// constructed, a pointer to it will be returned. Otherwise, nullptr. + static DataFormatter* GetDataFormatter(const String& data_formatter_name); + + /// Formats the raw results of a data source request into RML. + /// @param[out] formatted_data The formatted RML. + /// @param[in] raw_data A list of the raw data fields. + virtual void FormatData(String& formatted_data, const StringList& raw_data) = 0; + + virtual void* GetScriptObject() const; + +private: + String name; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataQuery.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataQuery.h new file mode 100644 index 000000000..5e272b0ee --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataQuery.h @@ -0,0 +1,134 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_DATAQUERY_H +#define RMLUI_CORE_ELEMENTS_DATAQUERY_H + +#include "../Header.h" +#include "../TypeConverter.h" +#include "../Log.h" + +namespace Rml { + +class DataSource; + +/** + DataQuery + @author Robert Curry + + Represents a request for information from an DataSource, encapsulates the result and offers + mechanisms to iterate through the returned rows. +*/ + +class RMLUICORE_API DataQuery +{ +public: + DataQuery(); + DataQuery(DataSource* data_source, const String& table, const String& fields, int offset = 0, int limit = -1, const String& order = ""); + virtual ~DataQuery(); + + void ExecuteQuery(DataSource* data_source, const String& table, const String& fields, int offset = 0, int limit = -1, const String& order = ""); + bool NextRow(); + + bool IsFieldSet(const String& field) const; + + template< typename T > + T Get(const String& field_name, const T& default_value) const + { + FieldIndices::const_iterator itr = field_indices.find(field_name); + if (itr == field_indices.end()) + { + Log::Message(Log::LT_ERROR, "Field %s not found in query", field_name.c_str()); + return default_value; + } + + T return_value = default_value; + + GetInto((*itr).second, return_value); + + return return_value; + } + + template< typename T > + bool GetInto(const String& field_name, T& value) const + { + FieldIndices::const_iterator itr = field_indices.find(field_name); + if (itr == field_indices.end()) + { + Log::Message(Log::LT_ERROR, "Field %s not found in query", field_name.c_str()); + return false; + } + + return GetInto((*itr).second, value); + } + + template< typename T > + T Get(const size_t field_index, const T& default_value) const + { + T return_value = default_value; + + GetInto(field_index, return_value); + + return return_value; + } + + template< typename T > + bool GetInto(const size_t field_index, T& value) const + { + if (field_index < rows[current_row].size()) + { + return TypeConverter< String, T >::Convert(rows[current_row][field_index], value); + } + + return false; + } + + size_t GetNumFields() + { + return rows[current_row].size(); + } + +private: + StringList fields; + + DataSource* data_source; + String table; + int current_row; + int offset; + int limit; + + typedef Vector< StringList > Rows; + Rows rows; + typedef UnorderedMap< String, size_t > FieldIndices; + FieldIndices field_indices; + + void LoadRow(); +}; + +} // namespace Rml +#endif // RMLUI_CORE_ELEMENTS_DATAQUERY_H diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataSource.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataSource.h new file mode 100644 index 000000000..2115b60e2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataSource.h @@ -0,0 +1,109 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_DATASOURCE_H +#define RMLUI_CORE_ELEMENTS_DATASOURCE_H + +#include "../Header.h" +#include "../Types.h" + +namespace Rml { + +class DataSourceListener; + +/** + Generic object that provides a database-like interface for requesting rows from a table. + @author Robert Curry + */ + +class RMLUICORE_API DataSource +{ + public: + DataSource(const String& name = ""); + virtual ~DataSource(); + + const String& GetDataSourceName(); + static DataSource* GetDataSource(const String& data_source_name); + + /// Fetches the contents of one row of a table within the data source. + /// @param[out] row The list of values in the table. + /// @param[in] table The name of the table to query. + /// @param[in] row_index The index of the desired row. + /// @param[in] columns The list of desired columns within the row. + virtual void GetRow(StringList& row, const String& table, int row_index, const StringList& columns) = 0; + /// Fetches the number of rows within one of this data source's tables. + /// @param[in] table The name of the table to query. + /// @return The number of rows within the specified table. + virtual int GetNumRows(const String& table) = 0; + + void AttachListener(DataSourceListener* listener); + void DetachListener(DataSourceListener* listener); + + virtual void* GetScriptObject() const; + + static const String CHILD_SOURCE; + static const String DEPTH; + static const String NUM_CHILDREN; + + protected: + /// Tells all attached listeners that one or more rows have been added to the data source. + /// @param[in] table The name of the table to have rows added to it. + /// @param[in] first_row_added The index of the first row added. + /// @param[in] num_rows_added The number of rows added (including the first row). + void NotifyRowAdd(const String& table, int first_row_added, int num_rows_added); + + /// Tells all attached listeners that one or more rows have been removed from the data source. + /// @param[in] table The name of the table to have rows removed from it. + /// @param[in] first_row_removed The index of the first row removed. + /// @param[in] num_rows_removed The number of rows removed (including the first row). + void NotifyRowRemove(const String& table, int first_row_removed, int num_rows_removed); + + /// Tells all attached listeners that one or more rows have been changed in the data source. + /// @param[in] table The name of the table to have rows changed in it. + /// @param[in] first_row_changed The index of the first row changed. + /// @param[in] num_rows_changed The number of rows changed (including the first row). + void NotifyRowChange(const String& table, int first_row_changed, int num_rows_changed); + + /// Tells all attached listeners that the row structure has completely changed in the data source. + /// @param[in] table The name of the table to have rows changed in it. + void NotifyRowChange(const String& table); + + /// Helper function for building a result set. + typedef UnorderedMap< String, String > RowMap; + void BuildRowEntries(StringList& row, const RowMap& row_map, const StringList& columns); + + private: + String name; + + using ListenerList = List< DataSourceListener* >; + ListenerList listeners; +}; + +} // namespace Rml +#endif // RMLUI_CORE_ELEMENTS_DATASOURCE_H + diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataSourceListener.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataSourceListener.h new file mode 100644 index 000000000..c0394d03b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/DataSourceListener.h @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_DATASOURCELISTENER_H +#define RMLUI_CORE_ELEMENTS_DATASOURCELISTENER_H + +#include "../Header.h" +#include "../Types.h" + +namespace Rml { + +class DataSource; + +/** + Interface for objects wishing to listen to data source events. Listeners should use the + AttachListener() on DataSource to begin observing a data source. + + @author Robert Curry + */ + +class RMLUICORE_API DataSourceListener +{ +public: + DataSourceListener(); + virtual ~DataSourceListener(); + + /// Notification of the destruction of an observed data source. + /// @param[in] data_source Data source being destroyed. + virtual void OnDataSourceDestroy(DataSource* data_source); + /// Notification of the addition of one or more rows to an observed data source's table. + /// @param[in] data_source Data source being changed. + /// @param[in] table The name of the changing table within the data source. + /// @param[in] first_row_added Index of the first new row. + /// @param[in] num_rows_added Number of new sequential rows being added. + virtual void OnRowAdd(DataSource* data_source, const String& table, int first_row_added, int num_rows_added); + /// Notification of the removal of one or more rows from an observed data source's table. + /// @param[in] data_source Data source being changed. + /// @param[in] table The name of the changing table within the data source. + /// @param[in] first_row_removed Index of the first removed row. + /// @param[in] num_rows_removed Number of new sequential rows being removed. + virtual void OnRowRemove(DataSource* data_source, const String& table, int first_row_removed, int num_rows_removed); + /// Notification of the changing of one or more rows from an observed data source's table. + /// @param[in] data_source Data source being changed. + /// @param[in] table The name of the changing table within the data source. + /// @param[in] first_row_removed Index of the first changed row. + /// @param[in] num_rows_removed Number of new sequential rows being changed. + virtual void OnRowChange(DataSource* data_source, const String& table, int first_row_changed, int num_rows_changed); + /// Notification of the change of all of the data of an observed data source's table. + /// @param[in] data_source Data source being changed. + /// @param[in] table The name of the changing table within the data source. + virtual void OnRowChange(DataSource* data_source, const String& table); + +protected: + /// Sets up data source and table from a given String. + /// @param[out] data_source A pointer to a data_source that gets loaded with the specified data source. + /// @param[out] table_name A reference to an String that gets loaded with the specified data table. + /// @param[in] data_source_name The data source and table in SOURCE.TABLE format. + /// @return True if the data source name was in the correct format, and the data source was found. + bool ParseDataSource(DataSource*& data_source, String& table_name, const String& data_source_name); +}; + +} // namespace Rml +#endif // RMLUI_CORE_ELEMENTS_DATASOURCELISTENER_H diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGrid.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGrid.h new file mode 100644 index 000000000..a1f95914c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGrid.h @@ -0,0 +1,153 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTDATAGRID_H +#define RMLUI_CORE_ELEMENTS_ELEMENTDATAGRID_H + +#include "../Header.h" +#include "../Element.h" +#include "DataSourceListener.h" + +namespace Rml { + +class DataFormatter; +class ElementDataGridRow; + +/** + A table driven from a data source. + + @author Robert Curry + */ + +class RMLUICORE_API ElementDataGrid : public Element, public DataSourceListener +{ +public: + RMLUI_RTTI_DefineWithParent(ElementDataGrid, Element) + + ElementDataGrid(const String& tag); + virtual ~ElementDataGrid(); + + /// Sets a new data source for the contents of the data grid. + /// @param[in] data_source_name The name of the new data source. + void SetDataSource(const String& data_source_name); + + /** + A column inside a table. + + @author Robert Curry + */ + struct Column + { + /// The list of fields that this column reads from the data source for + /// each row. + StringList fields; + + /// The data formatter this is used to process the field information + /// into what is finally displayed in the data grid. + DataFormatter* formatter; + /// The header that is displayed at the top of the column, in the + /// header row. + Element* header; + + /// The width of this column. + float current_width; + + /// Whether this column has a forced refresh when a child node changes. + /// This is to allow the expand/collapse buttons to be added or removed + /// when a child node is added. + bool refresh_on_child_change; + }; + + /// Adds a column to the table. + /// @param[in] fields A comma-separated list of fields that this column reads from the data source. + /// @param[in] formatter The name of the data formatter to be used to format the raw column data into RML. + /// @param[in] initial_width The initial width, in pixels, of the column. + /// @param[in] header_rml The RML to use as the column header. + /// @return True if the column was added successfully, false if not. + bool AddColumn(const String& fields, const String& formatter, float initial_width, const String& header_rml); + /// Adds a column to the table. + /// @param[in] fields A comma-separated list of fields that this column reads from the data source. + /// @param[in] formatter The name of the data formatter to be used to format the raw column data into RML. + /// @param[in] initial_width The initial width, in pixels, of the column. + /// @param[in] header_element The element hierarchy to use as the column header. + void AddColumn(const String& fields, const String& formatter, float initial_width, ElementPtr header_element); + /// Returns the number of columns in this table + int GetNumColumns(); + /// Returns the column at the specified index. + const Column* GetColumn(int column_index); + /// Returns a CSV string containing all the fields that each column requires, in order. + const String& GetAllColumnFields(); + + /// Adds a new row to the table. This is only called from child rows. + /// @param[in] parent The parent row that the row is being added under. + /// @param[in] index The index of the child, relative to its parent. + /// @return A pointer to the newly created row. + ElementDataGridRow* AddRow(ElementDataGridRow* parent, int index); + /// Removes a series of rows from the table. + /// @param[in] index The index of the first row, relative to the table. + /// @param[in] num_rows The number of rows to remove. Defaults to one. + void RemoveRows(int index, int num_rows = 1); + + /// Returns the number of rows in the table + int GetNumRows() const; + /// Returns the row at the given index in the table. + /// @param[in] index The index of the row, relative to the table. + ElementDataGridRow* GetRow(int index) const; + +protected: + void OnUpdate() override; + + void OnResize() override; + + /// Gets the markup and content of the element. + /// @param content[out] The content of the element. + void GetInnerRML(String& content) const override; + +private: + typedef Vector< Column > ColumnList; + typedef Vector< ElementDataGridRow* > RowList; + + ColumnList columns; + String column_fields; + + // The row that contains the header elements of the table. + ElementDataGridRow* header; + + // The root row, all the top level rows are children under this. Not + // actually rendered, has "display: none". + ElementDataGridRow* root; + // If this is non-empty, then in the previous update the data source was set + // and we must set it this update. + String new_data_source; + + // The block element that contains all our rows. Only used for applying styles. + Element* body; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridCell.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridCell.h new file mode 100644 index 000000000..cb2ae499e --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridCell.h @@ -0,0 +1,61 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTDATAGRIDCELL_H +#define RMLUI_CORE_ELEMENTS_ELEMENTDATAGRIDCELL_H + +#include "../Element.h" +#include "../EventListener.h" +#include "../Header.h" + +namespace Rml { + +/** + The class for cells inside a data table row. + + @author Robert Curry + */ + +class RMLUICORE_API ElementDataGridCell : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementDataGridCell, Element) + + ElementDataGridCell(const String& tag); + virtual ~ElementDataGridCell(); + + void Initialise(int column, Element* header); + int GetColumn(); + +private: + int column; + Element* header; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridExpandButton.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridExpandButton.h new file mode 100644 index 000000000..6fa98d1f7 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridExpandButton.h @@ -0,0 +1,52 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTDATAGRIDEXPANDBUTTON_H +#define RMLUI_CORE_ELEMENTS_ELEMENTDATAGRIDEXPANDBUTTON_H + +#include "../Element.h" +#include "../Header.h" + +namespace Rml { + +/** + @author Robert Curry + */ + +class RMLUICORE_API ElementDataGridExpandButton : public Element +{ +public: + ElementDataGridExpandButton(const String& tag); + virtual ~ElementDataGridExpandButton(); + +protected: + void ProcessDefaultAction(Event& event) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridRow.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridRow.h new file mode 100644 index 000000000..2496eed48 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementDataGridRow.h @@ -0,0 +1,169 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTDATAGRIDROW_H +#define RMLUI_CORE_ELEMENTS_ELEMENTDATAGRIDROW_H + +#include "../Header.h" +#include "../Element.h" +#include "DataSourceListener.h" +#include "DataQuery.h" + +namespace Rml { + +class ElementDataGrid; + +/** + Class for rows inside a data table. Used for both the header and the individual rows. + + @author Robert Curry + */ + +class RMLUICORE_API ElementDataGridRow : public Element, public DataSourceListener +{ +friend class ElementDataGrid; + +public: + RMLUI_RTTI_DefineWithParent(ElementDataGridRow, Element) + + ElementDataGridRow(const String& tag); + virtual ~ElementDataGridRow(); + + void Initialise(ElementDataGrid* parent_grid, ElementDataGridRow* parent_row = nullptr, int child_index = -1, ElementDataGridRow* header_row = nullptr, int depth = -1); + void SetChildIndex(int child_index); + int GetDepth(); + + void SetDataSource(const String& data_source_name); + + /// Checks dirty children and cells, and loads them if necessary. + /// @return True if any children were updated. + bool UpdateChildren(); + + /// Returns the number of children that aren't dirty (have been loaded) + int GetNumLoadedChildren(); + + /// Removes all the child cells and fetches them again from the data source. + void RefreshRows(); + + /// Returns whether this row is expanded or not. + bool IsRowExpanded(); + /// Shows all of this row's descendants. + void ExpandRow(); + /// Hides all of this row's descendants. + void CollapseRow(); + /// Expands the row if collapsed, or collapses the row if expanded. + void ToggleRow(); + + /// Returns the index of this row, relative to its parent. + int GetParentRelativeIndex(); + /// Returns the index of this row, relative to the table rather than its parent. + int GetTableRelativeIndex(); + /// Returns the parent row of this row. + ElementDataGridRow* GetParentRow(); + /// Returns the grid that this row belongs to. + ElementDataGrid* GetParentGrid(); + +protected: + void OnDataSourceDestroy(DataSource* data_source) override; + void OnRowAdd(DataSource* data_source, const String& table, int first_row_added, int num_rows_added) override; + void OnRowRemove(DataSource* data_source, const String& table, int first_row_removed, int num_rows_removed) override; + void OnRowChange(DataSource* data_source, const String& table, int first_row_changed, int num_rows_changed) override; + void OnRowChange(DataSource* data_source, const String& table) override; + +private: + typedef Queue< ElementDataGridRow* > RowQueue; + typedef Vector< ElementDataGridRow* > RowList; + + // Called when a row change (addition or removal) occurs in one of our + // children. Causes the table row index to be dirtied on all following + // children. + void ChildChanged(int child_index); + // Checks if any columns are dependent on the number of children + // present, and refreshes them from the data source if they are. + void RefreshChildDependentCells(); + + // Forces the row to recalculate its relative table index the next time + // it is requested. + void DirtyTableRelativeIndex(); + // Works out what the table relative index is for a given child. + int GetChildTableRelativeIndex(int child_index); + + // Adds children underneath this row, and fetches their contents (and + // possible children) from the row's data source. If first_row is left + // as the default -1, the rows are appended at the end of the list. + void AddChildren(int first_row_added = -1, int num_rows_added = 1); + // Removes this rows children, and their children, etc, from the table. + // If the num_rows_removed parameter is left as the -1 default, it'll + // default to the rest of the children after the first row. + void RemoveChildren(int first_row_removed = 0, int num_rows_removed = -1); + // Marks children as dirty and dispatches the event. + void ChangeChildren(int first_row_changed = 0, int num_rows_changed = -1); + // Returns the number of rows under this row (children, grandchildren, etc) + int GetNumDescendants(); + + // Adds or refreshes the cell contents, and undirties the row's cells. + void Load(const DataQuery& row_information); + // Finds all children that have cell information missing (either though being + // refreshed or not being loaded yet) and reloads them. + void LoadChildren(float time_slice); + // Loads a specific set of children. Called by the above function. + void LoadChildren(int first_row_to_load, int num_rows_to_load, double time_slice); + + // Sets the dirty_cells flag on this row, and lets our ancestors know. + void DirtyCells(); + // Sets the dirty children flag on this row and the row's ancestors. + void DirtyRow(); + // This row has one or more cells that need loading. + bool dirty_cells; + // This row has one or more children that have either dirty flag set. + bool dirty_children; + + // Shows this row, and, if this was was expanded before it was hidden, its children as well. + void Show(); + // Hides this row and all descendants. + void Hide(); + bool row_expanded; + + int table_relative_index; + bool table_relative_index_dirty; + + ElementDataGrid* parent_grid; + + ElementDataGridRow* parent_row; + int child_index; + int depth; + + RowList children; + + // The data source and table that the children are fetched from. + DataSource* data_source; + String data_table; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementForm.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementForm.h new file mode 100644 index 000000000..57fa214e6 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementForm.h @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTFORM_H +#define RMLUI_CORE_ELEMENTS_ELEMENTFORM_H + +#include "../Element.h" +#include "../Header.h" + +namespace Rml { + +/** + A specialisation of the generic Element representing a form element. + + @author Peter Curry + */ + +class RMLUICORE_API ElementForm : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementForm, Element) + + /// Constructs a new ElementForm. This should not be called directly; use the Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementForm(const String& tag); + virtual ~ElementForm(); + + /// Submits the form. + /// @param[in] name The name of the item doing the submit + /// @param[in] submit_value The value to send through as the 'submit' parameter. + void Submit(const String& name = "", const String& submit_value = ""); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControl.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControl.h new file mode 100644 index 000000000..07c6ef93f --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControl.h @@ -0,0 +1,86 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROL_H +#define RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROL_H + +#include "../Element.h" +#include "../Header.h" + +namespace Rml { + +/** + A generic specialisation of the generic Element for all input controls. + + @author Peter Curry + */ + +class RMLUICORE_API ElementFormControl : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementFormControl, Element) + + /// Constructs a new ElementFormControl. This should not be called directly; use the Factory + /// instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementFormControl(const String& tag); + virtual ~ElementFormControl(); + + /// Returns the name of the form control. This is not guaranteed to be unique, and in the case of some form + /// controls (such as radio buttons) most likely will not be. + /// @return The name of the form control. + String GetName() const; + /// Sets the name of the form control. + /// @param[in] name The new name of the form control. + void SetName(const String& name); + + /// Returns a string representation of the current value of the form control. + /// @return The value of the form control. + virtual String GetValue() const = 0; + /// Sets the current value of the form control. + /// @param[in] value The new value of the form control. + virtual void SetValue(const String& value) = 0; + /// Returns if this value should be submitted with the form. + /// @return True if the value should be be submitted with the form, false otherwise. + virtual bool IsSubmitted(); + + /// Returns the disabled status of the form control. + /// @return True if the element is disabled, false otherwise. + bool IsDisabled() const; + /// Sets the disabled status of the form control. + /// @param[in] disable True to disable the element, false to enable. + void SetDisabled(bool disable); + +protected: + /// Checks for changes to the 'disabled' attribute. + /// @param[in] changed_attributes List of changed attributes on the element. + void OnAttributeChange(const ElementAttributes& changed_attributes) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlDataSelect.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlDataSelect.h new file mode 100644 index 000000000..6fbb3f92b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlDataSelect.h @@ -0,0 +1,91 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLDATASELECT_H +#define RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLDATASELECT_H + +#include "../Header.h" +#include "ElementFormControlSelect.h" +#include "DataSourceListener.h" + +namespace Rml { + + +class DataSource; + +/** + A drop-down select form control driven from a data source. + + @author Peter Curry + */ + +class RMLUICORE_API ElementFormControlDataSelect : public ElementFormControlSelect, public DataSourceListener +{ +public: + /// Constructs a new ElementFormControlDataSelect. This should not be called directly; use the + /// Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementFormControlDataSelect(const String& tag); + virtual ~ElementFormControlDataSelect(); + + /// Sets the data source the control's options are driven from. + /// @param[in] data_source The name of the new data source. + void SetDataSource(const String& data_source); + +protected: + /// If a new data source has been set on the control, this will attach to it and build the + /// initial options. + void OnUpdate() override; + + /// Checks for changes to the data source or formatting attributes. + /// @param[in] changed_attributes List of changed attributes on the element. + void OnAttributeChange(const ElementAttributes& changed_attributes) override; + + /// Detaches from the data source and rebuilds the options. + void OnDataSourceDestroy(DataSource* data_source) override; + /// Rebuilds the available options from the data source. + void OnRowAdd(DataSource* data_source, const String& table, int first_row_added, int num_rows_added) override; + /// Rebuilds the available options from the data source. + void OnRowRemove(DataSource* data_source, const String& table, int first_row_removed, int num_rows_removed) override; + /// Rebuilds the available options from the data source. + void OnRowChange(DataSource* data_source, const String& table, int first_row_changed, int num_rows_changed) override; + /// Rebuilds the available options from the data source. + void OnRowChange(DataSource* data_source, const String& table) override; + +private: + // Builds the option list from the data source. + void BuildOptions(); + + DataSource* data_source; + String data_table; + + bool initialised; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlInput.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlInput.h new file mode 100644 index 000000000..0c33a8451 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlInput.h @@ -0,0 +1,102 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLINPUT_H +#define RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLINPUT_H + +#include "../Header.h" +#include "ElementFormControl.h" + +namespace Rml { + +class InputType; + +/** + A form control for the generic input element. All functionality is handled through an input type interface. + + @author Peter Curry + */ + +class RMLUICORE_API ElementFormControlInput : public ElementFormControl +{ +public: + RMLUI_RTTI_DefineWithParent(ElementFormControlInput, ElementFormControl) + + /// Constructs a new ElementFormControlInput. This should not be called directly; use the + /// Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementFormControlInput(const String& tag); + virtual ~ElementFormControlInput(); + + /// Returns a string representation of the current value of the form control. + /// @return The value of the form control. + String GetValue() const override; + /// Sets the current value of the form control. + /// @param value[in] The new value of the form control. + void SetValue(const String& value) override; + /// Returns if this value's type should be submitted with the form. + /// @return True if the form control is to be submitted, false otherwise. + bool IsSubmitted() override; + +protected: + /// Updates the element's underlying type. + void OnUpdate() override; + /// Renders the element's underlying type. + void OnRender() override; + /// Calls the element's underlying type. + void OnResize() override; + + /// Checks for necessary functional changes in the control as a result of changed attributes. + /// @param[in] changed_attributes The list of changed attributes. + void OnAttributeChange(const ElementAttributes& changed_attributes) override; + /// Called when properties on the control are changed. + /// @param[in] changed_properties The properties changed on the element. + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + + /// If we are the added element, this will pass the call onto our type handler. + /// @param[in] child The new member of the hierarchy. + void OnChildAdd(Element* child) override; + /// If we are the removed element, this will pass the call onto our type handler. + /// @param[in] child The member of the hierarchy that was just removed. + void OnChildRemove(Element* child) override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; + +private: + InputType* type; + String type_name; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlSelect.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlSelect.h new file mode 100644 index 000000000..04d24ace1 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlSelect.h @@ -0,0 +1,109 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLSELECT_H +#define RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLSELECT_H + +#include "../Header.h" +#include "ElementFormControl.h" +#include "SelectOption.h" + +namespace Rml { + +class WidgetDropDown; + +/** + A drop-down select form control. + + @author Peter Curry + */ + +class RMLUICORE_API ElementFormControlSelect : public ElementFormControl +{ +public: + /// Constructs a new ElementFormControlSelect. This should not be called directly; use the + /// Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementFormControlSelect(const String& tag); + virtual ~ElementFormControlSelect(); + + /// Returns a string representation of the current value of the form control. + /// @return The value of the form control. + String GetValue() const override; + /// Sets the current value of the form control. + /// @param[in] value The new value of the form control. + void SetValue(const String& value) override; + + /// Sets the index of the selection. If the new index lies outside of the bounds, it will be clamped. + /// @param[in] selection The new selection index. + void SetSelection(int selection); + /// Returns the index of the currently selected item. + /// @return The index of the currently selected item. + int GetSelection() const; + + /// Returns one of the select control's option elements. + /// @param[in] The index of the desired option element. + /// @return The option element at the given index. This will be nullptr if the index is out of bounds. + SelectOption* GetOption(int index); + /// Returns the number of options in the select control. + /// @return The number of options. + int GetNumOptions(); + + /// Adds a new option to the select control. + /// @param[in] rml The RML content used to represent the option. This is usually a simple string, but can include RML tags. + /// @param[in] value The value of the option. This is used to identify the option, but does not necessarily need to be unique. + /// @param[in] before The index of the element to insert the new option before. If out of bounds of the control's option list (the default) the new option will be added at the end of the list. + /// @param[in] selectable If true this option can be selected. If false, this option is not selectable. + /// @return The index of the new option. + int Add(const String& rml, const String& value, int before = -1, bool selectable = true); + /// Removes an option from the select control. + /// @param[in] index The index of the option to remove. If this is outside of the bounds of the control's option list, no option will be removed. + void Remove(int index); + + /// Removes all options from the select control. + void RemoveAll(); + +protected: + /// Moves all children to be under control of the widget. + void OnUpdate() override; + /// Updates the layout of the widget's elements. + void OnRender() override; + + /// Forces an internal layout. + void OnLayout() override; + + /// Returns true to mark this element as replaced. + /// @param[out] intrinsic_dimensions Set to the arbitrary dimensions of 128 x 16 just to give this element a size. Resize with the 'width' and 'height' properties. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& intrinsic_dimensions) override; + + WidgetDropDown* widget; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlTextArea.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlTextArea.h new file mode 100644 index 000000000..01c19149b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementFormControlTextArea.h @@ -0,0 +1,123 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLTEXTAREA_H +#define RMLUI_CORE_ELEMENTS_ELEMENTFORMCONTROLTEXTAREA_H + +#include "../Header.h" +#include "ElementFormControl.h" + +namespace Rml { + +class WidgetTextInput; + +/** + Default RmlUi implemention of a text area. + + @author Peter Curry + */ + +class RMLUICORE_API ElementFormControlTextArea : public ElementFormControl +{ +public: + RMLUI_RTTI_DefineWithParent(ElementFormControlTextArea, ElementFormControl) + + /// Constructs a new ElementFormControlTextArea. This should not be called directly; use the + /// Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementFormControlTextArea(const String& tag); + virtual ~ElementFormControlTextArea(); + + /// Returns a string representation of the current value of the form control. This is the value of the control + /// regardless of whether it has been selected / checked (as appropriate for the control). + /// @return The value of the form control. + String GetValue() const override; + /// Sets the current value of the form control. + /// @param[in] value The new value of the form control. + void SetValue(const String& value) override; + + /// Sets the number of characters visible across the text area. Note that this will only be precise when using + /// a fixed-width font. + /// @param[in] size The number of visible characters. + void SetNumColumns(int num_columns); + /// Returns the approximate number of characters visible at once. + /// @return The number of visible characters. + int GetNumColumns() const; + + /// Sets the number of visible lines of text in the text area. + /// @param[in] num_rows The new number of visible lines of text. + void SetNumRows(int num_rows); + /// Returns the number of visible lines of text in the text area. + /// @return The number of visible lines of text. + int GetNumRows() const; + + /// Sets the maximum length (in characters) of this text area. + /// @param[in] max_length The new maximum length of the text area. A number lower than zero will mean infinite + /// characters. + void SetMaxLength(int max_length); + /// Returns the maximum length (in characters) of this text area. + /// @return The maximum number of characters allowed in this text area. + int GetMaxLength() const; + + /// Enables or disables word-wrapping in the text area. + /// @param[in] word_wrap True to enable word-wrapping, false to disable. + void SetWordWrap(bool word_wrap); + /// Returns the state of word-wrapping in the text area. + /// @return True if the text area is word-wrapping, false otherwise. + bool GetWordWrap(); + + /// Returns the control's inherent size, based on the length of the input field and the current font size. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; + +protected: + /// Updates the control's widget. + void OnUpdate() override; + /// Renders the control's widget. + void OnRender() override; + /// Resizes and positions the control's widget. + void OnResize() override; + /// Formats the element. + void OnLayout() override; + + /// Called when attributes on the element are changed. + void OnAttributeChange(const ElementAttributes& changed_attributes) override; + /// Called when properties on the control are changed. + /// @param[in] changed_properties The properties changed on the element. + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + + /// Returns the text content of the element. + /// @param[out] content The content of the element. + void GetInnerRML(String& content) const override; + +private: + WidgetTextInput* widget; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementProgressBar.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementProgressBar.h new file mode 100644 index 000000000..7444e048c --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementProgressBar.h @@ -0,0 +1,119 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTPROGRESSBAR_H +#define RMLUI_CORE_ELEMENTS_ELEMENTPROGRESSBAR_H + +#include "../Header.h" +#include "../Element.h" +#include "../Geometry.h" +#include "../Texture.h" +#include "../Spritesheet.h" + +namespace Rml { + +/** + The 'progressbar' element. + + The 'value' attribute should be a number [0, 1] where 1 means completely filled. + + The 'direction' attribute should be one of: + top | right (default) | bottom | left | clockwise | counter-clockwise + + The 'start-edge' attribute should be one of: + top (default) | right | bottom | left + Only applies to 'clockwise' or 'counter-clockwise' directions. Defines which edge the + circle should start expanding from. + + The progressbar generates a non-dom 'fill' element beneath it which can be used to style + the filled part of the bar. The 'fill' element can use the 'fill-image'-property to set + an image which will be clipped according to the progressbar value. This property is the + only way to style a 'clockwise' or 'counter-clockwise' progressbar. + + */ + +class RMLUICORE_API ElementProgressBar : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementProgressBar, Element) + + /// Constructs a new ElementProgressBar. This should not be called directly; use the Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementProgressBar(const String& tag); + virtual ~ElementProgressBar(); + + /// Return the value of the progress bar [0, 1] + float GetValue() const; + + /// Set the value of the progress bar + void SetValue(float value); + +protected: + void OnRender() override; + + void OnResize() override; + + void OnAttributeChange(const ElementAttributes& changed_attributes) override; + + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + +private: + enum class Direction { Top, Right, Bottom, Left, Clockwise, CounterClockwise, Count }; + enum class StartEdge { Top, Right, Bottom, Left, Count }; + + static constexpr Direction DefaultDirection = Direction::Right; + static constexpr StartEdge DefaultStartEdge = StartEdge::Top; + + void GenerateGeometry(); + bool LoadTexture(); + + Direction direction; + StartEdge start_edge; + + float value; + + Element* fill; + + // The size of the fill geometry as if fully filled, and the offset relative to the 'progressbar' element. + Vector2f fill_size, fill_offset; + + // The texture this element is rendering from if the 'fill-image' property is set. + Texture texture; + bool texture_dirty; + + // The rectangle extracted from a sprite, 'rect_set' controls whether it is active. + Rectangle rect; + bool rect_set; + + // The geometry used to render this element. Only applies if the 'fill-image' property is set. + Geometry geometry; + bool geometry_dirty; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementTabSet.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementTabSet.h new file mode 100644 index 000000000..0d68e20f6 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/ElementTabSet.h @@ -0,0 +1,99 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTTABSET_H +#define RMLUI_CORE_ELEMENTS_ELEMENTTABSET_H + +#include "../Element.h" +#include "../Header.h" + +namespace Rml { + +/** + A tabulated set of panels. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API ElementTabSet : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementTabSet, Element) + + ElementTabSet(const String& tag); + ~ElementTabSet(); + + /// Sets the specifed tab index's tab title RML. + /// @param[in] tab_index The tab index to set. If it doesn't already exist, it will be created. + /// @param[in] rml The RML to set on the tab title. + void SetTab(int tab_index, const String& rml); + /// Sets the specifed tab index's tab panel RML. + /// @param[in] tab_index The tab index to set. If it doesn't already exist, it will be created. + /// @param[in] rml The RML to set on the tab panel. + void SetPanel(int tab_index, const String& rml); + + /// Set the specifed tab index's title element. + /// @param[in] tab_index The tab index to set. If it doesn't already exist, it will be created. + /// @param[in] element The root of the element tree to set as the tab title. + void SetTab(int tab_index, ElementPtr element); + /// Set the specified tab index's body element. + /// @param[in] tab_index The tab index to set. If it doesn't already exist, it will be created. + /// @param[in] element The root of the element tree to set as the window. + void SetPanel(int tab_index, ElementPtr element); + + /// Remove one of the tab set's panels and its corresponding tab. + /// @param[in] tab_index The tab index to remove. If no tab matches this index, nothing will be removed. + void RemoveTab(int tab_index); + + /// Retrieve the number of tabs in the tabset. + /// @return The number of tabs. + int GetNumTabs(); + + /// Sets the currently active (visible) tab index. + /// @param[in] tab_index Index of the tab to display. + void SetActiveTab(int tab_index); + + /// Get the current active tab index. + /// @return The index of the active tab. + int GetActiveTab() const; + + /// Capture clicks on our tabs. + void ProcessDefaultAction(Event& event) override; + +protected: + // Catch child add so we can correctly set up its properties. + void OnChildAdd(Element* child) override; + +private: + Element* GetChildByTag(const String& tag); + + int active_tab; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Elements/SelectOption.h b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/SelectOption.h new file mode 100644 index 000000000..0b0d7c409 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Elements/SelectOption.h @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_SELECTOPTION_H +#define RMLUI_CORE_ELEMENTS_SELECTOPTION_H + +#include "../Header.h" +#include "../Types.h" + +namespace Rml { + +class Element; + + +/** + Represents individual options within a select control. + + @author Peter Curry + */ + +class RMLUICORE_API SelectOption +{ +public: + SelectOption(Element* element, const String& value, bool selectable); + ~SelectOption(); + + /// Returns the element that represents the option visually. + /// @return The option's element. + Element* GetElement(); + /// Returns the value of the option. + /// @return The option's value. + const String& GetValue() const; + + /// Returns true if the item is selectable. + /// @return True if the item is selectable. + bool IsSelectable() { return selectable; } + +private: + Element* element; + String value; + bool selectable; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Event.h b/thirdparty/RmlUi/Include/RmlUi/Core/Event.h new file mode 100644 index 000000000..f0d4df963 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Event.h @@ -0,0 +1,152 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENT_H +#define RMLUI_CORE_EVENT_H + +#include "Header.h" +#include "Dictionary.h" +#include "ScriptInterface.h" +#include "ID.h" + +namespace Rml { + +class Element; +class EventInstancer; +struct EventSpecification; + +enum class EventPhase { None, Capture = 1, Target = 2, Bubble = 4 }; +enum class DefaultActionPhase { None, Target = (int)EventPhase::Target, TargetAndBubble = ((int)Target | (int)EventPhase::Bubble) }; + +/** + An event that propogates through the element hierarchy. Events follow the DOM3 event specification. See + http://www.w3.org/TR/DOM-Level-3-Events/events.html. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API Event : public ScriptInterface +{ +public: + /// Constructor + Event(); + /// Constructor + /// @param[in] target The target element of this event + /// @param[in] type The event type + /// @param[in] parameters The event parameters + /// @param[in] interruptible Can this event have is propagation stopped? + Event(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible); + /// Destructor + virtual ~Event(); + + /// Get the current propagation phase. + EventPhase GetPhase() const; + /// Set the current propagation phase + void SetPhase(EventPhase phase); + + /// Set the current element in the propagation. + void SetCurrentElement(Element* element); + /// Get the current element in the propagation. + Element* GetCurrentElement() const; + /// Get the target element of this event. + Element* GetTargetElement() const; + + /// Get the event type. + const String& GetType() const; + /// Get the event id. + EventId GetId() const; + + /// Stops propagation of the event if it is interruptible, but finish all listeners on the current element. + void StopPropagation(); + /// Stops propagation of the event if it is interruptible, including to any other listeners on the current element. + void StopImmediatePropagation(); + + /// Returns true if the event can be interrupted, that is, stopped from propagating. + bool IsInterruptible() const; + /// Returns true if the event is still propagating. + bool IsPropagating() const; + /// Returns true if the event is still immediate propagating. + bool IsImmediatePropagating() const; + + /// Checks if the event is of a certain type. + /// @param type The name of the type to check for. + /// @return True if the event is of the requested type, false otherwise. + bool operator==(const String& type) const; + /// Checks if the event is of a certain id. + bool operator==(EventId id) const; + + /// Returns the value of one of the event's parameters. + /// @param key[in] The name of the desired parameter. + /// @return The value of the requested parameter. + template < typename T > + T GetParameter(const String& key, const T& default_value) const + { + return Get(parameters, key, default_value); + } + /// Access the dictionary of parameters + /// @return The dictionary of parameters + const Dictionary& GetParameters() const; + + /// Return the unprojected mouse screen position. + /// Note: Only specified for events with 'mouse_x' and 'mouse_y' parameters. + const Vector2f& GetUnprojectedMouseScreenPos() const; + +protected: + Dictionary parameters; + + Element* target_element = nullptr; + Element* current_element = nullptr; + +private: + /// Project the mouse coordinates to the current element to enable + /// interacting with transformed elements. + void ProjectMouse(Element* element); + + /// Release this event through its instancer. + void Release() override; + + String type; + EventId id = EventId::Invalid; + bool interruptible = false; + + bool interrupted = false; + bool interrupted_immediate = false; + + bool has_mouse_position = false; + Vector2f mouse_screen_position = Vector2f(0, 0); + + EventPhase phase = EventPhase::None; + + EventInstancer* instancer = nullptr; + + friend class Factory; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/EventInstancer.h b/thirdparty/RmlUi/Include/RmlUi/Core/EventInstancer.h new file mode 100644 index 000000000..0d19d8fba --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/EventInstancer.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTINSTANCER_H +#define RMLUI_CORE_EVENTINSTANCER_H + +#include "Traits.h" +#include "Header.h" +#include "Types.h" + +namespace Rml { + +class Element; +class Event; + +/** + Abstract instancer interface for instancing events. This is required to be overridden for scripting systems. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API EventInstancer : public Releasable +{ +public: + virtual ~EventInstancer(); + + /// Instance an event object. + /// @param[in] target Target element of this event. + /// @param[in] id EventId of this event. + /// @param[in] name Name of this event. + /// @param[in] parameters Additional parameters for this event. + /// @param[in] interruptible If the event propagation can be stopped. + virtual EventPtr InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible) = 0; + + /// Releases an event instanced by this instancer. + /// @param[in] event The event to release. + virtual void ReleaseEvent(Event* event) = 0; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/EventListener.h b/thirdparty/RmlUi/Include/RmlUi/Core/EventListener.h new file mode 100644 index 000000000..c2afe3191 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/EventListener.h @@ -0,0 +1,69 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTLISTENER_H +#define RMLUI_CORE_EVENTLISTENER_H + +#include "Header.h" +#include "Event.h" +#include "ObserverPtr.h" + +namespace Rml { + +class Event; +class Element; + +/** + Abstract interface class for handling events. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API EventListener : public EnableObserverPtr +{ +public: + virtual ~EventListener() {} + + /// Process the incoming Event + virtual void ProcessEvent(Event& event) = 0; + + /// Called when the listener has been attached to a new Element + virtual void OnAttach(Element* RMLUI_UNUSED_PARAMETER(element)) + { + RMLUI_UNUSED(element); + } + + /// Called when the listener has been detached from an Element + virtual void OnDetach(Element* RMLUI_UNUSED_PARAMETER(element)) + { + RMLUI_UNUSED(element); + } +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/EventListenerInstancer.h b/thirdparty/RmlUi/Include/RmlUi/Core/EventListenerInstancer.h new file mode 100644 index 000000000..355f8826f --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/EventListenerInstancer.h @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTLISTENERINSTANCER_H +#define RMLUI_CORE_EVENTLISTENERINSTANCER_H + +#include "Traits.h" +#include "Types.h" +#include "Header.h" +#include "Element.h" + +namespace Rml { + +class EventListener; + +/** + Abstract instancer interface for instancing event listeners. This is required to be overridden for scripting + systems. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API EventListenerInstancer +{ +public: + virtual ~EventListenerInstancer(); + + /// Instance an event listener object. + /// @param value Value of the event. + /// @param element Element that triggers the events. + virtual EventListener* InstanceEventListener(const String& value, Element* element) = 0; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Factory.h b/thirdparty/RmlUi/Include/RmlUi/Core/Factory.h new file mode 100644 index 000000000..24bb7d77d --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Factory.h @@ -0,0 +1,207 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FACTORY_H +#define RMLUI_CORE_FACTORY_H + +#include "XMLParser.h" +#include "Header.h" + +namespace Rml { + +class Context; +class ContextInstancer; +class DataControllerInstancer; +class DataViewInstancer; +class Decorator; +class DecoratorInstancer; +class Element; +class ElementDocument; +class ElementInstancer; +class Event; +class EventInstancer; +class EventListener; +class EventListenerInstancer; +class FontEffect; +class FontEffectInstancer; +class StyleSheet; +class PropertyDictionary; +class PropertySpecification; +class DecoratorInstancerInterface; +enum class EventId : uint16_t; + +/** + The Factory contains a registry of instancers for different types. + + All instantiation of these rmlui types should go through the factory + so that scripting API's can bind in new types. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API Factory +{ +public: + /// Initialise the element factory + static bool Initialise(); + /// Cleanup and shutdown the factory + static void Shutdown(); + + /// Registers a non-owning pointer to the instancer used to instance contexts. + /// @param[in] instancer The new context instancer. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + static void RegisterContextInstancer(ContextInstancer* instancer); + /// Instances a new context. + /// @param[in] name The name of the new context. + /// @return The new context, or nullptr if no context could be created. + static ContextPtr InstanceContext(const String& name); + + /// Registers a non-owning pointer to the element instancer that will be used to instance an element when the specified tag is encountered. + /// @param[in] name Name of the instancer; elements with this as their tag will use this instancer. + /// @param[in] instancer The instancer to call when the tag is encountered. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + static void RegisterElementInstancer(const String& name, ElementInstancer* instancer); + /// Returns the element instancer for the specified tag. + /// @param[in] tag Name of the tag to get the instancer for. + /// @return The requested element instancer, or nullptr if no such instancer is registered. + static ElementInstancer* GetElementInstancer(const String& tag); + /// Instances a single element. + /// @param[in] parent The parent of the new element, or nullptr for a root tag. + /// @param[in] instancer The name of the instancer to create the element with. + /// @param[in] tag The tag of the element to be instanced. + /// @param[in] attributes The attributes to instance the element with. + /// @return The instanced element, or nullptr if the instancing failed. + static ElementPtr InstanceElement(Element* parent, const String& instancer, const String& tag, const XMLAttributes& attributes); + + /// Instances a text element containing a string. + /// More than one element may be instanced if the string contains RML or RML is introduced during translation. + /// @param[in] parent The element any instanced elements will be parented to. + /// @param[in] text The text to instance the element (or elements) from. + /// @return True if the string was parsed without error, false otherwise. + static bool InstanceElementText(Element* parent, const String& text); + /// Instances an element tree based on the stream. + /// @param[in] parent The element the stream elements will be added to. + /// @param[in] stream The stream to read the element RML from. + /// @return True if the stream was parsed without error, false otherwise. + static bool InstanceElementStream(Element* parent, Stream* stream); + /// Instances a document from a stream. + /// @param[in] context The context that is creating the document. + /// @param[in] stream The stream to instance from. + /// @return The instanced document, or nullptr if an error occurred. + static ElementPtr InstanceDocumentStream(Context* context, Stream* stream); + + /// Registers a non-owning pointer to an instancer that will be used to instance decorators. + /// @param[in] name The name of the decorator the instancer will be called for. + /// @param[in] instancer The instancer to call when the decorator name is encountered. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + /// @return The added instancer if the registration was successful, nullptr otherwise. + static void RegisterDecoratorInstancer(const String& name, DecoratorInstancer* instancer); + /// Retrieves a decorator instancer registered with the factory. + /// @param[in] name The name of the desired decorator type. + /// @return The decorator instancer it it exists, nullptr otherwise. + static DecoratorInstancer* GetDecoratorInstancer(const String& name); + + /// Registers a non-owning pointer to an instancer that will be used to instance font effects. + /// @param[in] name The name of the font effect the instancer will be called for. + /// @param[in] instancer The instancer to call when the font effect name is encountered. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + /// @return The added instancer if the registration was successful, nullptr otherwise. + static void RegisterFontEffectInstancer(const String& name, FontEffectInstancer* instancer); + /// Retrieves a font-effect instancer registered with the factory. + /// @param[in] name The name of the desired font-effect type. + /// @return The font-effect instancer it it exists, nullptr otherwise. + static FontEffectInstancer* GetFontEffectInstancer(const String& name); + + /// Creates a style sheet from a user-generated string. + /// @param[in] string The contents of the style sheet. + /// @return A pointer to the newly created style sheet. + static SharedPtr InstanceStyleSheetString(const String& string); + /// Creates a style sheet from a file. + /// @param[in] file_name The location of the style sheet file. + /// @return A pointer to the newly created style sheet. + static SharedPtr InstanceStyleSheetFile(const String& file_name); + /// Creates a style sheet from an Stream. + /// @param[in] stream A pointer to the stream containing the style sheet's contents. + /// @return A pointer to the newly created style sheet. + static SharedPtr InstanceStyleSheetStream(Stream* stream); + /// Clears the style sheet cache. This will force style sheets to be reloaded. + static void ClearStyleSheetCache(); + /// Clears the template cache. This will force template to be reloaded. + static void ClearTemplateCache(); + + /// Registers an instancer for all events. + /// @param[in] instancer The instancer to be called. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + static void RegisterEventInstancer(EventInstancer* instancer); + /// Instance an event object + /// @param[in] target Target element of this event. + /// @param[in] name Name of this event. + /// @param[in] parameters Additional parameters for this event. + /// @param[in] interruptible If the event propagation can be stopped. + /// @return The instanced event. + static EventPtr InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible); + + /// Register the instancer to be used for all event listeners. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown, or until a new instancer is set. + static void RegisterEventListenerInstancer(EventListenerInstancer* instancer); + /// Instance an event listener with the given string. This is used for instancing listeners for the on* events from RML. + /// @param[in] value The parameters to the event listener. + /// @return The instanced event listener. + static EventListener* InstanceEventListener(const String& value, Element* element); + + /// Register an instancer for data views. + /// Structural views start a special XML parsing procedure when encountering a declaration of the view. Instead of instancing + /// children elements, the raw inner XML/RML contents are submitted to the initializing procedure of the view. + /// @param[in] instancer The instancer to be called. + /// @param[in] type_name The type name of the view, determines the element attribute that is used to initialize it. + /// @param[in] is_structural_view Set true if the view should be parsed as a structural view. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + static void RegisterDataViewInstancer(DataViewInstancer* instancer, const String& type_name, bool is_structural_view = false); + + /// Register an instancer for data controllers. + /// @param[in] instancer The instancer to be called. + /// @param[in] type_name The type name of the controller, determines the element attribute that is used to initialize it. + /// @lifetime The instancer must be kept alive until after the call to Rml::Shutdown. + static void RegisterDataControllerInstancer(DataControllerInstancer* instancer, const String& type_name); + + /// Instance the data view with the given type name. + static DataViewPtr InstanceDataView(const String& type_name, Element* element, bool is_structural_view); + + /// Instance the data controller with the given type name. + static DataControllerPtr InstanceDataController(const String& type_name, Element* element); + + /// Returns the list of element attribute names with an associated structural data view instancer. + static const StringList& GetStructuralDataViewAttributeNames(); + +private: + Factory(); + ~Factory(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/FileInterface.h b/thirdparty/RmlUi/Include/RmlUi/Core/FileInterface.h new file mode 100644 index 000000000..2df28663e --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/FileInterface.h @@ -0,0 +1,87 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FILEINTERFACE_H +#define RMLUI_CORE_FILEINTERFACE_H + +#include "Header.h" +#include "Types.h" +#include "Traits.h" + +namespace Rml { + +/** + The abstract base class for application-specific file I/O. + + By default, RmlUi will use a file interface implementing the standard C file functions. If this is not sufficient, + or your application wants more control over file I/O, this class should be derived, instanced, and installed + through Rml::SetFileInterface() before you initialise RmlUi. + + @author Peter Curry + */ + +class RMLUICORE_API FileInterface : public NonCopyMoveable +{ +public: + FileInterface(); + virtual ~FileInterface(); + + /// Opens a file. + /// @param file The file handle to write to. + /// @return A valid file handle, or nullptr on failure + virtual FileHandle Open(const String& path) = 0; + /// Closes a previously opened file. + /// @param file The file handle previously opened through Open(). + virtual void Close(FileHandle file) = 0; + + /// Reads data from a previously opened file. + /// @param buffer The buffer to be read into. + /// @param size The number of bytes to read into the buffer. + /// @param file The handle of the file. + /// @return The total number of bytes read into the buffer. + virtual size_t Read(void* buffer, size_t size, FileHandle file) = 0; + /// Seeks to a point in a previously opened file. + /// @param file The handle of the file to seek. + /// @param offset The number of bytes to seek. + /// @param origin One of either SEEK_SET (seek from the beginning of the file), SEEK_END (seek from the end of the file) or SEEK_CUR (seek from the current file position). + /// @return True if the operation completed successfully, false otherwise. + virtual bool Seek(FileHandle file, long offset, int origin) = 0; + /// Returns the current position of the file pointer. + /// @param file The handle of the file to be queried. + /// @return The number of bytes from the origin of the file. + virtual size_t Tell(FileHandle file) = 0; + + /// Returns the length of the file. + /// The default implementation uses Seek & Tell. + /// @param file The handle of the file to be queried. + /// @return The length of the file in bytes. + virtual size_t Length(FileHandle file); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/FontEffect.h b/thirdparty/RmlUi/Include/RmlUi/Core/FontEffect.h new file mode 100644 index 000000000..832899a25 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/FontEffect.h @@ -0,0 +1,92 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTEFFECT_H +#define RMLUI_CORE_FONTEFFECT_H + +#include "FontGlyph.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class RMLUICORE_API FontEffect +{ +public: + // Behind or in front of the main text. + enum class Layer { Back, Front }; + + FontEffect(); + virtual ~FontEffect(); + + /// Asks the font effect if it requires, and will generate, its own unique texture. If it does + /// not, it will share the font's base layer's textures instead. + /// @return True if the effect generates its own textures, false if not. The default implementation returns false. + virtual bool HasUniqueTexture() const; + + /// Requests the effect for a size and position of a single glyph's bitmap. + /// @param[out] origin The desired origin of the effect's glyph bitmap, as a pixel offset from its original origin. This defaults to (0, 0). + /// @param[out] dimensions The desired dimensions of the effect's glyph bitmap, in pixels. This defaults to the dimensions of the glyph's original bitmap. If the font effect is not generating a unique texture, this will be ignored. + /// @param[in] glyph The glyph the effect is being asked to size. + /// @return False if the effect is not providing support for the glyph, true otherwise. + virtual bool GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& glyph) const; + + /// Requests the effect to generate the texture data for a single glyph's bitmap. The default implementation does nothing. + /// @param[out] destination_data The top-left corner of the glyph's 32-bit, RGBA-ordered, destination texture. Note that the glyph shares its texture with other glyphs. + /// @param[in] destination_dimensions The dimensions of the glyph's area on its texture. + /// @param[in] destination_stride The stride of the glyph's texture. + /// @param[in] glyph The glyph the effect is being asked to generate an effect texture for. + virtual void GenerateGlyphTexture(byte* destination_data, Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const; + + /// Sets the colour of the effect's geometry. + void SetColour(const Colourb& colour); + /// Returns the effect's colour. + const Colourb& GetColour() const; + + Layer GetLayer() const; + void SetLayer(Layer layer); + + /// Returns the font effect's fingerprint. + /// @return A hash of the effect's type and properties used to generate the geometry and texture data. + size_t GetFingerprint() const; + void SetFingerprint(size_t fingerprint); + +private: + Layer layer; + + // The colour of the effect's geometry. + Colourb colour; + + // A hash value identifying the properties that affected the generation of the effect's geometry and texture data. + size_t fingerprint; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/FontEffectInstancer.h b/thirdparty/RmlUi/Include/RmlUi/Core/FontEffectInstancer.h new file mode 100644 index 000000000..3bf5bb207 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/FontEffectInstancer.h @@ -0,0 +1,90 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTEFFECTINSTANCER_H +#define RMLUI_CORE_FONTEFFECTINSTANCER_H + +#include "Traits.h" +#include "Header.h" +#include "PropertyDictionary.h" +#include "PropertySpecification.h" + +namespace Rml { + +class FontEffect; + +/** + A font effect instancer provides a method for allocating and deallocating font effects. + + It is important that the same instancer that allocated a font effect releases it. This ensures there are no issues + with memory from different DLLs getting mixed up. + + @author Peter Curry + */ + +class RMLUICORE_API FontEffectInstancer +{ +public: + FontEffectInstancer(); + virtual ~FontEffectInstancer(); + + /// Instances a font effect given the property tag and attributes from the RCSS file. + /// @param[in] name The type of font effect desired. For example, "font-effect: outline(1px black);" is declared as type "outline". + /// @param[in] properties All RCSS properties associated with the font effect. + /// @param[in] interface An interface for querying the active style sheet. + /// @return A shared_ptr to the font-effect if it was instanced successfully. + virtual SharedPtr InstanceFontEffect(const String& name, const PropertyDictionary& properties) = 0; + + /// Returns the property specification associated with the instancer. + const PropertySpecification& GetPropertySpecification() const; + +protected: + /// Registers a property for the font effect. + /// @param[in] property_name The name of the new property (how it is specified through RCSS). + /// @param[in] default_value The default value to be used. + /// @param[in] affects_generation True if this property affects the effect's texture data or glyph size, false if not. + /// @return The new property definition, ready to have parsers attached. + PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value, bool affects_generation = true); + /// Registers a shorthand property definition. + /// @param[in] shorthand_name The name to register the new shorthand property under. + /// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed. + /// @param[in] type The type of shorthand to declare. + /// @param True if all the property names exist, false otherwise. + ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type); + +private: + PropertySpecification properties; + + // Properties that define the geometry. + SmallUnorderedSet< PropertyId > volatile_properties; + + friend class Factory; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/FontEngineInterface.h b/thirdparty/RmlUi/Include/RmlUi/Core/FontEngineInterface.h new file mode 100644 index 000000000..cd8787cbb --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/FontEngineInterface.h @@ -0,0 +1,133 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEINTERFACE_H +#define RMLUI_CORE_FONTENGINEINTERFACE_H + +#include "Header.h" +#include "Types.h" +#include "ComputedValues.h" +#include "Geometry.h" + +namespace Rml { + +/** + The abstract base class for an application-specific font engine implementation. + + By default, RmlUi will use its own font engine with characters rendered through FreeType. To use your own engine, + provide a concrete implementation of this class and install it through Rml::SetFontEngineInterface(). + */ + + +class RMLUICORE_API FontEngineInterface +{ +public: + FontEngineInterface(); + virtual ~FontEngineInterface(); + + /// Called by RmlUi when it wants to load a font face from file. + /// @param[in] file_name The file to load the face from. + /// @param[in] fallback_face True to use this font face for unknown characters in other font faces. + /// @return True if the face was loaded successfully, false otherwise. + virtual bool LoadFontFace(const String& file_name, bool fallback_face); + + /// Called by RmlUi when it wants to load a font face from memory, registered using the provided family, style, and weight. + /// @param[in] data A pointer to the data. + /// @param[in] data_size Size of the data in bytes. + /// @param[in] family The family to register the font as. + /// @param[in] style The style to register the font as. + /// @param[in] weight The weight to register the font as. + /// @param[in] fallback_face True to use this font face for unknown characters in other font faces. + /// @return True if the face was loaded successfully, false otherwise. + /// Note: The debugger plugin will load its embedded font faces through this method using the family name 'rmlui-debugger-font'. + virtual bool LoadFontFace(const byte* data, int data_size, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face); + + /// Called by RmlUi when a font configuration is resolved for an element. Should return a handle that + /// can later be used to resolve properties of the face, and generate string geometry to be rendered. + /// @param[in] family The family of the desired font handle. + /// @param[in] style The style of the desired font handle. + /// @param[in] weight The weight of the desired font handle. + /// @param[in] size The size of desired handle, in points. + /// @return A valid handle if a matching (or closely matching) font face was found, NULL otherwise. + virtual FontFaceHandle GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size); + + /// Called by RmlUi when a list of font effects is resolved for an element with a given font face. + /// @param[in] handle The font handle. + /// @param[in] font_effects The list of font effects to generate the configuration for. + /// @return A handle to the prepared font effects which will be used when generating geometry for a string. + virtual FontEffectsHandle PrepareFontEffects(FontFaceHandle handle, const FontEffectList &font_effects); + + /// Should return the point size of this font face. + /// @param[in] handle The font handle. + /// @return The face's point size. + virtual int GetSize(FontFaceHandle handle); + /// Should return the pixel height of a lower-case x in this font face. + /// @param[in] handle The font handle. + /// @return The height of a lower-case x. + virtual int GetXHeight(FontFaceHandle handle); + /// Should return the default height between this font face's baselines. + /// @param[in] handle The font handle. + /// @return The default line height. + virtual int GetLineHeight(FontFaceHandle handle); + + /// Should return the font's baseline, as a pixel offset from the bottom of the font. + /// @param[in] handle The font handle. + /// @return The font's baseline. + virtual int GetBaseline(FontFaceHandle handle); + + /// Should return the font's underline, as a pixel offset from the bottom of the font. + /// @param[in] handle The font handle. + /// @param[out] thickness The font's underline thickness in pixels. + /// @return The underline pixel offset. + virtual float GetUnderline(FontFaceHandle handle, float &thickness); + + /// Called by RmlUi when it wants to retrieve the width of a string when rendered with this handle. + /// @param[in] handle The font handle. + /// @param[in] string The string to measure. + /// @param[in] prior_character The optionally-specified character that immediately precedes the string. This may have an impact on the string width due to kerning. + /// @return The width, in pixels, this string will occupy if rendered with this handle. + virtual int GetStringWidth(FontFaceHandle handle, const String& string, Character prior_character = Character::Null); + + /// Called by RmlUi when it wants to retrieve the geometry required to render a single line of text. + /// @param[in] face_handle The font handle. + /// @param[in] font_effects_handle The handle to the prepared font effects for which the geometry should be generated. + /// @param[in] string The string to render. + /// @param[in] position The position of the baseline of the first character to render. + /// @param[in] colour The colour to render the text. + /// @param[out] geometry An array of geometries to generate the geometry into. + /// @return The width, in pixels, of the string geometry. + virtual int GenerateString(FontFaceHandle face_handle, FontEffectsHandle font_effects_handle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry); + + /// Called by RmlUi to determine if the text geometry is required to be re-generated. Whenever the returned version + /// is changed, all geometry belonging to the given face handle will be re-generated. + /// @param[in] face_handle The font handle. + /// @return The version required for using any geometry generated with the face handle. + virtual int GetVersion(FontFaceHandle handle); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/FontGlyph.h b/thirdparty/RmlUi/Include/RmlUi/Core/FontGlyph.h new file mode 100644 index 000000000..925acc386 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/FontGlyph.h @@ -0,0 +1,82 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTGLYPH_H +#define RMLUI_CORE_FONTGLYPH_H + +#include "Types.h" + +namespace Rml { + +/** + Metrics and bitmap data for a single glyph within a font face. + + @author Peter Curry + */ + +class RMLUICORE_API FontGlyph +{ +public: + FontGlyph() : dimensions(0,0), bearing(0,0), advance(0), bitmap_data(nullptr), bitmap_dimensions(0,0) + {} + + /// The glyph's bounding box. Not to be confused with the dimensions of the glyph's bitmap! + Vector2i dimensions; + /// The distance from the cursor (positioned vertically on the baseline) to the top-left corner + /// of this glyph's bitmap. + Vector2i bearing; + /// The glyph's advance; this is how far the cursor will be moved along after rendering this + /// character. + int advance; + + /// 8-bit opacity information for the glyph's bitmap. The size of the data is given by the + /// dimensions, below. This will be nullptr if the glyph has no bitmap data. + const byte* bitmap_data; + /// The dimensions of the glyph's bitmap. + Vector2i bitmap_dimensions; + + // Bitmap_data may point to this member or another font glyph data. + UniquePtr bitmap_owned_data; + + // Create a copy with its bitmap data owned by another glyph. + FontGlyph WeakCopy() const + { + FontGlyph glyph; + glyph.dimensions = dimensions; + glyph.bearing = bearing; + glyph.advance = advance; + glyph.bitmap_data = bitmap_data; + glyph.bitmap_dimensions = bitmap_dimensions; + return glyph; + } +}; + +using FontGlyphMap = UnorderedMap; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Geometry.h b/thirdparty/RmlUi/Include/RmlUi/Core/Geometry.h new file mode 100644 index 000000000..ac3304ec5 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Geometry.h @@ -0,0 +1,112 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_GEOMETRY_H +#define RMLUI_CORE_GEOMETRY_H + +#include "Header.h" +#include "Vertex.h" +#include + +namespace Rml { + +class Context; +class Element; +class RenderInterface; +struct Texture; +using GeometryDatabaseHandle = uint32_t; + +/** + A helper object for holding an array of vertices and indices, and compiling it as necessary when rendered. + + @author Peter Curry + */ + +class RMLUICORE_API Geometry +{ +public: + Geometry(Element* host_element = nullptr); + Geometry(Context* host_context); + + Geometry(const Geometry&) = delete; + Geometry& operator=(const Geometry&) = delete; + + Geometry(Geometry&& other); + Geometry& operator=(Geometry&& other); + + ~Geometry(); + + /// Set the host element for this geometry; this should be passed in the constructor if possible. + /// @param[in] host_element The new host element for the geometry. + void SetHostElement(Element* host_element); + + /// Attempts to compile the geometry if appropriate, then renders the geometry, compiled if it can. + /// @param[in] translation The translation of the geometry. + void Render(const Vector2f& translation); + + /// Returns the geometry's vertices. If these are written to, Release() should be called to force a recompile. + /// @return The geometry's vertex array. + Vector< Vertex >& GetVertices(); + /// Returns the geometry's indices. If these are written to, Release() should be called to force a recompile. + /// @return The geometry's index array. + Vector< int >& GetIndices(); + + /// Gets the geometry's texture. + /// @return The geometry's texture. + const Texture* GetTexture() const; + /// Sets the geometry's texture. + void SetTexture(const Texture* texture); + + /// Releases any previously-compiled geometry, and forces any new geometry to have a compile attempted. + /// @param[in] clear_buffers True to also clear the vertex and index buffers, false to leave intact. + void Release(bool clear_buffers = false); + +private: + // Move members from another geometry. + void MoveFrom(Geometry& other); + + // Returns the host context's render interface. + RenderInterface* GetRenderInterface(); + + Context* host_context = nullptr; + Element* host_element = nullptr; + + Vector< Vertex > vertices; + Vector< int > indices; + const Texture* texture = nullptr; + + CompiledGeometryHandle compiled_geometry = 0; + bool compile_attempted = false; + + GeometryDatabaseHandle database_handle; +}; + +using GeometryList = Vector< Geometry >; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/GeometryUtilities.h b/thirdparty/RmlUi/Include/RmlUi/Core/GeometryUtilities.h new file mode 100644 index 000000000..db6acc146 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/GeometryUtilities.h @@ -0,0 +1,83 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_GEOMETRYUTILITIES_H +#define RMLUI_CORE_GEOMETRYUTILITIES_H + +#include "Header.h" +#include "Types.h" +#include "Vertex.h" +#include "ComputedValues.h" + +namespace Rml { + +class Geometry; + +/** + A class containing helper functions for rendering geometry. + + @author Robert Curry + */ + +class RMLUICORE_API GeometryUtilities +{ +public: + /// Generates a quad from a position, size and colour. + /// @param[out] vertices An array of at least four vertices that the generated vertex data will be written into. + /// @param[out] indices An array of at least six indices that the generated index data will be written into. + /// @param[in] origin The origin of the quad to generate. + /// @param[in] dimensions The dimensions of the quad to generate. + /// @param[in] colour The colour to be assigned to each of the quad's vertices. + /// @param[in] index_offset The offset to be added to the generated indices; this should be the number of vertices already in the array. + static void GenerateQuad(Vertex* vertices, int* indices, const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour, int index_offset = 0); + /// Generates a quad from a position, size, colour and texture coordinates. + /// @param[out] vertices An array of at least four vertices that the generated vertex data will be written into. + /// @param[out] indices An array of at least six indices that the generated index data will be written into. + /// @param[in] origin The origin of the quad to generate. + /// @param[in] dimensions The dimensions of the quad to generate. + /// @param[in] colour The colour to be assigned to each of the quad's vertices. + /// @param[in] top_left_texcoord The texture coordinates at the top-left of the quad. + /// @param[in] bottom_right_texcoord The texture coordinates at the bottom-right of the quad. + /// @param[in] index_offset The offset to be added to the generated indices; this should be the number of vertices already in the array. + static void GenerateQuad(Vertex* vertices, int* indices, const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour, const Vector2f& top_left_texcoord, const Vector2f& bottom_right_texcoord, int index_offset = 0); + + /// Generates the geometry required to render a line above, below or through a line of text. + /// @param[out] geometry The geometry to append the newly created geometry into. + /// @param[in] position The position of the baseline of the lined text. + /// @param[in] width The width of the string to line. + /// @param[in] decoration_type The type for vertical positioning of line. + /// @param[in] colour The colour to draw the line in. + static void GenerateLine(FontFaceHandle font_face_handle, Geometry* geometry, const Vector2f& position, int width, Style::TextDecoration decoration_type, const Colourb& colour); + +private: + GeometryUtilities(); + ~GeometryUtilities(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Header.h b/thirdparty/RmlUi/Include/RmlUi/Core/Header.h new file mode 100644 index 000000000..68089330a --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Header.h @@ -0,0 +1,86 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_HEADER_H +#define RMLUI_CORE_HEADER_H + +#include "Platform.h" + +// Note: Changing a RMLUICORE_API_INLINE method +// breaks ABI compatibility!! + +#if !defined RMLUI_STATIC_LIB + #if defined RMLUI_PLATFORM_WIN32 + #if defined RmlCore_EXPORTS + #define RMLUICORE_API __declspec(dllexport) + // Note: Changing a RMLUICORE_API_INLINE method + // breaks ABI compatibility!! + + // This results in an exported method from the DLL + // that may be inlined in DLL clients, or if not + // possible the client may choose to import the copy + // in the DLL if it can not be inlined. + #define RMLUICORE_API_INLINE __declspec(dllexport) inline + #else + #define RMLUICORE_API __declspec(dllimport) + // Note: Changing a RMLUICORE_API_INLINE method + // breaks ABI compatibility!! + + // Based on the warnngs emitted by GCC/MinGW if using + // dllimport and inline together, the information at + // http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx + // using dllimport inline is tricky. + #if defined(_MSC_VER) + // VisualStudio dllimport inline is supported + // and may be expanded to inline code when the + // /Ob1 or /Ob2 options are given for inline + // expansion, or pulled from the DLL if it can + // not be inlined. + #define RMLUICORE_API_INLINE __declspec(dllimport) inline + #else + // MinGW 32/64 dllimport inline is not supported + // and dllimport is ignored, so we avoid using + // it here to squelch compiler generated + // warnings. + #define RMLUICORE_API_INLINE inline + #endif + #endif + #else + #define RMLUICORE_API __attribute__((visibility("default"))) + // Note: Changing a RMLUICORE_API_INLINE method + // breaks ABI compatibility!! + #define RMLUICORE_API_INLINE __attribute__((visibility("default"))) inline + #endif +#else + #define RMLUICORE_API + // Note: Changing a RMLUICORE_API_INLINE method + // breaks ABI compatibility!! + #define RMLUICORE_API_INLINE inline +#endif + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ID.h b/thirdparty/RmlUi/Include/RmlUi/Core/ID.h new file mode 100644 index 000000000..2440001ef --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ID.h @@ -0,0 +1,214 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#ifndef RMLUI_CORE_ID_H +#define RMLUI_CORE_ID_H + +#include + +namespace Rml { + +enum class ShorthandId : uint8_t +{ + Invalid, + + /* + The following values define the shorthand ids for the main stylesheet specification. + These values must not be used in places that have their own property specification, + such as decorators and font-effects. + */ + Margin, + Padding, + BorderWidth, + BorderColor, + BorderTop, + BorderRight, + BorderBottom, + BorderLeft, + Border, + Overflow, + Background, + Font, + PerspectiveOrigin, + TransformOrigin, + + NumDefinedIds, + FirstCustomId = NumDefinedIds, + + // The maximum number of IDs. This limits the number of possible custom IDs to MaxNumIds - FirstCustomId. + MaxNumIds = 0xff +}; + + +enum class PropertyId : uint8_t +{ + Invalid, + + /* + The following values define the property ids for the main stylesheet specification. + These values must not be used in places that have their own property specification, + such as decorators and font-effects. + */ + MarginTop, + MarginRight, + MarginBottom, + MarginLeft, + PaddingTop, + PaddingRight, + PaddingBottom, + PaddingLeft, + BorderTopWidth, + BorderRightWidth, + BorderBottomWidth, + BorderLeftWidth, + BorderTopColor, + BorderRightColor, + BorderBottomColor, + BorderLeftColor, + Display, + Position, + Top, + Right, + Bottom, + Left, + Float, + Clear, + ZIndex, + Width, + MinWidth, + MaxWidth, + Height, + MinHeight, + MaxHeight, + LineHeight, + VerticalAlign, + OverflowX, + OverflowY, + Clip, + Visibility, + BackgroundColor, + Color, + ImageColor, + FontFamily, + FontStyle, + FontWeight, + FontSize, + TextAlign, + TextDecoration, + TextTransform, + WhiteSpace, + Cursor, + Drag, + TabIndex, + ScrollbarMargin, + + Perspective, + PerspectiveOriginX, + PerspectiveOriginY, + Transform, + TransformOriginX, + TransformOriginY, + TransformOriginZ, + + Transition, + Animation, + + Opacity, + PointerEvents, + Focus, + + Decorator, + FontEffect, + + FillImage, + + NumDefinedIds, + FirstCustomId = NumDefinedIds, + + // The maximum number of IDs. This limits the number of possible custom IDs to MaxNumIds - FirstCustomId. + MaxNumIds = 128 +}; + + +enum class EventId : uint16_t +{ + Invalid, + + // Core events + Mousedown, + Mousescroll, + Mouseover, + Mouseout, + Focus, + Blur, + Keydown, + Keyup, + Textinput, + Mouseup, + Click, + Dblclick, + Load, + Unload, + Show, + Hide, + Mousemove, + Dragmove, + Drag, + Dragstart, + Dragover, + Dragdrop, + Dragout, + Dragend, + Handledrag, + Resize, + Scroll, + Animationend, + Transitionend, + + // Form control events + Change, + Submit, + Tabchange, + Columnadd, + Rowadd, + Rowchange, + Rowremove, + Rowupdate, + + NumDefinedIds, + + // Custom IDs start here + FirstCustomId = NumDefinedIds, + + // The maximum number of IDs. This limits the number of possible custom IDs to MaxNumIds - FirstCustomId. + MaxNumIds = 0xffff +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Input.h b/thirdparty/RmlUi/Include/RmlUi/Core/Input.h new file mode 100644 index 000000000..06fe53474 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Input.h @@ -0,0 +1,273 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_INPUT_H +#define RMLUI_CORE_INPUT_H + +namespace Rml { + +/* + Enumerants for sending input events into RmlUi. + + @author Peter Curry + */ + +namespace Input +{ + enum KeyIdentifier + { + KI_UNKNOWN = 0, + + KI_SPACE = 1, + + KI_0 = 2, + KI_1 = 3, + KI_2 = 4, + KI_3 = 5, + KI_4 = 6, + KI_5 = 7, + KI_6 = 8, + KI_7 = 9, + KI_8 = 10, + KI_9 = 11, + + KI_A = 12, + KI_B = 13, + KI_C = 14, + KI_D = 15, + KI_E = 16, + KI_F = 17, + KI_G = 18, + KI_H = 19, + KI_I = 20, + KI_J = 21, + KI_K = 22, + KI_L = 23, + KI_M = 24, + KI_N = 25, + KI_O = 26, + KI_P = 27, + KI_Q = 28, + KI_R = 29, + KI_S = 30, + KI_T = 31, + KI_U = 32, + KI_V = 33, + KI_W = 34, + KI_X = 35, + KI_Y = 36, + KI_Z = 37, + + KI_OEM_1 = 38, // US standard keyboard; the ';:' key. + KI_OEM_PLUS = 39, // Any region; the '=+' key. + KI_OEM_COMMA = 40, // Any region; the ',<' key. + KI_OEM_MINUS = 41, // Any region; the '-_' key. + KI_OEM_PERIOD = 42, // Any region; the '.>' key. + KI_OEM_2 = 43, // Any region; the '/?' key. + KI_OEM_3 = 44, // Any region; the '`~' key. + + KI_OEM_4 = 45, // US standard keyboard; the '[{' key. + KI_OEM_5 = 46, // US standard keyboard; the '\|' key. + KI_OEM_6 = 47, // US standard keyboard; the ']}' key. + KI_OEM_7 = 48, // US standard keyboard; the ''"' key. + KI_OEM_8 = 49, + + KI_OEM_102 = 50, // RT 102-key keyboard; the '<>' or '\|' key. + + KI_NUMPAD0 = 51, + KI_NUMPAD1 = 52, + KI_NUMPAD2 = 53, + KI_NUMPAD3 = 54, + KI_NUMPAD4 = 55, + KI_NUMPAD5 = 56, + KI_NUMPAD6 = 57, + KI_NUMPAD7 = 58, + KI_NUMPAD8 = 59, + KI_NUMPAD9 = 60, + KI_NUMPADENTER = 61, + KI_MULTIPLY = 62, // Asterisk on the numeric keypad. + KI_ADD = 63, // Plus on the numeric keypad. + KI_SEPARATOR = 64, + KI_SUBTRACT = 65, // Minus on the numeric keypad. + KI_DECIMAL = 66, // Period on the numeric keypad. + KI_DIVIDE = 67, // Forward Slash on the numeric keypad. + + /* + * NEC PC-9800 kbd definitions + */ + KI_OEM_NEC_EQUAL = 68, // Equals key on the numeric keypad. + + KI_BACK = 69, // Backspace key. + KI_TAB = 70, // Tab key. + + KI_CLEAR = 71, + KI_RETURN = 72, + + KI_PAUSE = 73, + KI_CAPITAL = 74, // Capslock key. + + KI_KANA = 75, // IME Kana mode. + KI_HANGUL = 76, // IME Hangul mode. + KI_JUNJA = 77, // IME Junja mode. + KI_FINAL = 78, // IME final mode. + KI_HANJA = 79, // IME Hanja mode. + KI_KANJI = 80, // IME Kanji mode. + + KI_ESCAPE = 81, // Escape key. + + KI_CONVERT = 82, // IME convert. + KI_NONCONVERT = 83, // IME nonconvert. + KI_ACCEPT = 84, // IME accept. + KI_MODECHANGE = 85, // IME mode change request. + + KI_PRIOR = 86, // Page Up key. + KI_NEXT = 87, // Page Down key. + KI_END = 88, + KI_HOME = 89, + KI_LEFT = 90, // Left Arrow key. + KI_UP = 91, // Up Arrow key. + KI_RIGHT = 92, // Right Arrow key. + KI_DOWN = 93, // Down Arrow key. + KI_SELECT = 94, + KI_PRINT = 95, + KI_EXECUTE = 96, + KI_SNAPSHOT = 97, // Print Screen key. + KI_INSERT = 98, + KI_DELETE = 99, + KI_HELP = 100, + + KI_LWIN = 101, // Left Windows key. + KI_RWIN = 102, // Right Windows key. + KI_APPS = 103, // Applications key. + + KI_POWER = 104, + KI_SLEEP = 105, + KI_WAKE = 106, + + KI_F1 = 107, + KI_F2 = 108, + KI_F3 = 109, + KI_F4 = 110, + KI_F5 = 111, + KI_F6 = 112, + KI_F7 = 113, + KI_F8 = 114, + KI_F9 = 115, + KI_F10 = 116, + KI_F11 = 117, + KI_F12 = 118, + KI_F13 = 119, + KI_F14 = 120, + KI_F15 = 121, + KI_F16 = 122, + KI_F17 = 123, + KI_F18 = 124, + KI_F19 = 125, + KI_F20 = 126, + KI_F21 = 127, + KI_F22 = 128, + KI_F23 = 129, + KI_F24 = 130, + + KI_NUMLOCK = 131, // Numlock key. + KI_SCROLL = 132, // Scroll Lock key. + + /* + * Fujitsu/OASYS kbd definitions + */ + KI_OEM_FJ_JISHO = 133, // 'Dictionary' key. + KI_OEM_FJ_MASSHOU = 134, // 'Unregister word' key. + KI_OEM_FJ_TOUROKU = 135, // 'Register word' key. + KI_OEM_FJ_LOYA = 136, // 'Left OYAYUBI' key. + KI_OEM_FJ_ROYA = 137, // 'Right OYAYUBI' key. + + KI_LSHIFT = 138, + KI_RSHIFT = 139, + KI_LCONTROL = 140, + KI_RCONTROL = 141, + KI_LMENU = 142, + KI_RMENU = 143, + + KI_BROWSER_BACK = 144, + KI_BROWSER_FORWARD = 145, + KI_BROWSER_REFRESH = 146, + KI_BROWSER_STOP = 147, + KI_BROWSER_SEARCH = 148, + KI_BROWSER_FAVORITES = 149, + KI_BROWSER_HOME = 150, + + KI_VOLUME_MUTE = 151, + KI_VOLUME_DOWN = 152, + KI_VOLUME_UP = 153, + KI_MEDIA_NEXT_TRACK = 154, + KI_MEDIA_PREV_TRACK = 155, + KI_MEDIA_STOP = 156, + KI_MEDIA_PLAY_PAUSE = 157, + KI_LAUNCH_MAIL = 158, + KI_LAUNCH_MEDIA_SELECT = 159, + KI_LAUNCH_APP1 = 160, + KI_LAUNCH_APP2 = 161, + + /* + * Various extended or enhanced keyboards + */ + KI_OEM_AX = 162, + KI_ICO_HELP = 163, + KI_ICO_00 = 164, + + KI_PROCESSKEY = 165, // IME Process key. + + KI_ICO_CLEAR = 166, + + KI_ATTN = 167, + KI_CRSEL = 168, + KI_EXSEL = 169, + KI_EREOF = 170, + KI_PLAY = 171, + KI_ZOOM = 172, + KI_PA1 = 173, + KI_OEM_CLEAR = 174, + + KI_LMETA = 175, + KI_RMETA = 176 + }; + + enum KeyModifier + { + KM_CTRL = 1 << 0, // Set if at least one Ctrl key is depressed. + KM_SHIFT = 1 << 1, // Set if at least one Shift key is depressed. + KM_ALT = 1 << 2, // Set if at least one Alt key is depressed. + KM_META = 1 << 3, // Set if at least one Meta key (the command key) is depressed. + KM_CAPSLOCK = 1 << 4, // Set if caps lock is enabled. + KM_NUMLOCK = 1 << 5, // Set if num lock is enabled. + KM_SCROLLLOCK = 1 << 6 // Set if scroll lock is enabled. + }; +} + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Log.h b/thirdparty/RmlUi/Include/RmlUi/Core/Log.h new file mode 100644 index 000000000..5ca20f460 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Log.h @@ -0,0 +1,77 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LOG_H +#define RMLUI_CORE_LOG_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +/** + RmlUi logging API. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API Log +{ +public: + enum Type + { + LT_ALWAYS = 0, + LT_ERROR, + LT_ASSERT, + LT_WARNING, + LT_INFO, + LT_DEBUG, + LT_MAX + }; + +public: + /// Initialises the logging interface. + /// @return True if the logging interface was successful, false if not. + static bool Initialise(); + /// Shutdown the log interface. + static void Shutdown(); + + /// Log the specified message via the registered log interface + /// @param[in] type Type of message. + /// @param[in] format The message, with sprintf-style parameters. + static void Message(Type type, const char* format, ...); + + /// Log a parse error on the specified file and line number. + /// @param[in] filename Name of the file with the parse error. + /// @param[in] line_number Line the error occured on. + /// @param[in] format The error message, with sprintf-style parameters. + static void ParseError(const String& filename, int line_number, const char* format, ...); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Math.h b/thirdparty/RmlUi/Include/RmlUi/Core/Math.h new file mode 100644 index 000000000..d64ba7275 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Math.h @@ -0,0 +1,185 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_MATH_H +#define RMLUI_CORE_MATH_H + +#include "Header.h" + +namespace Rml { + +namespace Math { + +// The constant PI. +extern RMLUICORE_API const float RMLUI_PI; + +template < typename Type > +Type Max(Type a, Type b) +{ + return (a > b) ? a : b; +} + +template< typename Type > +Type Min(Type a, Type b) +{ + return (a < b) ? a : b; +} + +template < typename Type > +Type ClampLower(Type value, Type min) +{ + return (value < min) ? min : value; +} + +template < typename Type > +Type ClampUpper(Type value, Type max) +{ + return (value > max) ? max: value; +} + +template< typename Type > +Type Clamp(Type value, Type min, Type max) +{ + return (value < min) ? min : (value > max) ? max : value; +} + +/// Evaluates if a number is, or close to, zero. +/// @param[in] value The number to compare to zero. +/// @return True if the number if zero or close to it, false otherwise. +RMLUICORE_API bool IsZero(float value); +/// Evaluates if two floating-point numbers are equal, or so similar that they could be considered +/// so. +/// @param[in] value_0 The first number to compare. +/// @param[in] value_1 The second number to compare. +/// @return True if the numbers are similar or equal. +RMLUICORE_API bool AreEqual(float value_0, float value_1); + +/// Calculates the absolute value of a number. +/// @param[in] value The number of get the absolute value of. +/// @return The absolute value of the number. +RMLUICORE_API float AbsoluteValue(float value); + +/// Calculates the cosine of an angle. +/// @param[in] angle The angle to calculate the cosine of, in radians. +/// @return The cosine of the angle. +RMLUICORE_API float Cos(float angle); +/// Calculates the arc-cosine of an value. +/// @param[in] angle The value to calculate the arc-cosine of. +/// @return The angle, in radians. +RMLUICORE_API float ACos(float value); +/// Calculates the sine of an angle. +/// @param[in] angle The angle to calculate the sine of, in radians. +/// @return The sine of the angle. +RMLUICORE_API float Sin(float angle); +/// Calculates the arc-sine of an value. +/// @param[in] angle The value to calculate the arc-sine of. +/// @return The angle, in radians. +RMLUICORE_API float ASin(float angle); +/// Calculates the tangent of an angle. +/// @param[in] angle The angle to calculate the tangent of, in radians. +/// @return The tanget of the angle. +RMLUICORE_API float Tan(float angle); +/// Calculates the angle of a two-dimensional line. +/// @param[in] y The y-component of the line. +/// @param[in] x The x-component of the line. +/// @return The angle of the line in radians. +RMLUICORE_API float ATan2(float y, float x); +/// Evaluates the natural exponential function on a value. +/// @param[in] value The value +/// @return e^(value) +RMLUICORE_API float Exp(float value); + +/// Converts an angle from radians to degrees. +/// @param[in] The angle, in radians. +/// @return The angle converted to degrees. +RMLUICORE_API float RadiansToDegrees(float angle); +/// Converts an angle from degrees to radians. +/// @param[in] The angle, in degrees. +/// @return The angle converted to radians. +RMLUICORE_API float DegreesToRadians(float angle); +/// Normalises and angle in radians +/// @param[in] The angle, in randians +/// @return The normalised angle +RMLUICORE_API float NormaliseAngle(float angle); + +/// Calculates the square root of a value. +/// @param[in] value The value to calculate the square root of. This must be above zero. +/// @return The square root of the value. +RMLUICORE_API float SquareRoot(float value); + +/// Rounds a floating-point value to the nearest integer. +/// @param[in] value The value to round. +/// @return The rounded integer as float. +RMLUICORE_API float RoundFloat(float value); +/// Rounds a floating-point value to the nearest integer. +/// @param[in] value The value to round. +/// @return The rounded integer as double. +RMLUICORE_API double RoundFloat(double value); +/// Rounds a floating-point value to the nearest integer. +/// @param[in] value The value to round. +/// @return The rounded integer. +RMLUICORE_API int RoundToInteger(float value); +/// Rounds a floating-point value up to the nearest integer. +/// @param[in] value The value to round. +/// @return The rounded integer. +RMLUICORE_API int RoundUpToInteger(float value); +/// Rounds a floating-point value down to the nearest integer. +/// @param[in] value The value to round. +/// @return The rounded integer. +RMLUICORE_API int RoundDownToInteger(float value); + +/// Efficiently truncates a floating-point value into an integer. +/// @param[in] value The value to truncate. +/// @return The truncated value as a signed integer. +RMLUICORE_API int RealToInteger(float value); + +/// Converts a number to the nearest power of two, rounding up if necessary. +/// @param[in] value The value to convert to a power-of-two. +/// @return The smallest power of two that is as least as big as the input value. +RMLUICORE_API int ToPowerOfTwo(int value); + +/// Converts from the ASCII-representation of a hexadecimal digit to decimal. +/// @param[in] hex_digit The hexadecimal digit to convert to decimal. +/// @return The digit in decimal. +RMLUICORE_API int HexToDecimal(char hex_digit); + +/// Generates a random floating-point value between 0 and a user-specified value. +/// @param[in] max_value The limit to random value. The generated value will be guaranteed to be below this limit. +/// @return The random value. +RMLUICORE_API float RandomReal(float max_value); +/// Generates a random integer value between 0 and a user-specified value. +/// @param[in] max_value The limit to random value. The generated value will be guaranteed to be below this limit. +/// @return The random value. +RMLUICORE_API int RandomInteger(int max_value); +/// Generates a random boolean value, with equal chance of true or false. +/// @return The random value. +RMLUICORE_API bool RandomBool(); + +} +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/MathTypes.h b/thirdparty/RmlUi/Include/RmlUi/Core/MathTypes.h new file mode 100644 index 000000000..9aec39b6d --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/MathTypes.h @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_MATHTYPES_H +#define RMLUI_CORE_MATHTYPES_H + +#include "Header.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Vector4.h" + +namespace Rml { + +// Define common Vector2 types. +typedef Vector2< int > Vector2i; +typedef Vector2< float > Vector2f; +RMLUICORE_API Vector2i operator*(int lhs, const Vector2i& rhs); +RMLUICORE_API Vector2f operator*(float lhs, const Vector2f& rhs); + +// Define common Vector3 types. +typedef Vector3< int > Vector3i; +typedef Vector3< float > Vector3f; +RMLUICORE_API Vector3i operator*(int lhs, const Vector3i& rhs); +RMLUICORE_API Vector3f operator*(float lhs, const Vector3f& rhs); + +// Define common Vector4 types. +typedef Vector4< int > Vector4i; +typedef Vector4< float > Vector4f; +RMLUICORE_API Vector4i operator*(int lhs, const Vector4i& rhs); +RMLUICORE_API Vector4f operator*(float lhs, const Vector4f& rhs); + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Matrix4.h b/thirdparty/RmlUi/Include/RmlUi/Core/Matrix4.h new file mode 100644 index 000000000..0ed62f034 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Matrix4.h @@ -0,0 +1,511 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_MATRIX4_H +#define RMLUI_CORE_MATRIX4_H + +#include "Debug.h" +#include "Math.h" +#include "Vector4.h" + +namespace Rml { + +/** + Templated class that acts as base strategy for vectors access patterns of matrices. + @author Markus Schöngart + */ +template< typename Component > +struct MatrixStorageBase +{ + typedef Component ComponentType; + typedef Vector4< ComponentType > VectorType; + typedef VectorType VectorsType[4]; + + class StrideVector + { + VectorsType& vectors; + int idx; + + public: + inline StrideVector(VectorsType& vectors, int idx) noexcept + : vectors(vectors), idx(idx) { } + inline ComponentType& operator[](int i) noexcept + { return vectors[i][idx]; } + inline StrideVector& operator=(const VectorType& vec) noexcept + { + (*this)[0] = vec[0]; + (*this)[1] = vec[1]; + (*this)[2] = vec[2]; + (*this)[3] = vec[3]; + return *this; + } + operator const VectorType() const noexcept + { + return VectorType( + (*this)[0], + (*this)[1], + (*this)[2], + (*this)[3] + ); + } + }; + class StrideAccess + { + VectorsType& vectors; + public: + inline StrideAccess(VectorsType& vectors) noexcept + : vectors(vectors) { } + inline StrideVector operator[](int i) noexcept + { return StrideVector(vectors, i); } + }; + class ConstStrideVector + { + const VectorsType& vectors; + int idx; + public: + inline ConstStrideVector(const VectorsType& vectors, int idx) noexcept + : vectors(vectors), idx(idx) { } + inline const ComponentType& operator[](int i) const noexcept + { return vectors[i][idx]; } + inline operator const VectorType() const noexcept + { + return VectorType( + (*this)[0], + (*this)[1], + (*this)[2], + (*this)[3] + ); + } + }; + class ConstStrideAccess + { + const VectorsType& vectors; + public: + inline ConstStrideAccess(const VectorsType& vectors) noexcept + : vectors(vectors) { } + inline ConstStrideVector operator[](int i) noexcept + { return ConstStrideVector(vectors, i); } + }; + + class PackedVector + { + VectorType& vector; + public: + inline PackedVector(VectorType& vector) noexcept + : vector(vector) { } + inline ComponentType& operator[](int i) noexcept + { return vector[i]; } + inline PackedVector& operator=(const VectorType& vec) noexcept + { + vector = vec; + return *this; + } + inline PackedVector& operator=(StrideVector& vec) noexcept + { + vector[0] = vec[0]; + vector[1] = vec[1]; + vector[2] = vec[2]; + vector[3] = vec[3]; + return *this; + } + inline PackedVector& operator=(ConstStrideVector& vec) noexcept + { + vector[0] = vec[0]; + vector[1] = vec[1]; + vector[2] = vec[2]; + vector[3] = vec[3]; + return *this; + } + inline operator VectorType&() noexcept { return vector; } + }; + class PackedAccess + { + VectorsType& vectors; + public: + inline PackedAccess(VectorsType& vectors) noexcept + : vectors(vectors) { } + inline PackedVector operator[](int i) noexcept + { return PackedVector(vectors[i]); } + }; + #if 0 + class ConstPackedVector + { + const VectorType& vectors; + public: + inline ConstPackedVector(const VectorType& vectors) noexcept + : vectors(vectors) { } + inline const ComponentType& operator[](int i) const noexcept + { return vectors[i]; } + inline operator const VectorType&() noexcept { return vectors; } + }; + #endif + class ConstPackedAccess + { + const VectorsType& vectors; + public: + inline ConstPackedAccess(const VectorsType& vectors) noexcept + : vectors(vectors) { } + inline const VectorType& operator[](int i) noexcept + { return vectors[i]; } + }; +}; + +template< typename Component > +struct RowMajorStorage; +template< typename Component > +struct ColumnMajorStorage; + +/** + Templated class that defines the vectors access pattern for row-major matrices. + @author Markus Schöngart + */ +template< typename Component > +struct RowMajorStorage : public MatrixStorageBase< Component > +{ + typedef Component ComponentType; + typedef Vector4< ComponentType > VectorType; + typedef RowMajorStorage< ComponentType > ThisType; + typedef ColumnMajorStorage< ComponentType > TransposeType; + + typedef typename MatrixStorageBase< Component >::PackedVector Row; + typedef typename MatrixStorageBase< Component >::PackedAccess Rows; + typedef const typename MatrixStorageBase< Component >::VectorType& ConstRow; + typedef typename MatrixStorageBase< Component >::ConstPackedAccess ConstRows; + typedef typename MatrixStorageBase< Component >::StrideVector Column; + typedef typename MatrixStorageBase< Component >::StrideAccess Columns; + typedef typename MatrixStorageBase< Component >::ConstStrideVector ConstColumn; + typedef typename MatrixStorageBase< Component >::ConstStrideAccess ConstColumns; +}; + +/** + Templated class that defines the vectors access pattern for column-major matrices. + @author Markus Schöngart + */ +template< typename Component > +struct ColumnMajorStorage +{ + typedef Component ComponentType; + typedef Vector4< ComponentType > VectorType; + typedef ColumnMajorStorage< ComponentType > ThisType; + typedef RowMajorStorage< ComponentType > TransposeType; + + typedef typename MatrixStorageBase< Component >::PackedVector Column; + typedef typename MatrixStorageBase< Component >::PackedAccess Columns; + typedef const typename MatrixStorageBase< Component >::VectorType& ConstColumn; + typedef typename MatrixStorageBase< Component >::ConstPackedAccess ConstColumns; + typedef typename MatrixStorageBase< Component >::StrideVector Row; + typedef typename MatrixStorageBase< Component >::StrideAccess Rows; + typedef typename MatrixStorageBase< Component >::ConstStrideVector ConstRow; + typedef typename MatrixStorageBase< Component >::ConstStrideAccess ConstRows; +}; + +/** + Templated class for a generic 4x4 matrix. + @author Markus Schöngart + */ + +template< typename Component, class Storage = ColumnMajorStorage< Component > > +class Matrix4 +{ + public: + typedef Component ComponentType; + typedef Vector4< ComponentType > VectorType; + typedef Matrix4< ComponentType, Storage > ThisType; + + typedef Storage StorageType; + typedef typename StorageType::Row Row; + typedef typename StorageType::Rows Rows; + typedef typename StorageType::ConstRow ConstRow; + typedef typename StorageType::ConstRows ConstRows; + typedef typename StorageType::Column Column; + typedef typename StorageType::Columns Columns; + typedef typename StorageType::ConstColumn ConstColumn; + typedef typename StorageType::ConstColumns ConstColumns; + + typedef typename StorageType::TransposeType TransposeStorageType; + typedef Matrix4< ComponentType, TransposeStorageType > TransposeType; + friend class Matrix4< ComponentType, TransposeStorageType >; + + private: + // The components of the matrix. + VectorType vectors[4]; + + /// Initialising constructor. + Matrix4(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept; + + template< typename _Component, class _StorageA > + struct VectorMultiplier + { + typedef _Component ComponentType; + typedef _StorageA StorageAType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Vector4< ComponentType > VectorType; + + static const VectorType Multiply( + const MatrixAType& lhs, + const VectorType& rhs + ) noexcept; + }; + + template< typename _Component, class _StorageA, class _StorageB > + struct MatrixMultiplier + { + typedef _Component ComponentType; + typedef _StorageA StorageAType; + typedef _StorageB StorageBType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Matrix4< ComponentType, StorageBType > MatrixBType; + + static const VectorType Multiply( + const MatrixAType& lhs, + const VectorType& rhs + ); + + static const MatrixAType Multiply( + const MatrixAType& lhs, + const MatrixBType& rhs + ) noexcept; + }; + + public: + /// Zero-initialising default constructor. + inline Matrix4() noexcept; + + /// Copy constructor. + inline Matrix4(const ThisType& other) noexcept; + Matrix4(const TransposeType& other) noexcept; + + /// Assignment operator + const ThisType& operator=(const ThisType& other) noexcept; + const ThisType& operator=(const TransposeType& other) noexcept; + + /// Construct from row vectors. + static const ThisType FromRows(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept; + + /// Construct from column vectors. + static const ThisType FromColumns(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept; + + /// Construct from components. + static const ThisType FromRowMajor(const ComponentType* components) noexcept; + static const ThisType FromColumnMajor(const ComponentType* components) noexcept; + + // Convert to raw values; keep the storage mode in mind. + inline Component* data() noexcept + { return &vectors[0][0]; } + inline const Component* data() const noexcept + { return &vectors[0][0]; } + + /// Get the i-th row + inline Row GetRow(int i) noexcept + { Rows rows(vectors); return rows[i]; } + /// Get the i-th row + inline ConstRow GetRow(int i) const noexcept + { ConstRows rows(vectors); return rows[i]; } + /// Set the i-th row + inline void SetRow(int i, const VectorType& vec) noexcept + { Rows rows(vectors); rows[i] = vec; } + /// Set all rows + void SetRows(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept; + + /// Get the i-th column + inline Column GetColumn(int i) noexcept + { Columns columns(vectors); return columns[i]; } + /// Get the i-th column + inline ConstColumn GetColumn(int i) const noexcept + { ConstColumns columns(vectors); return columns[i]; } + /// Set the i-th column + inline void SetColumn(int i, const VectorType& vec) noexcept + { Columns columns(vectors); columns[i] = vec; } + /// Set all columns + void SetColumns(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept; + + /// Returns the transpose of this matrix. + /// @return The transpose matrix. + inline const TransposeType& Transpose() const noexcept + { return reinterpret_cast(*this); } + + /// Inverts this matrix in place, if possible. + /// @return true, if the inversion succeeded. + bool Invert() noexcept; + + /// Inverts this matrix in place, if possible. + /// @return true, if the inversion succeeded. + float Determinant() const noexcept; + + /// Returns the negation of this matrix. + /// @return The negation of this matrix. + ThisType operator-() const noexcept; + + /// Adds another matrix to this in-place. + /// @param[in] other The matrix to add. + /// @return This matrix, post-operation. + const ThisType& operator+=(const ThisType& other) noexcept; + const ThisType& operator+=(const TransposeType& other) noexcept; + /// Subtracts another matrix from this in-place. + /// @param[in] other The matrix to subtract. + /// @return This matrix, post-operation. + const ThisType& operator-=(const ThisType& other) noexcept; + const ThisType& operator-=(const TransposeType& other) noexcept; + /// Scales this matrix in-place. + /// @param[in] other The value to scale this matrix's components by. + /// @return This matrix, post-operation. + const ThisType& operator*=(Component other) noexcept; + /// Scales this matrix in-place by the inverse of a value. + /// @param[in] other The value to divide this matrix's components by. + /// @return This matrix, post-operation. + const ThisType& operator/=(Component other) noexcept; + + inline const VectorType& operator[](size_t i) const noexcept { return vectors[i]; } + inline VectorType& operator[](size_t i) noexcept { return vectors[i]; } + + /// Returns the sum of this matrix and another. + /// @param[in] other The matrix to add this to. + /// @return The sum of the two matrices. + inline const ThisType operator+(const ThisType& other) const noexcept + { ThisType result(*this); result += other; return result; } + inline const ThisType operator+(const TransposeType& other) const noexcept + { ThisType result(*this); result += other; return result; } + /// Returns the result of subtracting another matrix from this matrix. + /// @param[in] other The matrix to subtract from this matrix. + /// @return The result of the subtraction. + inline const ThisType operator-(const ThisType& other) const noexcept + { ThisType result(*this); result -= other; return result; } + inline const ThisType operator-(const TransposeType& other) const noexcept + { ThisType result(*this); result -= other; return result; } + /// Returns the result of multiplying this matrix by a scalar. + /// @param[in] other The scalar value to multiply by. + /// @return The result of the scale. + inline const ThisType operator*(Component other) const noexcept + { ThisType result(*this); result *= other; return result; } + /// Returns the result of dividing this matrix by a scalar. + /// @param[in] other The scalar value to divide by. + /// @return The result of the scale. + inline const ThisType operator/(Component other) const noexcept + { ThisType result(*this); result *= other; return result; } + + /// Returns the result of multiplying this matrix by a vector. + /// @param[in] other The scalar value to multiply by. + /// @return The result of the scale. + const VectorType operator*(const VectorType& other) const noexcept + { return VectorMultiplier< Component, Storage >::Multiply(*this, other); } + + /// Returns the result of multiplying this matrix by another matrix. + /// @param[in] other The matrix value to multiply by. + /// @return The result of the multiplication. + template< class Storage2 > + const ThisType operator*(const Matrix4< Component, Storage2 >& other) const noexcept + { return MatrixMultiplier< Component, Storage, Storage2 >::Multiply(*this, other); } + + /// Multiplies this matrix by another matrix in place. + /// @return The result of the multiplication. + inline const ThisType& operator*=(const ThisType& other) noexcept + { *this = *this * other; return *this; } + inline const ThisType& operator*=(const TransposeType& other) noexcept + { *this = *this * other; return *this; } + + /// Equality operator. + /// @param[in] other The matrix to compare this against. + /// @return True if the two matrices are equal, false otherwise. + bool operator==(const ThisType& other) const noexcept; + bool operator==(const TransposeType& other) const noexcept; + /// Inequality operator. + /// @param[in] other The matrix to compare this against. + /// @return True if the two matrices are not equal, false otherwise. + bool operator!=(const ThisType& other) const noexcept; + bool operator!=(const TransposeType& other) const noexcept; + + /// Return the identity matrix. + /// @return The identity matrix. + inline static const ThisType& Identity() noexcept; + /// Return a diagonal matrix. + /// @return A diagonal matrix. + static ThisType Diag(Component a, Component b, Component c, Component d = 1) noexcept; + + /// Create an orthographic projection matrix + /// @param l The horizontal coordinate of the left clipping plane + /// @param r The horizontal coordinate of the right clipping plane + /// @param b The vertical coordinate of the bottom clipping plane + /// @param t The vertical coordinate of the top clipping plane + /// @param n The depth coordinate of the near clipping plane + /// @param f The depth coordinate of the far clipping plane + /// @return The specified orthographic projection matrix. + static ThisType ProjectOrtho(Component l, Component r, Component b, Component t, Component n, Component f) noexcept; + /// Create a perspective projection matrix + /// @param l The horizontal coordinate of the left clipping plane + /// @param r The horizontal coordinate of the right clipping plane + /// @param b The vertical coordinate of the bottom clipping plane + /// @param t The vertical coordinate of the top clipping plane + /// @param n The depth coordinate of the near clipping plane + /// @param f The depth coordinate of the far clipping plane + /// @return The specified perspective projection matrix. + static ThisType ProjectPerspective(Component l, Component r, Component b, Component t, Component n, Component f) noexcept; + /// Create a perspective projection matrix + /// @param d The distance to the z-plane + static ThisType Perspective(Component d) noexcept; + + /// Return a translation matrix. + /// @return A translation matrix. + static ThisType Translate (const Vector3< Component >& v) noexcept; + static ThisType Translate (Component x, Component y, Component z) noexcept; + static ThisType TranslateX (Component x) noexcept; + static ThisType TranslateY (Component y) noexcept; + static ThisType TranslateZ (Component z) noexcept; + + /// Return a scaling matrix. + /// @return A scaling matrix. + static ThisType Scale (Component x, Component y, Component z) noexcept; + static ThisType ScaleX (Component x) noexcept; + static ThisType ScaleY (Component y) noexcept; + static ThisType ScaleZ (Component z) noexcept; + + /// Return a rotation matrix. + /// @return A rotation matrix. + static ThisType Rotate (const Vector3< Component >& v, Component angle) noexcept; + static ThisType RotateX (Component angle) noexcept; + static ThisType RotateY (Component angle) noexcept; + static ThisType RotateZ (Component angle) noexcept; + + /// Return a skew/shearing matrix. + /// @return A skew matrix. + static ThisType Skew (Component angle_x, Component angle_y) noexcept; + static ThisType SkewX (Component angle) noexcept; + static ThisType SkewY (Component angle) noexcept; + + static ThisType Compose(const Vector3< Component >& translation, const Vector3< Component >& scale, + const Vector3< Component >& skew, const Vector4< Component >& perspective, const Vector4< Component >& quaternion) noexcept; + +#ifdef RMLUI_MATRIX4_USER_EXTRA + RMLUI_MATRIX4_USER_EXTRA +#endif +}; + +} // namespace Rml + +#include "Matrix4.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Matrix4.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Matrix4.inl new file mode 100644 index 000000000..010301e5b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Matrix4.inl @@ -0,0 +1,855 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { + +// Initialising constructor. +template< typename Component, class Storage > +Matrix4< Component, Storage >::Matrix4( + const typename Matrix4< Component, Storage >::VectorType& vec0, + const typename Matrix4< Component, Storage >::VectorType& vec1, + const typename Matrix4< Component, Storage >::VectorType& vec2, + const typename Matrix4< Component, Storage >::VectorType& vec3 +) noexcept +{ + vectors[0] = vec0; + vectors[1] = vec1; + vectors[2] = vec2; + vectors[3] = vec3; +} + +// Default constructor. +template< typename Component, class Storage > +Matrix4< Component, Storage >::Matrix4() noexcept + : vectors{ VectorType{0}, VectorType{0}, VectorType{0}, VectorType{0} } +{ +} + +// Initialising, copy constructor. +template< typename Component, class Storage > +Matrix4< Component, Storage >::Matrix4(const typename Matrix4< Component, Storage >::ThisType& other) noexcept +{ + for (int i = 0; i < 4; ++i) + { + vectors[i] = other.vectors[i]; + } +} + +template< typename Component, class Storage > +Matrix4< Component, Storage >::Matrix4(const typename Matrix4< Component, Storage >::TransposeType& other) noexcept +{ + Rows rows(vectors); + typename Matrix4< Component, Storage >::TransposeType::ConstRows other_rows(other.vectors); + for (int i = 0; i < 4; ++i) + { + rows[i] = other_rows[i]; + } +} + +// Assignment operator +template< typename Component, class Storage > +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator=(const typename Matrix4< Component, Storage >::ThisType& other) noexcept +{ + for (int i = 0; i < 4; ++i) + { + vectors[i] = other.vectors[i]; + } + return *this; +} + +template< typename Component, class Storage > +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator=(const typename Matrix4< Component, Storage >::TransposeType& other) noexcept +{ + Rows rows(vectors); + typename Matrix4< Component, Storage >::TransposeType::Rows other_rows(other.vectors); + for (int i = 0; i < 4; ++i) + { + rows[i] = other_rows[i]; + } + return *this; +} + +// Construct from row vectors. +template< typename Component, class Storage > +const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromRows( + const typename Matrix4< Component, Storage >::VectorType& vec0, + const typename Matrix4< Component, Storage >::VectorType& vec1, + const typename Matrix4< Component, Storage >::VectorType& vec2, + const typename Matrix4< Component, Storage >::VectorType& vec3 +) noexcept +{ + typename Matrix4< Component, Storage >::ThisType result; + result.SetRows(vec0, vec1, vec2, vec3); + return result; +} + +// Construct from column vectors. +template< typename Component, class Storage > +const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromColumns( + const typename Matrix4< Component, Storage >::VectorType& vec0, + const typename Matrix4< Component, Storage >::VectorType& vec1, + const typename Matrix4< Component, Storage >::VectorType& vec2, + const typename Matrix4< Component, Storage >::VectorType& vec3 +) noexcept +{ + typename Matrix4< Component, Storage >::ThisType result; + result.SetColumns(vec0, vec1, vec2, vec3); + return result; +} + +// Construct from components +template< typename Component, class Storage > +const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromRowMajor(const Component* components) noexcept +{ + Matrix4< Component, Storage >::ThisType result; + Matrix4< Component, Storage >::Rows rows(result.vectors); + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + rows[i][j] = components[i*4 + j]; + } + } + return result; +} +template< typename Component, class Storage > +const typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::FromColumnMajor(const Component* components) noexcept +{ + Matrix4< Component, Storage >::ThisType result; + Matrix4< Component, Storage >::Columns columns(result.vectors); + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + columns[i][j] = components[i*4 + j]; + } + } + return result; +} + +// Set all rows +template< typename Component, class Storage > +void Matrix4< Component, Storage >::SetRows(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept +{ + Rows rows(vectors); + rows[0] = vec0; + rows[1] = vec1; + rows[2] = vec2; + rows[3] = vec3; +} + +// Set all columns +template< typename Component, class Storage > +void Matrix4< Component, Storage >::SetColumns(const VectorType& vec0, const VectorType& vec1, const VectorType& vec2, const VectorType& vec3) noexcept +{ + Columns columns(vectors); + columns[0] = vec0; + columns[1] = vec1; + columns[2] = vec2; + columns[3] = vec3; +} + +// Inverts this matrix in place. +// This is from the MESA implementation of the GLU library. +template< typename Component, class Storage > +bool Matrix4< Component, Storage >::Invert() noexcept +{ + Matrix4< Component, Storage >::ThisType result; + Component *dst = result.data(); + const Component *src = data(); + + dst[0] = src[5] * src[10] * src[15] - + src[5] * src[11] * src[14] - + src[9] * src[6] * src[15] + + src[9] * src[7] * src[14] + + src[13] * src[6] * src[11] - + src[13] * src[7] * src[10]; + + dst[4] = -src[4] * src[10] * src[15] + + src[4] * src[11] * src[14] + + src[8] * src[6] * src[15] - + src[8] * src[7] * src[14] - + src[12] * src[6] * src[11] + + src[12] * src[7] * src[10]; + + dst[8] = src[4] * src[9] * src[15] - + src[4] * src[11] * src[13] - + src[8] * src[5] * src[15] + + src[8] * src[7] * src[13] + + src[12] * src[5] * src[11] - + src[12] * src[7] * src[9]; + + dst[12] = -src[4] * src[9] * src[14] + + src[4] * src[10] * src[13] + + src[8] * src[5] * src[14] - + src[8] * src[6] * src[13] - + src[12] * src[5] * src[10] + + src[12] * src[6] * src[9]; + + dst[1] = -src[1] * src[10] * src[15] + + src[1] * src[11] * src[14] + + src[9] * src[2] * src[15] - + src[9] * src[3] * src[14] - + src[13] * src[2] * src[11] + + src[13] * src[3] * src[10]; + + dst[5] = src[0] * src[10] * src[15] - + src[0] * src[11] * src[14] - + src[8] * src[2] * src[15] + + src[8] * src[3] * src[14] + + src[12] * src[2] * src[11] - + src[12] * src[3] * src[10]; + + dst[9] = -src[0] * src[9] * src[15] + + src[0] * src[11] * src[13] + + src[8] * src[1] * src[15] - + src[8] * src[3] * src[13] - + src[12] * src[1] * src[11] + + src[12] * src[3] * src[9]; + + dst[13] = src[0] * src[9] * src[14] - + src[0] * src[10] * src[13] - + src[8] * src[1] * src[14] + + src[8] * src[2] * src[13] + + src[12] * src[1] * src[10] - + src[12] * src[2] * src[9]; + + dst[2] = src[1] * src[6] * src[15] - + src[1] * src[7] * src[14] - + src[5] * src[2] * src[15] + + src[5] * src[3] * src[14] + + src[13] * src[2] * src[7] - + src[13] * src[3] * src[6]; + + dst[6] = -src[0] * src[6] * src[15] + + src[0] * src[7] * src[14] + + src[4] * src[2] * src[15] - + src[4] * src[3] * src[14] - + src[12] * src[2] * src[7] + + src[12] * src[3] * src[6]; + + dst[10] = src[0] * src[5] * src[15] - + src[0] * src[7] * src[13] - + src[4] * src[1] * src[15] + + src[4] * src[3] * src[13] + + src[12] * src[1] * src[7] - + src[12] * src[3] * src[5]; + + dst[14] = -src[0] * src[5] * src[14] + + src[0] * src[6] * src[13] + + src[4] * src[1] * src[14] - + src[4] * src[2] * src[13] - + src[12] * src[1] * src[6] + + src[12] * src[2] * src[5]; + + dst[3] = -src[1] * src[6] * src[11] + + src[1] * src[7] * src[10] + + src[5] * src[2] * src[11] - + src[5] * src[3] * src[10] - + src[9] * src[2] * src[7] + + src[9] * src[3] * src[6]; + + dst[7] = src[0] * src[6] * src[11] - + src[0] * src[7] * src[10] - + src[4] * src[2] * src[11] + + src[4] * src[3] * src[10] + + src[8] * src[2] * src[7] - + src[8] * src[3] * src[6]; + + dst[11] = -src[0] * src[5] * src[11] + + src[0] * src[7] * src[9] + + src[4] * src[1] * src[11] - + src[4] * src[3] * src[9] - + src[8] * src[1] * src[7] + + src[8] * src[3] * src[5]; + + dst[15] = src[0] * src[5] * src[10] - + src[0] * src[6] * src[9] - + src[4] * src[1] * src[10] + + src[4] * src[2] * src[9] + + src[8] * src[1] * src[6] - + src[8] * src[2] * src[5]; + + float det = src[0] * dst[0] + \ + src[1] * dst[4] + \ + src[2] * dst[8] + \ + src[3] * dst[12]; + + if (det == 0) + { + return false; + } + + *this = result * (1 / det); + return true; +} + + + + +template +inline float Matrix4::Determinant() const noexcept +{ + const Component *src = data(); + float diag[4]; // Diagonal elements of the matrix inverse (see Invert) + + diag[0] = src[5] * src[10] * src[15] - + src[5] * src[11] * src[14] - + src[9] * src[6] * src[15] + + src[9] * src[7] * src[14] + + src[13] * src[6] * src[11] - + src[13] * src[7] * src[10]; + + diag[1] = -src[4] * src[10] * src[15] + + src[4] * src[11] * src[14] + + src[8] * src[6] * src[15] - + src[8] * src[7] * src[14] - + src[12] * src[6] * src[11] + + src[12] * src[7] * src[10]; + + diag[2] = src[4] * src[9] * src[15] - + src[4] * src[11] * src[13] - + src[8] * src[5] * src[15] + + src[8] * src[7] * src[13] + + src[12] * src[5] * src[11] - + src[12] * src[7] * src[9]; + + diag[3] = -src[4] * src[9] * src[14] + + src[4] * src[10] * src[13] + + src[8] * src[5] * src[14] - + src[8] * src[6] * src[13] - + src[12] * src[5] * src[10] + + src[12] * src[6] * src[9]; + + float det = src[0] * diag[0] + \ + src[1] * diag[1] + \ + src[2] * diag[2] + \ + src[3] * diag[3]; + + return det; +} + +// Returns the negation of this matrix. +template< typename Component, class Storage > +typename Matrix4< Component, Storage >::ThisType Matrix4< Component, Storage >::operator-() const noexcept +{ + return typename Matrix4< Component, Storage >::ThisType( + -vectors[0], + -vectors[1], + -vectors[2], + -vectors[3] + ); +} + +// Adds another matrix to this in-place. +template< typename Component, class Storage> +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator+=(const typename Matrix4< Component, Storage >::ThisType& other) noexcept +{ + for (int i = 0; i < 4; ++i) + { + vectors[i] += other.vectors[i]; + } + return *this; +} +template< typename Component, class Storage> +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator+=(const typename Matrix4< Component, Storage >::TransposeType& other) noexcept +{ + Rows rows(vectors); + typename Matrix4< Component, Storage >::TransposeType::ConstRows other_rows(other); + for (int i = 0; i < 4; ++i) + { + rows[i] += other_rows[i]; + } + return *this; +} + +// Subtracts another matrix from this in-place. +template< typename Component, class Storage> +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator-=(const typename Matrix4< Component, Storage >::ThisType& other) noexcept +{ + for (int i = 0; i < 4; ++i) + { + vectors[i] -= other.vectors[i]; + } + return *this; +} +template< typename Component, class Storage> +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator-=(const typename Matrix4< Component, Storage >::TransposeType& other) noexcept +{ + Rows rows(vectors); + typename Matrix4< Component, Storage >::TransposeType::ConstRows other_rows(other); + for (int i = 0; i < 4; ++i) + { + rows[i] -= other_rows[i]; + } + return *this; +} + +// Scales this matrix in-place. +template< typename Component, class Storage> +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator*=(Component s) noexcept +{ + for (int i = 0; i < 4; ++i) + { + vectors[i] *= s; + } + return *this; +} + +// Scales this matrix in-place by the inverse of a value. +template< typename Component, class Storage> +const typename Matrix4< Component, Storage >::ThisType& Matrix4< Component, Storage >::operator/=(Component s) noexcept +{ + for (int i = 0; i < 4; ++i) + { + vectors[i] /= s; + } + return *this; +} + +// Equality operator. +template< typename Component, class Storage> +bool Matrix4< Component, Storage >::operator==(const typename Matrix4< Component, Storage >::ThisType& other) const noexcept +{ + typename Matrix4< Component, Storage >::ConstRows rows(vectors); + typename Matrix4< Component, Storage >::ConstRows other_rows(other.vectors); + return vectors[0] == other.vectors[0] + && vectors[1] == other.vectors[1] + && vectors[2] == other.vectors[2] + && vectors[3] == other.vectors[3]; +} +template< typename Component, class Storage> +bool Matrix4< Component, Storage >::operator==(const typename Matrix4< Component, Storage >::TransposeType& other) const noexcept +{ + typename Matrix4< Component, Storage >::ConstRows rows(vectors); + typename Matrix4< Component, Storage >::ConstRows other_rows(other.vectors); + return rows[0] == other_rows[0] + && rows[1] == other_rows[1] + && rows[2] == other_rows[2] + && rows[3] == other_rows[3]; +} + +// Inequality operator. +template< typename Component, class Storage> +bool Matrix4< Component, Storage >::operator!=(const typename Matrix4< Component, Storage >::ThisType& other) const noexcept +{ + return vectors[0] != other.vectors[0] + || vectors[1] != other.vectors[1] + || vectors[2] != other.vectors[2] + || vectors[3] != other.vectors[3]; +} +template< typename Component, class Storage> +bool Matrix4< Component, Storage >::operator!=(const typename Matrix4< Component, Storage >::TransposeType& other) const noexcept +{ + typename Matrix4< Component, Storage >::ConstRows rows(vectors); + typename Matrix4< Component, Storage >::ConstRows other_rows(other.vectors); + return rows[0] != other_rows[0] + || rows[1] != other_rows[1] + || rows[2] != other_rows[2] + || rows[3] != other_rows[3]; +} + +// Return the identity matrix. +template< typename Component, class Storage> +const Matrix4< Component, Storage >& Matrix4< Component, Storage >::Identity() noexcept +{ + static Matrix4< Component, Storage > identity(Diag(1, 1, 1, 1)); + return identity; +} + +// Return a diagonal matrix. +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Diag(Component a, Component b, Component c, Component d) noexcept +{ + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(a, 0, 0, 0), + Matrix4< Component, Storage >::VectorType(0, b, 0, 0), + Matrix4< Component, Storage >::VectorType(0, 0, c, 0), + Matrix4< Component, Storage >::VectorType(0, 0, 0, d) + ); +} + +// Create an orthographic projection matrix +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::ProjectOrtho(Component l, Component r, Component b, Component t, Component n, Component f) noexcept +{ + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(2 / (r - l), 0, 0, -(r + l)/(r - l)), + Matrix4< Component, Storage >::VectorType(0, 2 / (t - b), 0, -(t + b)/(t - b)), + Matrix4< Component, Storage >::VectorType(0, 0, 2 / (f - n), -(f + n)/(f - n)), + Matrix4< Component, Storage >::VectorType(0, 0, 0, 1) + ); +} + +// Create a perspective projection matrix +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::ProjectPerspective(Component l, Component r, Component b, Component t, Component n, Component f) noexcept +{ + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(2 * n / (r - l), 0, (r + l)/(r - l), 0), + Matrix4< Component, Storage >::VectorType(0, 2 * n / (t - b), (t + b)/(t - b), 0), + Matrix4< Component, Storage >::VectorType(0, 0, -(f + n)/(f - n), -(2 * f * n)/(f - n)), + Matrix4< Component, Storage >::VectorType(0, 0, -1, 0) + ); +} + +// Create a perspective projection matrix +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Perspective(Component d) noexcept +{ + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(1, 0, 0, 0), + Matrix4< Component, Storage >::VectorType(0, 1, 0, 0), + Matrix4< Component, Storage >::VectorType(0, 0, 1, 0), + Matrix4< Component, Storage >::VectorType(0, 0, -static_cast(1)/d, 1) + ); +} + +// Return a translation matrix. +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Translate(const Vector3< Component >& v) noexcept +{ + return Translate(v.x, v.y, v.z); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Translate(Component x, Component y, Component z) noexcept +{ + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(1, 0, 0, x), + Matrix4< Component, Storage >::VectorType(0, 1, 0, y), + Matrix4< Component, Storage >::VectorType(0, 0, 1, z), + Matrix4< Component, Storage >::VectorType(0, 0, 0, 1) + ); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::TranslateX(Component x) noexcept +{ + return Translate(Vector3< Component >(x, 0, 0)); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::TranslateY(Component y) noexcept +{ + return Translate(Vector3< Component >(0, y, 0)); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::TranslateZ(Component z) noexcept +{ + return Translate(Vector3< Component >(0, 0, z)); +} + +// Return a scaling matrix. +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Scale(Component x, Component y, Component z) noexcept +{ + return Matrix4::Diag(x, y, z, 1); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::ScaleX(Component x) noexcept +{ + return Scale(x, 1, 1); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::ScaleY(Component y) noexcept +{ + return Scale(1, y, 1); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::ScaleZ(Component z) noexcept +{ + return Scale(1, 1, z); +} + +// Return a rotation matrix. +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Rotate(const Vector3< Component >& v, Component angle) noexcept +{ + Vector3< Component > n = v.Normalise(); + Component Sin = Math::Sin(angle); + Component Cos = Math::Cos(angle); + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType( + n.x * n.x * (1 - Cos) + Cos, + n.x * n.y * (1 - Cos) - n.z * Sin, + n.x * n.z * (1 - Cos) + n.y * Sin, + 0 + ), + Matrix4< Component, Storage >::VectorType( + n.y * n.x * (1 - Cos) + n.z * Sin, + n.y * n.y * (1 - Cos) + Cos, + n.y * n.z * (1 - Cos) - n.x * Sin, + 0 + ), + Matrix4< Component, Storage >::VectorType( + n.z * n.x * (1 - Cos) - n.y * Sin, + n.z * n.y * (1 - Cos) + n.x * Sin, + n.z * n.z * (1 - Cos) + Cos, + 0 + ), + Matrix4< Component, Storage >::VectorType(0, 0, 0, 1) + ); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::RotateX(Component angle) noexcept +{ + Component Sin = Math::Sin(angle); + Component Cos = Math::Cos(angle); + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(1, 0, 0, 0), + Matrix4< Component, Storage >::VectorType(0, Cos, -Sin, 0), + Matrix4< Component, Storage >::VectorType(0, Sin, Cos, 0), + Matrix4< Component, Storage >::VectorType(0, 0, 0, 1) + ); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::RotateY(Component angle) noexcept +{ + Component Sin = Math::Sin(angle); + Component Cos = Math::Cos(angle); + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType( Cos, 0, Sin, 0), + Matrix4< Component, Storage >::VectorType( 0, 1, 0, 0), + Matrix4< Component, Storage >::VectorType(-Sin, 0, Cos, 0), + Matrix4< Component, Storage >::VectorType( 0, 0, 0, 1) + ); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::RotateZ(Component angle) noexcept +{ + Component Sin = Math::Sin(angle); + Component Cos = Math::Cos(angle); + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(Cos, -Sin, 0, 0), + Matrix4< Component, Storage >::VectorType(Sin, Cos, 0, 0), + Matrix4< Component, Storage >::VectorType( 0, 0, 1, 0), + Matrix4< Component, Storage >::VectorType( 0, 0, 0, 1) + ); +} +// Return a skew/shearing matrix. +// @return A skew matrix. +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::Skew(Component angle_x, Component angle_y) noexcept +{ + Component SkewX = Math::Tan(angle_x); + Component SkewY = Math::Tan(angle_y); + return Matrix4< Component, Storage >::FromRows( + Matrix4< Component, Storage >::VectorType(1, SkewX, 0, 0), + Matrix4< Component, Storage >::VectorType(SkewY, 1, 0, 0), + Matrix4< Component, Storage >::VectorType( 0, 0, 1, 0), + Matrix4< Component, Storage >::VectorType( 0, 0, 0, 1) + ); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::SkewX(Component angle) noexcept +{ + return Skew(angle, 0); +} + +template< typename Component, class Storage> +Matrix4< Component, Storage > Matrix4< Component, Storage >::SkewY(Component angle) noexcept +{ + return Skew(0, angle); +} + +template +Matrix4< Component, Storage > Matrix4::Compose(const Vector3& translation, + const Vector3& scale, const Vector3& skew, const Vector4& perspective, + const Vector4& quaternion) noexcept +{ + ThisType matrix = ThisType::Identity(); + + for (int i = 0; i < 4; i++) + matrix[i][3] = perspective[i]; + + for (int i = 0; i < 4; i++) + for (int j = 0; j < 3; j++) + matrix[3][i] += translation[j] * matrix[j][i]; + + float x = quaternion.x; + float y = quaternion.y; + float z = quaternion.z; + float w = quaternion.w; + + ThisType rotation = Matrix4< Component, Storage >::FromRows( + VectorType(1.f - 2.f * (y*y + z * z), 2.f*(x*y - z * w), 2.f*(x*z + y * w), 0.f), + VectorType(2.f * (x * y + z * w), 1.f - 2.f * (x * x + z * z), 2.f * (y * z - x * w), 0.f), + VectorType(2.f * (x * z - y * w), 2.f * (y * z + x * w), 1.f - 2.f * (x * x + y * y), 0.f), + VectorType(0, 0, 0, 1) + ); + + matrix *= rotation; + + ThisType temp = ThisType::Identity(); + if(skew[2]) + { + temp[2][1] = skew[2]; + matrix *= temp; + } + if (skew[1]) + { + temp[2][1] = 0; + temp[2][0] = skew[1]; + matrix *= temp; + } + if (skew[0]) + { + temp[2][0] = 0; + temp[1][0] = skew[0]; + matrix *= temp; + } + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + matrix[i][j] *= scale[i]; + + return matrix; +} + +template< typename Component, class Storage > +template< typename _Component > +struct Matrix4< Component, Storage >::VectorMultiplier< _Component, RowMajorStorage< _Component > > +{ + typedef _Component ComponentType; + typedef RowMajorStorage< ComponentType > StorageAType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Vector4< ComponentType > VectorType; + + static const VectorType Multiply(const MatrixAType& lhs, const VectorType& rhs) noexcept + { + typename MatrixAType::ConstRows rows(lhs.vectors); + return VectorType( + rhs.DotProduct(rows[0]), + rhs.DotProduct(rows[1]), + rhs.DotProduct(rows[2]), + rhs.DotProduct(rows[3]) + ); + } +}; + +template< typename Component, class Storage > +template< typename _Component > +struct Matrix4< Component, Storage >::VectorMultiplier< _Component, ColumnMajorStorage< _Component > > +{ + typedef _Component ComponentType; + typedef ColumnMajorStorage< ComponentType > StorageAType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Vector4< ComponentType > VectorType; + + static const VectorType Multiply(const MatrixAType& lhs, const VectorType& rhs) noexcept + { + typename MatrixAType::ConstRows rows(lhs.vectors); + return VectorType( + rhs.DotProduct(rows[0]), + rhs.DotProduct(rows[1]), + rhs.DotProduct(rows[2]), + rhs.DotProduct(rows[3]) + ); + } +}; + +template< typename Component, class Storage > +template< typename _Component, class _StorageB > +struct Matrix4< Component, Storage >::MatrixMultiplier< _Component, RowMajorStorage< _Component >, _StorageB > +{ + typedef _Component ComponentType; + typedef RowMajorStorage< ComponentType > StorageAType; + typedef _StorageB StorageBType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Matrix4< ComponentType, StorageBType > MatrixBType; + + static const MatrixAType Multiply(const MatrixAType& lhs, const MatrixBType& rhs) noexcept + { + typename MatrixAType::ThisType result; + typename MatrixAType::Rows result_rows(result.vectors); + typename MatrixAType::ConstRows lhs_rows(lhs.vectors); + typename MatrixBType::ConstColumns rhs_columns(rhs.vectors); + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + result_rows[i][j] = lhs_rows[i].DotProduct(rhs_columns[j]); + } + } + return result; + } +}; + +template< typename Component, class Storage > +template< typename _Component > +struct Matrix4< Component, Storage >::MatrixMultiplier< _Component, ColumnMajorStorage< _Component >, ColumnMajorStorage< _Component > > +{ + typedef _Component ComponentType; + typedef ColumnMajorStorage< ComponentType > StorageAType; + typedef ColumnMajorStorage< ComponentType > StorageBType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Matrix4< ComponentType, StorageBType > MatrixBType; + + static const MatrixAType Multiply(const MatrixAType& lhs, const MatrixBType& rhs) noexcept + { + typename MatrixAType::ThisType result; + typename MatrixAType::Rows result_rows(result.vectors); + typename MatrixAType::ConstRows lhs_rows(lhs.vectors); + typename MatrixBType::ConstColumns rhs_columns(rhs.vectors); + for (int i = 0; i < 4; ++i) + { + for (int j = 0; j < 4; ++j) + { + result_rows[i][j] = rhs_columns[j].DotProduct(lhs_rows[i]); + } + } + return result; + } +}; + +template< typename Component, class Storage > +template< typename _Component > +struct Matrix4< Component, Storage >::MatrixMultiplier< _Component, ColumnMajorStorage< _Component >, RowMajorStorage< _Component > > +{ + typedef _Component ComponentType; + typedef ColumnMajorStorage< ComponentType > StorageAType; + typedef RowMajorStorage< ComponentType > StorageBType; + typedef Matrix4< ComponentType, StorageAType > MatrixAType; + typedef Matrix4< ComponentType, StorageBType > MatrixBType; + + static const MatrixAType Multiply(const MatrixAType& lhs, const MatrixBType& rhs) noexcept + { + return lhs * MatrixAType(rhs); + } +}; + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ObserverPtr.h b/thirdparty/RmlUi/Include/RmlUi/Core/ObserverPtr.h new file mode 100644 index 000000000..54c86312a --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ObserverPtr.h @@ -0,0 +1,188 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUIOBSERVERPTR_H +#define RMLUIOBSERVERPTR_H + +#include +#include +#include "Header.h" + +namespace Rml { + +struct RMLUICORE_API ObserverPtrBlock { + int num_observers; + void* pointed_to_object; +}; +RMLUICORE_API ObserverPtrBlock* AllocateObserverPtrBlock(); +RMLUICORE_API void DeallocateObserverPtrBlockIfEmpty(ObserverPtrBlock* block); + +template +class EnableObserverPtr; + + +/** + Observer pointer. + + Holds a weak reference to an object owned by someone else. Can tell whether or not the pointed to object has been destroyed. + + Usage: Given a class T, derive from EnableObserverPtr. Then, we can use the observer pointer as follows: + + auto object = MakeUnique(); + ObserverPtr observer_ptr = object->GetObserverPtr(); + // ... + if(obserer_ptr) { + // Will only enter if object is still alive. + observer_ptr->do_a_thing(); + } + + Note: Not thread safe. + */ + +template +class RMLUICORE_API ObserverPtr { +public: + ObserverPtr() noexcept : block(nullptr) {} + ObserverPtr(std::nullptr_t) noexcept : block(nullptr) {} + ~ObserverPtr() noexcept { + reset(); + } + + // Copy + ObserverPtr(const ObserverPtr& other) noexcept : block(other.block) { + if (block) + block->num_observers += 1; + } + ObserverPtr& operator=(const ObserverPtr& other) noexcept { + reset(); + block = other.block; + if (block) + block->num_observers += 1; + return *this; + } + + // Move + ObserverPtr(ObserverPtr&& other) noexcept : block(std::exchange(other.block, nullptr)) {} + ObserverPtr& operator=(ObserverPtr&& other) noexcept { + reset(); + block = std::exchange(other.block, nullptr); + return *this; + } + + // Returns true if we can dereference the pointer. + explicit operator bool() const noexcept { return block && block->pointed_to_object; } + + // Retrieve the pointer to the observed object if we have one and it's still alive. + T* get() const noexcept { + return block ? static_cast(block->pointed_to_object) : nullptr; + } + // Dereference the pointed to object. + T* operator->() const noexcept { return static_cast(block->pointed_to_object); } + + // Reset the pointer so that it does not point to anything. + // When the pointed to object and all observer pointers to it have been destroyed, it will deallocate the block. + void reset() noexcept + { + if (block) + { + block->num_observers -= 1; + DeallocateObserverPtrBlockIfEmpty(block); + block = nullptr; + } + } + +private: + + friend class EnableObserverPtr; + + explicit ObserverPtr(ObserverPtrBlock* block) noexcept : block(block) + { + if (block) + block->num_observers += 1; + } + + ObserverPtrBlock* block; +}; + + + + +template +class RMLUICORE_API EnableObserverPtr { +public: + + ObserverPtr GetObserverPtr() const noexcept { return ObserverPtr(block); } + +protected: + + EnableObserverPtr() + { + static_assert(std::is_base_of, T>::value, "T must derive from EnableObserverPtr."); + InitializeBlock(); + } + + ~EnableObserverPtr() noexcept + { + block->pointed_to_object = nullptr; + DeallocateObserverPtrBlockIfEmpty(block); + } + + EnableObserverPtr(const EnableObserverPtr&) { + // We do not copy or modify the block, it should always point to the same object. + InitializeBlock(); + } + EnableObserverPtr& operator=(const EnableObserverPtr&) noexcept { + // Assignment should not do anything, the block must point to the initially constructed object. + return *this; + } + + EnableObserverPtr(EnableObserverPtr&&) { + // We do not move or modify the block, it should always point to the same object. + InitializeBlock(); + } + EnableObserverPtr& operator=(EnableObserverPtr&&) noexcept { + // Assignment should not do anything, the block must point to the initially constructed object. + return *this; + } + +private: + + inline void InitializeBlock() + { + block = AllocateObserverPtrBlock(); + block->num_observers = 0; + block->pointed_to_object = static_cast(static_cast(this)); + } + + ObserverPtrBlock* block; +}; + + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Platform.h b/thirdparty/RmlUi/Include/RmlUi/Core/Platform.h new file mode 100644 index 000000000..c889ea197 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Platform.h @@ -0,0 +1,129 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PLATFORM_H +#define RMLUI_CORE_PLATFORM_H + +#if defined __WIN32__ || defined _WIN32 + #define RMLUI_PLATFORM_WIN32 + #define RMLUI_PLATFORM_NAME "win32" +#elif defined __APPLE_CC__ + #define RMLUI_PLATFORM_UNIX + #define RMLUI_PLATFORM_MACOSX + #define RMLUI_PLATFORM_NAME "macosx" +#else + #define RMLUI_PLATFORM_UNIX + #define RMLUI_PLATFORM_LINUX + #define RMLUI_PLATFORM_NAME "linux" +#endif + +#if !defined NDEBUG && !defined RMLUI_DEBUG + #define RMLUI_DEBUG +#endif + +#if defined __LP64__ || defined _M_X64 || defined _WIN64 || defined __MINGW64__ || defined _LP64 + #define RMLUI_ARCH_64 +#else + #define RMLUI_ARCH_32 +#endif + + +#if defined(RMLUI_PLATFORM_WIN32) && !defined(__MINGW32__) + // declaration of 'identifier' hides class member + #pragma warning(disable : 4458) + + // needs to have dll-interface to be used by clients + #pragma warning(disable : 4251) + + // was declared deprecated + #pragma warning(disable : 4996) +#endif + +// Wraps unused variables in methods or functions to avoid compiler warnings. This should +// be wrapped around the name of all parameters that are wrapped with RMLUI_UNUSED_PARAMETER +// to cover warnings generated by non-llvm/gcc style compilers that can't be covered with +// RMLUI_UNUSED_PARAMETER +#if defined __llvm__ +//# define RMLUI_UNUSED(x) UNUSED_ ## x __unused +# define RMLUI_UNUSED(x) +#elif defined __GNUC__ +//# define RMLUI_UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) +# define RMLUI_UNUSED(x) +#else +# define RMLUI_UNUSED(x) (void)(UNUSED_ ## x) +#endif + +// Wraps unused parameter names in method or function declarations. When used, the first lines +// of the function should contain a matching RMLUI_UNUSED call with the name of the function +// as well to cover compilers with no-op RMLUI_UNUSED_PARAMETER macros. +#if defined __llvm__ +# define RMLUI_UNUSED_PARAMETER(x) UNUSED_ ## x __attribute__((unused)) +#elif defined __GNUC__ +# define RMLUI_UNUSED_PARAMETER(x) UNUSED_ ## x __attribute__((__unused__)) +#else +# define RMLUI_UNUSED_PARAMETER(x) UNUSED_ ## x +#endif + +// RMLUI_UNUSED_ASSERT_PARAMETERS wraps method parameters which are not used in the method other than +// by a RMLUI_ASSERT check. This safely deals with debug versus release mode configurations +// and will warn if the parameter starts being used when compiled with GCC +#ifdef RMLUI_DEBUG + // In this case, the parameter is used by a RMLUI_ASSERT test, so we just pass through as is +# define RMLUI_UNUSED_ASSERT_PARAMETER(x) x +# define RMLUI_UNUSED_ASSERT(x) +#else + // If not in DEBUG builds, this parameter is unused, mark it as such +# if defined __llvm__ +# define RMLUI_UNUSED_ASSERT_PARAMETER(x) UNUSED_ ## x __attribute__((unused)) +# define RMLUI_UNUSED_ASSERT(x) +# elif defined __GNUC__ +# define RMLUI_UNUSED_ASSERT_PARAMETER(x) UNUSED_ ## x __attribute__((__unused__)) +# define RMLUI_UNUSED_ASSERT(x) +# else +# define RMLUI_UNUSED_ASSERT_PARAMETER(x) UNUSED_ ## x +# define RMLUI_UNUSED_ASSERT(x) (void)(UNUSED_ ## x) +# endif +#endif + +// Wraps functions which are not referenced or exported to avoid compiler warnings +#if defined __llvm__ +# define RMLUI_UNUSED_FUNCTION(x) __attribute__((unused)) UNUSED_ ## x +#elif defined __GNUC__ +# define RMLUI_UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x +#else +# define RMLUI_UNUSED_FUNCTION(x) UNUSED_ ## x +#endif + +// Squelchs warnings for unused enums in switch statements, this should only be used for special values +// that are known to NEVER be used. +#define RMLUI_UNUSED_SWITCH_ENUM(x) \ + case x: \ + RMLUI_ERRORMSG("Switch case for unhandled ENUM has been hit! This shouldn't happen! ENUM Name: " # x); \ + break; + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Plugin.h b/thirdparty/RmlUi/Include/RmlUi/Core/Plugin.h new file mode 100644 index 000000000..ccbc4cdbd --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Plugin.h @@ -0,0 +1,91 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PLUGIN_H +#define RMLUI_CORE_PLUGIN_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +class Element; +class ElementDocument; +class Context; + +/** + Generic Interface for plugins to RmlUi. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API Plugin +{ +public: + virtual ~Plugin(); + + enum EventClasses + { + EVT_BASIC = (1 << 0), // Initialise, Shutdown, ContextCreate, ContextDestroy + EVT_DOCUMENT = (1 << 1), // DocumentOpen, DocumentLoad, DocumentUnload + EVT_ELEMENT = (1 << 2), // ElementCreate, ElementDestroy + + EVT_ALL = EVT_BASIC | EVT_DOCUMENT | EVT_ELEMENT + }; + /// Called when the plugin is registered to determine + /// which of the above event types the plugin is interested in + virtual int GetEventClasses(); + + /// Called when RmlUi is initialised, or immediately when the plugin registers itself if + /// RmlUi has already been initialised. + virtual void OnInitialise(); + /// Called when RmlUi shuts down. + virtual void OnShutdown(); + + /// Called when a new context is created. + virtual void OnContextCreate(Context* context); + /// Called when a context is destroyed. + virtual void OnContextDestroy(Context* context); + + /// Called when a document load request occurs, before the document's file is opened. + virtual void OnDocumentOpen(Context* context, const String& document_path); + /// Called when a document is successfully loaded from file or instanced, initialised and added + /// to its context. This is called before the document's 'load' event. + virtual void OnDocumentLoad(ElementDocument* document); + /// Called when a document is unloaded from its context. This is called after the document's + /// 'unload' event. + virtual void OnDocumentUnload(ElementDocument* document); + + /// Called when a new element is created. + virtual void OnElementCreate(Element* element); + /// Called when an element is destroyed. + virtual void OnElementDestroy(Element* element); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Profiling.h b/thirdparty/RmlUi/Include/RmlUi/Core/Profiling.h new file mode 100644 index 000000000..6d46382b3 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Profiling.h @@ -0,0 +1,83 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROFILING_H +#define RMLUI_CORE_PROFILING_H + + +#ifdef RMLUI_ENABLE_PROFILING + +#define TRACY_ENABLE +#include + +#define RMLUI_ZoneNamed(varname, active) ZoneNamed(varname, active) +#define RMLUI_ZoneNamedN(varname, name, active) ZoneNamedN(varname, name, active) +#define RMLUI_ZoneNamedC(varname, color, active) ZoneNamedC(varname, color, active) +#define RMLUI_ZoneNamedNC(varname, name, color, active) ZoneNamedNC(varname, name, color, active) + +#define RMLUI_ZoneScoped ZoneScoped +#define RMLUI_ZoneScopedN(name) ZoneScopedN(name) +#define RMLUI_ZoneScopedC(color) ZoneScopedC(color) +#define RMLUI_ZoneScopedNC(name, color) ZoneScopedNC(name, color) + +#define RMLUI_ZoneText(txt, size) ZoneText(txt, size) +#define RMLUI_ZoneName(txt, size) ZoneName(txt, size) + +#define RMLUI_TracyPlot(name,val) TracyPlot(name, val) + +#define RMLUI_FrameMark FrameMark +#define RMLUI_FrameMarkNamed(name) FrameMarkNamed(name) +#define RMLUI_FrameMarkStart(name) FrameMarkStart(name) +#define RMLUI_FrameMarkEnd(name) FrameMarkEnd(name) + +#else + +#define RMLUI_ZoneNamed(varname, active) +#define RMLUI_ZoneNamedN(varname, name, active) +#define RMLUI_ZoneNamedC(varname, color, active) +#define RMLUI_ZoneNamedNC(varname, name, color, active) + +#define RMLUI_ZoneScoped +#define RMLUI_ZoneScopedN(name) +#define RMLUI_ZoneScopedC(color) +#define RMLUI_ZoneScopedNC(name, color) + +#define RMLUI_ZoneText(txt, size) +#define RMLUI_ZoneName(txt, size) + +#define RMLUI_TracyPlot(name,val) + +#define RMLUI_FrameMark +#define RMLUI_FrameMarkNamed(name) +#define RMLUI_FrameMarkStart(name) +#define RMLUI_FrameMarkEnd(name) + +#endif + + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/PropertiesIteratorView.h b/thirdparty/RmlUi/Include/RmlUi/Core/PropertiesIteratorView.h new file mode 100644 index 000000000..7e413080a --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/PropertiesIteratorView.h @@ -0,0 +1,76 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef RMLUI_CORE_PROPERTIESITERATORVIEW_H +#define RMLUI_CORE_PROPERTIESITERATORVIEW_H + +#include "Types.h" +#include "Property.h" + +namespace Rml { + +class PropertiesIterator; + +/** + Provides an iterator for properties defined in the element's style or definition. + Construct it through the desired Element. + Warning: Modifying the underlying style invalidates the iterator. + + Usage: + for(auto it = element.IterateLocalProperties(); !it.AtEnd(); ++it) { ... } + + Note: Not an std-style iterator. Implemented as a wrapper over the internal + iterator to avoid exposing internal headers to the user. + + @author Michael R. P. Ragazzon + */ + +class RMLUICORE_API PropertiesIteratorView { +public: + PropertiesIteratorView(UniquePtr ptr); + PropertiesIteratorView(PropertiesIteratorView&& other) noexcept; + PropertiesIteratorView& operator=(PropertiesIteratorView&& other) noexcept; + PropertiesIteratorView(const PropertiesIteratorView& other) = delete; + PropertiesIteratorView& operator=(const PropertiesIteratorView&) = delete; + ~PropertiesIteratorView(); + + PropertiesIteratorView& operator++(); + + // Returns true when all properties have been iterated over. + // @warning The getters and operator++ can only be called if the iterator is not at the end. + bool AtEnd() const; + + PropertyId GetId() const; + const String& GetName() const; + const Property& GetProperty() const; + +private: + UniquePtr ptr; +}; + +} // namespace Rml +#endif \ No newline at end of file diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Property.h b/thirdparty/RmlUi/Include/RmlUi/Core/Property.h new file mode 100644 index 000000000..a442c7cf9 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Property.h @@ -0,0 +1,132 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTY_H +#define RMLUI_CORE_PROPERTY_H + +#include "Variant.h" +#include "Header.h" + +namespace Rml { + +class PropertyDefinition; + +struct RMLUICORE_API PropertySource { + PropertySource(String path, int line_number, String rule_name) : path(path), line_number(line_number), rule_name(rule_name) {} + String path; + int line_number; + String rule_name; +}; + + +/** + @author Peter Curry + */ + +class RMLUICORE_API Property +{ +public: + enum Unit + { + UNKNOWN = 1 << 0, + + KEYWORD = 1 << 1, // generic keyword; fetch as < int > + + STRING = 1 << 2, // generic string; fetch as < String > + + // Absolute values. + NUMBER = 1 << 3, // number unsuffixed; fetch as < float > + PX = 1 << 4, // number suffixed by 'px'; fetch as < float > + DEG = 1 << 5, // number suffixed by 'deg'; fetch as < float > + RAD = 1 << 6, // number suffixed by 'rad'; fetch as < float > + COLOUR = 1 << 7, // colour; fetch as < Colourb > + DP = 1 << 8, // density-independent pixel; number suffixed by 'dp'; fetch as < float > + ABSOLUTE_UNIT = NUMBER | PX | DP | DEG | RAD | COLOUR, + + // Relative values. + EM = 1 << 9, // number suffixed by 'em'; fetch as < float > + PERCENT = 1 << 10, // number suffixed by '%'; fetch as < float > + REM = 1 << 11, // number suffixed by 'rem'; fetch as < float > + RELATIVE_UNIT = EM | REM | PERCENT, + + // Values based on pixels-per-inch. + INCH = 1 << 12, // number suffixed by 'in'; fetch as < float > + CM = 1 << 13, // number suffixed by 'cm'; fetch as < float > + MM = 1 << 14, // number suffixed by 'mm'; fetch as < float > + PT = 1 << 15, // number suffixed by 'pt'; fetch as < float > + PC = 1 << 16, // number suffixed by 'pc'; fetch as < float > + PPI_UNIT = INCH | CM | MM | PT | PC, + + TRANSFORM = 1 << 17, // transform; fetch as < TransformPtr >, may be empty + TRANSITION = 1 << 18, // transition; fetch as < TransitionList > + ANIMATION = 1 << 19, // animation; fetch as < AnimationList > + DECORATOR = 1 << 20, // decorator; fetch as < DecoratorsPtr > + FONTEFFECT = 1 << 21, // font-effect; fetch as < FontEffectsPtr > + + LENGTH = PX | DP | PPI_UNIT | EM | REM, + LENGTH_PERCENT = LENGTH | PERCENT, + NUMBER_LENGTH_PERCENT = NUMBER | LENGTH | PERCENT, + ABSOLUTE_LENGTH = PX | DP | PPI_UNIT, + ANGLE = DEG | RAD + }; + + Property(); + template < typename PropertyType > + Property(PropertyType value, Unit unit, int specificity = -1) : value(value), unit(unit), specificity(specificity) + { + definition = nullptr; + parser_index = -1; + } + template::value, EnumType >::type> + Property(EnumType value) : value(static_cast(value)), unit(KEYWORD), specificity(-1) {} + + /// Get the value of the property as a string. + String ToString() const; + + /// Templatised accessor. + template + T Get() const + { + return value.Get(); + } + + bool operator==(const Property& other) const { return unit == other.unit && value == other.value; } + bool operator!=(const Property& other) const { return !(*this == other); } + + Variant value; + Unit unit; + int specificity; + + const PropertyDefinition* definition = nullptr; + int parser_index = -1; + + SharedPtr source; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/PropertyDefinition.h b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyDefinition.h new file mode 100644 index 000000000..b2fc069e0 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyDefinition.h @@ -0,0 +1,106 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYDEFINITION_H +#define RMLUI_CORE_PROPERTYDEFINITION_H + +#include "Header.h" +#include "Property.h" +#include "PropertyParser.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +enum class RelativeTarget { None, ContainingBlockWidth, ContainingBlockHeight, FontSize, ParentFontSize, LineHeight }; + +class RMLUICORE_API PropertyDefinition final +{ +public: + PropertyDefinition(PropertyId id, const String& default_value, bool inherited, bool forces_layout); + PropertyDefinition(const PropertyDefinition &) = delete; + PropertyDefinition& operator=(const PropertyDefinition &) = delete; + ~PropertyDefinition(); + + /// Registers a parser to parse values for this definition. + /// @param[in] parser_name The name of the parser (default parsers are 'string', 'keyword', 'number' and 'colour'). + /// @param[in] parser_parameters A comma-separated list of validation parameters for the parser. + /// @return This property definition. + PropertyDefinition& AddParser(const String& parser_name, const String& parser_parameters = ""); + + /// Set target for relative units when resolving sizes such as percentages. + PropertyDefinition& SetRelativeTarget(RelativeTarget relative_target); + + /// Called when parsing a RCSS declaration. + /// @param property[out] The property to set the parsed value onto. + /// @param value[in] The raw value defined for this property. + /// @return True if all values were parsed successfully, false otherwise. + bool ParseValue(Property& property, const String& value) const; + /// Called to convert a parsed property back into a value. + /// @param value[out] The string to return the value in. + /// @param property[in] The processed property to parse. + /// @return True if the property was reverse-engineered successfully, false otherwise. + bool GetValue(String& value, const Property& property) const; + + /// Returns true if this property is inherited from parent to child elements. + bool IsInherited() const; + + /// Returns true if this property forces a re-layout when changed. + bool IsLayoutForced() const; + + /// Returns the default defined for this property. + const Property* GetDefaultValue() const; + + /// Returns the target for resolving values with percent and possibly number units. + RelativeTarget GetRelativeTarget() const; + + /// Return the property id + PropertyId GetId() const; + +private: + PropertyId id; + + Property default_value; + bool inherited; + bool forces_layout; + + struct ParserState + { + PropertyParser* parser; + ParameterMap parameters; + }; + + Vector< ParserState > parsers; + + RelativeTarget relative_target; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/PropertyDictionary.h b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyDictionary.h new file mode 100644 index 000000000..350c46df3 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyDictionary.h @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYDICTIONARY_H +#define RMLUI_CORE_PROPERTYDICTIONARY_H + +#include "Header.h" +#include "Property.h" + +namespace Rml { + +/** + A dictionary to property names to values. + + @author Peter Curry + */ + +class RMLUICORE_API PropertyDictionary +{ +public: + PropertyDictionary(); + + /// Sets a property on the dictionary. Any existing property with the same id will be overwritten. + void SetProperty(PropertyId id, const Property& property); + /// Removes a property from the dictionary, if it exists. + void RemoveProperty(PropertyId id); + /// Returns the value of the property with the requested id, if one exists. + const Property* GetProperty(PropertyId id) const; + + /// Returns the number of properties in the dictionary. + int GetNumProperties() const; + /// Returns the map of properties in the dictionary. + const PropertyMap& GetProperties() const; + + /// Imports into the dictionary, and optionally defines the specificity of, potentially + /// un-specified properties. In the case of id conflicts, the incoming properties will + /// overwrite the existing properties if their specificity (or their forced specificity) + /// are at least equal. + /// @param[in] property_dictionary The properties to import. + /// @param[in] specificity The specificity for all incoming properties. If this is not specified, the properties will keep their original specificity. + void Import(const PropertyDictionary& property_dictionary, int specificity = -1); + + /// Merges the contents of another fully-specified property dictionary with this one. + /// Properties defined in the new dictionary will overwrite those with the same id as + /// appropriate. + /// @param[in] property_dictionary The dictionary to merge. + /// @param[in] specificity_offset The specificities of all incoming properties will be offset by this value. + void Merge(const PropertyDictionary& property_dictionary, int specificity_offset = 0); + + /// Set the source of all properties in the dictionary to the given one. + void SetSourceOfAllProperties(const SharedPtr& property_source); + +private: + // Sets a property on the dictionary and its specificity if there is no name conflict, or its + // specificity (given by the parameter, not read from the property itself) is at least equal to + // the specificity of the conflicting property. + void SetProperty(PropertyId id, const Property& property, int specificity); + + PropertyMap properties; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/PropertyIdSet.h b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyIdSet.h new file mode 100644 index 000000000..a33167c86 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyIdSet.h @@ -0,0 +1,178 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef RMLUI_CORE_PROPERTYIDSET_H +#define RMLUI_CORE_PROPERTYIDSET_H + +#include "Types.h" +#include "ID.h" +#include + +namespace Rml { + +class PropertyIdSetIterator; + + +/* + PropertyIdSet is a 'set'-like container for PropertyIds. + + Implemented as a wrapper around bitset. It is cheap to construct and use, requiring no dynamic allocation. + + Supports union and intersection operations between two sets, as well as iteration through the IDs that are inserted. +*/ + +class RMLUICORE_API PropertyIdSet { +private: + static constexpr size_t N = size_t(PropertyId::MaxNumIds); + std::bitset defined_ids; + +public: + PropertyIdSet() { + static_assert((size_t)PropertyId::Invalid == 0, "PropertyIdSet makes an assumption that PropertyId::Invalid is zero."); + } + + void Insert(PropertyId id) { + RMLUI_ASSERT(size_t(id) < N); + defined_ids.set((size_t)id); + } + + void Clear() { + defined_ids.reset(); + } + void Erase(PropertyId id) { + RMLUI_ASSERT(size_t(id) < N); + defined_ids.reset((size_t)id); + } + + bool Empty() const { + return defined_ids.none(); + } + bool Contains(PropertyId id) const { + return defined_ids.test((size_t)id); + } + + size_t Size() const { + return defined_ids.count(); + } + + // Union with another set + PropertyIdSet& operator|=(const PropertyIdSet& other) { + defined_ids |= other.defined_ids; + return *this; + } + PropertyIdSet operator|(const PropertyIdSet& other) const { + PropertyIdSet result = *this; + result |= other; + return result; + } + + // Intersection with another set + PropertyIdSet& operator&=(const PropertyIdSet& other) { + defined_ids &= other.defined_ids; + return *this; + } + PropertyIdSet operator&(const PropertyIdSet& other) const { + PropertyIdSet result; + result.defined_ids = (defined_ids & other.defined_ids); + return result; + } + + // Iterator support. Iterates through all the PropertyIds that are set (contained). + // @note: Only const_iterators are provided. + inline PropertyIdSetIterator begin() const; + inline PropertyIdSetIterator end() const; + + // Erases the property id represented by a valid iterator. Iterator must be in the range [begin, end). + // @return A new iterator pointing to the next element or end(). + inline PropertyIdSetIterator Erase(PropertyIdSetIterator it); +}; + + + +class RMLUICORE_API PropertyIdSetIterator +{ +public: + PropertyIdSetIterator() = default; + PropertyIdSetIterator(const PropertyIdSet* container, size_t id_index) : container(container), id_index(id_index) + { + ProceedToNextValid(); + } + + PropertyIdSetIterator& operator++() { + ++id_index; + ProceedToNextValid(); + return *this; + } + + bool operator==(const PropertyIdSetIterator& other) const { + return container == other.container && id_index == other.id_index; + } + bool operator!=(const PropertyIdSetIterator& other) const { + return !(*this == other); + } + PropertyId operator*() const { + return static_cast(id_index); + } + +private: + + inline void ProceedToNextValid() + { + for (; id_index < size_t(PropertyId::MaxNumIds); ++id_index) + { + if (container->Contains( static_cast(id_index) )) + return; + } + } + + const PropertyIdSet* container = nullptr; + size_t id_index = 0; + + friend PropertyIdSetIterator PropertyIdSet::Erase(PropertyIdSetIterator); +}; + + + +PropertyIdSetIterator PropertyIdSet::begin() const { + if (Empty()) + return end(); + return PropertyIdSetIterator(this, 1); +} + +PropertyIdSetIterator PropertyIdSet::end() const { + return PropertyIdSetIterator(this, N); +} + +PropertyIdSetIterator PropertyIdSet::Erase(PropertyIdSetIterator it) { + RMLUI_ASSERT(it.container == this && it.id_index < N); + defined_ids.reset(it.id_index); + ++it; + return it; +} + +} // namespace Rml +#endif \ No newline at end of file diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/PropertyParser.h b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyParser.h new file mode 100644 index 000000000..d9e721e66 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/PropertyParser.h @@ -0,0 +1,59 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYPARSER_H +#define RMLUI_CORE_PROPERTYPARSER_H + +#include "Header.h" +#include "Property.h" + +namespace Rml { + +using ParameterMap = UnorderedMap< String, int >; + +/** + A property parser takes a property declaration in string form, validates it, and converts it to a Property. + + @author Peter Curry + */ + +class RMLUICORE_API PropertyParser +{ +public: + virtual ~PropertyParser() {} + + /// Called to parse a RCSS declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The list of parameters defined for this property. + /// @return True if the value was parsed successfully, false otherwise. + virtual bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const = 0; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/PropertySpecification.h b/thirdparty/RmlUi/Include/RmlUi/Core/PropertySpecification.h new file mode 100644 index 000000000..67d4c1b9b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/PropertySpecification.h @@ -0,0 +1,143 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYSPECIFICATION_H +#define RMLUI_CORE_PROPERTYSPECIFICATION_H + +#include "Header.h" +#include "Types.h" +#include "PropertyIdSet.h" +#include "ID.h" + +namespace Rml { + +class StyleSheetSpecification; +class PropertyDefinition; +class PropertyDictionary; +class PropertyIdNameMap; +class ShorthandIdNameMap; +struct ShorthandDefinition; + +enum class ShorthandType +{ + // Normal; properties that fail to parse fall-through to the next until they parse correctly, and any + // undeclared are not set. + FallThrough, + // A single failed parse will abort, and any undeclared are replicated from the last declared property. + Replicate, + // For 'padding', 'margin', etc; up to four properties are expected. + Box, + // Repeatedly resolves the full value string on each property, whether it is a normal property or another shorthand. + RecursiveRepeat, + // Comma-separated list of properties or shorthands, the number of declared values must match the specified. + RecursiveCommaSeparated +}; + + +/** + A property specification stores a group of property definitions. + + @author Peter Curry + */ + +class RMLUICORE_API PropertySpecification +{ +public: + PropertySpecification(size_t reserve_num_properties, size_t reserve_num_shorthands); + ~PropertySpecification(); + + /// Registers a property with a new definition. + /// @param[in] property_name The name to register the new property under. + /// @param[in] default_value The default value to be used for an element if it has no other definition provided. + /// @param[in] inherited True if this property is inherited from parent to child, false otherwise. + /// @param[in] forces_layout True if this property requires its parent to be reformatted if changed. + /// @param[in] id If 'Invalid' then automatically assigns a new id, otherwise assigns the given id. + /// @return The new property definition, ready to have parsers attached. + PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout, PropertyId id = PropertyId::Invalid); + /// Returns a property definition. + /// @param[in] id The id of the desired property. + /// @return The appropriate property definition if it could be found, nullptr otherwise. + const PropertyDefinition* GetProperty(PropertyId id) const; + const PropertyDefinition* GetProperty(const String& property_name) const; + + /// Returns the id set of all registered property definitions. + const PropertyIdSet& GetRegisteredProperties() const; + /// Returns the id set of all registered inherited property definitions. + const PropertyIdSet& GetRegisteredInheritedProperties() const; + /// Returns the id set of all registered property definitions that may dirty the layout. + const PropertyIdSet& GetRegisteredPropertiesForcingLayout() const; + + /// Registers a shorthand property definition. + /// @param[in] shorthand_name The name to register the new shorthand property under. + /// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed. + /// @param[in] type The type of shorthand to declare. + /// @param[in] id If 'Invalid' then automatically assigns a new id, otherwise assigns the given id. + /// @param True if all the property names exist, false otherwise. + ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type, ShorthandId id = ShorthandId::Invalid); + /// Returns a shorthand definition. + /// @param[in] shorthand_name The name of the desired shorthand. + /// @return The appropriate shorthand definition if it could be found, nullptr otherwise. + const ShorthandDefinition* GetShorthand(ShorthandId id) const; + const ShorthandDefinition* GetShorthand(const String& shorthand_name) const; + + /// Parse declaration by name, whether it's a property or shorthand. + bool ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value) const; + /// Parse property declaration by ID. + bool ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value) const; + /// Parses a shorthand declaration, setting any parsed and validated properties on the given dictionary. + /// @return True if all properties were parsed successfully, false otherwise. + bool ParseShorthandDeclaration(PropertyDictionary& dictionary, ShorthandId shorthand_id, const String& property_value) const; + + /// Sets all undefined properties in the dictionary to their defaults. + /// @param dictionary[in-out] The dictionary to set the default values on. + void SetPropertyDefaults(PropertyDictionary& dictionary) const; + + /// Returns the properties of dictionary converted to a string. + String PropertiesToString(const PropertyDictionary& dictionary) const; + +private: + using Properties = Vector< UniquePtr >; + using Shorthands = Vector< UniquePtr >; + + Properties properties; + Shorthands shorthands; + + UniquePtr property_map; + UniquePtr shorthand_map; + + PropertyIdSet property_ids; + PropertyIdSet property_ids_inherited; + PropertyIdSet property_ids_forcing_layout; + + bool ParsePropertyValues(StringList& values_list, const String& values, bool split_values) const; + + friend class StyleSheetSpecification; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/RenderInterface.h b/thirdparty/RmlUi/Include/RmlUi/Core/RenderInterface.h new file mode 100644 index 000000000..61ec27d63 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/RenderInterface.h @@ -0,0 +1,126 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_RENDERINTERFACE_H +#define RMLUI_CORE_RENDERINTERFACE_H + +#include "Traits.h" +#include "Header.h" +#include "Texture.h" +#include "Vertex.h" +#include "Types.h" + +namespace Rml { + +class Context; + +/** + The abstract base class for application-specific rendering implementation. Your application must provide a concrete + implementation of this class and install it through Rml::SetRenderInterface() in order for anything to be rendered. + + @author Peter Curry + */ + +class RMLUICORE_API RenderInterface : public NonCopyMoveable +{ +public: + RenderInterface(); + virtual ~RenderInterface(); + + /// Called by RmlUi when it wants to render geometry that the application does not wish to optimise. Note that + /// RmlUi renders everything as triangles. + /// @param[in] vertices The geometry's vertex data. + /// @param[in] num_vertices The number of vertices passed to the function. + /// @param[in] indices The geometry's index data. + /// @param[in] num_indices The number of indices passed to the function. This will always be a multiple of three. + /// @param[in] texture The texture to be applied to the geometry. This may be nullptr, in which case the geometry is untextured. + /// @param[in] translation The translation to apply to the geometry. + virtual void RenderGeometry(Vertex* vertices, int num_vertices, int* indices, int num_indices, TextureHandle texture, const Vector2f& translation) = 0; + + /// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future. + /// If supported, this should return a handle to an optimised, application-specific version of the data. If + /// not, do not override the function or return zero; the simpler RenderGeometry() will be called instead. + /// @param[in] vertices The geometry's vertex data. + /// @param[in] num_vertices The number of vertices passed to the function. + /// @param[in] indices The geometry's index data. + /// @param[in] num_indices The number of indices passed to the function. This will always be a multiple of three. + /// @param[in] texture The texture to be applied to the geometry. This may be nullptr, in which case the geometry is untextured. + /// @return The application-specific compiled geometry. Compiled geometry will be stored and rendered using RenderCompiledGeometry() in future calls, and released with ReleaseCompiledGeometry() when it is no longer needed. + virtual CompiledGeometryHandle CompileGeometry(Vertex* vertices, int num_vertices, int* indices, int num_indices, TextureHandle texture); + /// Called by RmlUi when it wants to render application-compiled geometry. + /// @param[in] geometry The application-specific compiled geometry to render. + /// @param[in] translation The translation to apply to the geometry. + virtual void RenderCompiledGeometry(CompiledGeometryHandle geometry, const Vector2f& translation); + /// Called by RmlUi when it wants to release application-compiled geometry. + /// @param[in] geometry The application-specific compiled geometry to release. + virtual void ReleaseCompiledGeometry(CompiledGeometryHandle geometry); + + /// Called by RmlUi when it wants to enable or disable scissoring to clip content. + /// @param[in] enable True if scissoring is to enabled, false if it is to be disabled. + virtual void EnableScissorRegion(bool enable) = 0; + /// Called by RmlUi when it wants to change the scissor region. + /// @param[in] x The left-most pixel to be rendered. All pixels to the left of this should be clipped. + /// @param[in] y The top-most pixel to be rendered. All pixels to the top of this should be clipped. + /// @param[in] width The width of the scissored region. All pixels to the right of (x + width) should be clipped. + /// @param[in] height The height of the scissored region. All pixels to below (y + height) should be clipped. + virtual void SetScissorRegion(int x, int y, int width, int height) = 0; + + /// Called by RmlUi when a texture is required by the library. + /// @param[out] texture_handle The handle to write the texture handle for the loaded texture to. + /// @param[out] texture_dimensions The variable to write the dimensions of the loaded texture. + /// @param[in] source The application-defined image source, joined with the path of the referencing document. + /// @return True if the load attempt succeeded and the handle and dimensions are valid, false if not. + virtual bool LoadTexture(TextureHandle& texture_handle, Vector2i& texture_dimensions, const String& source); + /// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels. + /// @param[out] texture_handle The handle to write the texture handle for the generated texture to. + /// @param[in] source The raw 8-bit texture data. Each pixel is made up of four 8-bit values, indicating red, green, blue and alpha in that order. + /// @param[in] source_dimensions The dimensions, in pixels, of the source data. + /// @return True if the texture generation succeeded and the handle is valid, false if not. + virtual bool GenerateTexture(TextureHandle& texture_handle, const byte* source, const Vector2i& source_dimensions); + /// Called by RmlUi when a loaded texture is no longer required. + /// @param texture The texture handle to release. + virtual void ReleaseTexture(TextureHandle texture); + + /// Called by RmlUi when it wants the renderer to use a new transform matrix. + /// This will only be called if 'transform' properties are encountered. If no transform applies to the current element, nullptr + /// is submitted. Then it expects the renderer to use an identity matrix or otherwise omit the multiplication with the transform. + /// @param[in] transform The new transform to apply, or nullptr if no transform applies to the current element. + virtual void SetTransform(const Matrix4f* transform); + + /// Get the context currently being rendered. This is only valid during RenderGeometry, + /// CompileGeometry, RenderCompiledGeometry, EnableScissorRegion and SetScissorRegion. + Context* GetContext() const; + +private: + Context* context; + + friend class Context; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/ScriptInterface.h b/thirdparty/RmlUi/Include/RmlUi/Core/ScriptInterface.h new file mode 100644 index 000000000..371ef6c89 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/ScriptInterface.h @@ -0,0 +1,56 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_SCRIPTINTERFACE_H +#define RMLUI_CORE_SCRIPTINTERFACE_H + +#include "Header.h" +#include "Traits.h" +#include "Types.h" + +namespace Rml { + +/** + Base class for all objects that hold a scriptable object. + @author Peter Curry + */ + +class RMLUICORE_API ScriptInterface : public Releasable { +public: + RMLUI_RTTI_Define(ScriptInterface) + + virtual ~ScriptInterface() { } + + virtual ScriptObject GetScriptObject() const + { + return nullptr; + } +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Spritesheet.h b/thirdparty/RmlUi/Include/RmlUi/Core/Spritesheet.h new file mode 100644 index 000000000..9cbaa7a01 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Spritesheet.h @@ -0,0 +1,98 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUISPRITESHEET_H +#define RMLUISPRITESHEET_H + +#include "Types.h" +#include "Texture.h" + +namespace Rml { + +struct Spritesheet; + + +struct Rectangle { + Rectangle(float x = 0, float y = 0, float width = 0, float height = 0) : x(x), y(y), width(width), height(height) {} + float x, y, width, height; +}; + +struct Sprite { + Rectangle rectangle; // in 'px' units + const Spritesheet* sprite_sheet; +}; +using SpriteMap = UnorderedMap; // key: sprite name (as given in @spritesheet) + + +/** + Spritesheet holds a list of sprite names given in the @spritesheet at-rule in RCSS. + */ +struct Spritesheet { + String name; + String image_source; + String definition_source; + int definition_line_number; + Texture texture; + StringList sprite_names; + + Spritesheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const Texture& texture) + : name(name), image_source(image_source), definition_source(definition_source), definition_line_number(definition_line_number), texture(texture) {} +}; + +using SpritesheetMap = SmallUnorderedMap>; // key: spritesheet name (as given in @spritesheet) +using SpriteDefinitionList = Vector>; // Sprite name and rectangle + + +/** + SpritesheetList holds all the spritesheets and sprites given in a style sheet. + */ +class SpritesheetList { +public: + /// Adds a new sprite sheet to the list and inserts all sprites with unique names into the global list. + bool AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const SpriteDefinitionList& sprite_definitions); + + /// Get a sprite from its name if it exists. + /// Note: The pointer is invalidated whenever another sprite is added. Do not store it around. + const Sprite* GetSprite(const String& name) const; + + /// Merge 'other' into this. + void Merge(const SpritesheetList& other); + + void Reserve(size_t size_sprite_sheets, size_t size_sprites); + size_t NumSpriteSheets() const; + size_t NumSprites() const; + + String ToString() const; + +private: + SpritesheetMap spritesheet_map; + SpriteMap sprite_map; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Stream.h b/thirdparty/RmlUi/Include/RmlUi/Core/Stream.h new file mode 100644 index 000000000..cef020e21 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Stream.h @@ -0,0 +1,133 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STREAM_H +#define RMLUI_CORE_STREAM_H + +#include "Header.h" +#include "Traits.h" +#include "Types.h" +#include "URL.h" + +namespace Rml { + +class StreamListener; + +/** + Abstract class for a media-independent byte stream. + @author Lloyd Weehuizen + */ + +class RMLUICORE_API Stream : public NonCopyMoveable +{ +public: + // Stream modes. + enum StreamMode + { + MODE_WRITE = 1 << 0, + MODE_APPEND = 1 << 1, + MODE_READ = 1 << 2, + MODE_ASYNC = 1 << 3, + + MODE_MASK = MODE_WRITE | MODE_APPEND | MODE_READ + }; + + Stream(); + virtual ~Stream(); + + /// Closes the stream. + virtual void Close(); + + /// Returns the mode the stream was opened in. + int GetStreamMode() const; + + /// Obtain the source url of this stream (if available) + const URL& GetSourceURL() const; + + /// Are we at the end of the stream + virtual bool IsEOS() const; + + /// Returns the size of this stream (in bytes). + virtual size_t Length() const = 0; + + /// Returns the position of the stream pointer (in bytes). + virtual size_t Tell() const = 0; + /// Sets the stream position (in bytes). + virtual bool Seek(long offset, int origin) const = 0; + + /// Read from the stream. + virtual size_t Read(void* buffer, size_t bytes) const = 0; + /// Read from the stream into another stream. + virtual size_t Read(Stream* stream, size_t bytes) const; + /// Read from the stream and append to the string buffer + virtual size_t Read(String& buffer, size_t bytes) const; + /// Read from the stream, without increasing the stream offset. + virtual size_t Peek(void* buffer, size_t bytes) const; + + /// Write to the stream at the current position. + virtual size_t Write(const void* buffer, size_t bytes) = 0; + /// Write to this stream from another stream. + virtual size_t Write(const Stream* stream, size_t bytes); + /// Write a character array to the stream. + virtual size_t Write(const char* string); + /// Write a string to the stream + virtual size_t Write(const String& string); + + /// Truncate the stream to the specified length. + virtual size_t Truncate(size_t bytes) = 0; + + /// Push onto the front of the stream. + virtual size_t PushFront(const void* buffer, size_t bytes); + /// Push onto the back of the stream. + virtual size_t PushBack(const void* buffer, size_t bytes); + + /// Pop from the front of the stream. + virtual size_t PopFront(size_t bytes); + /// Pop from the back of the stream. + virtual size_t PopBack(size_t bytes); + + /// Returns true if the stream is ready for reading, false otherwise. + /// This is usually only implemented on streams supporting asynchronous + /// operations. + virtual bool IsReadReady() = 0; + /// Returns true if the stream is ready for writing, false otherwise. + /// This is usually only implemented on streams supporting asynchronous + /// operations. + virtual bool IsWriteReady() = 0; + +protected: + /// Sets the mode on the stream; should be called by a stream when it is opened. + void SetStreamDetails(const URL& url, int stream_mode); + +private: + URL url; + int stream_mode; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/StreamMemory.h b/thirdparty/RmlUi/Include/RmlUi/Core/StreamMemory.h new file mode 100644 index 000000000..24a0ea55d --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/StreamMemory.h @@ -0,0 +1,116 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STREAMMEMORY_H +#define RMLUI_CORE_STREAMMEMORY_H + +#include "Header.h" +#include "Stream.h" + +namespace Rml { + +/** + Memory Byte Stream Class + @author Lloyd Weehuizen + */ + +class RMLUICORE_API StreamMemory : public Stream +{ +public: + /// Empty memory stream with default size buffer + StreamMemory(); + /// Empty memory stream with specified buffer size + StreamMemory(size_t initial_size); + /// Read only memory stream based on the existing buffer + StreamMemory(const byte* buffer, size_t buffer_size); + virtual ~StreamMemory(); + + /// Close the stream + void Close() override; + + /// Are we at the end of the stream + bool IsEOS() const override; + + /// Size of this stream ( in bytes ) + size_t Length() const override; + + /// Get Stream position ( in bytes ) + size_t Tell() const override; + + /// Set Stream position ( in bytes ) + bool Seek(long offset, int origin) const override; + + /// Read from the stream + using Stream::Read; + size_t Read(void* buffer, size_t bytes) const override; + + /// Peek into the stream + size_t Peek(void *buffer, size_t bytes) const override; + + /// Write to the stream + using Stream::Write; + size_t Write(const void* buffer, size_t bytes) override; + + /// Truncate the stream to the specified length + size_t Truncate(size_t bytes) override; + + /// Push onto the front of the stream + size_t PushFront(const void* buffer, size_t bytes) override; + + /// Pop from the front of the stream + size_t PopFront(size_t bytes) override; + + /// Raw access to the stream + const byte* RawStream() const; + + /// Erase a section of the stream + void Erase(size_t offset, size_t bytes); + + /// Does the stream have data available for reading + bool IsReadReady() override; + + /// Is the stream able to accept data now + bool IsWriteReady() override; + + /// Sets this streams source URL, useful data that is stored + /// in memory streams that originated from files + void SetSourceURL(const URL& url); + +private: + + byte* buffer; + mutable byte* buffer_ptr; + size_t buffer_size; + size_t buffer_used; + bool owns_buffer; + + bool Reallocate(size_t size); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/StringUtilities.h b/thirdparty/RmlUi/Include/RmlUi/Core/StringUtilities.h new file mode 100644 index 000000000..ef11fe7c1 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/StringUtilities.h @@ -0,0 +1,223 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STRINGUTILITIES_H +#define RMLUI_CORE_STRINGUTILITIES_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +/** + Helper functions for string manipulation. + @author Lloyd Weehuizen + */ + +class StringView; + +/// Construct a string using sprintf-style syntax. +RMLUICORE_API String CreateString(size_t max_size, const char* format, ...); + +/// Format to a string using sprintf-style syntax. +RMLUICORE_API int FormatString(String& string, size_t max_size, const char* format, ...); + + +namespace StringUtilities +{ + /// Expands character-delimited list of values in a single string to a whitespace-trimmed list + /// of values. + /// @param[out] string_list Resulting list of values. + /// @param[in] string String to expand. + /// @param[in] delimiter Delimiter found between entries in the string list. + RMLUICORE_API void ExpandString(StringList& string_list, const String& string, const char delimiter = ','); + /// Expands character-delimited list of values with custom quote characters. + /// @param[out] string_list Resulting list of values. + /// @param[in] string String to expand. + /// @param[in] delimiter Delimiter found between entries in the string list. + /// @param[in] quote_character Begin quote + /// @param[in] unquote_character End quote + /// @param[in] ignore_repeated_delimiters If true, repeated values of the delimiter will not add additional entries to the list. + RMLUICORE_API void ExpandString(StringList& string_list, const String& string, const char delimiter, char quote_character, char unquote_character, bool ignore_repeated_delimiters = false); + /// Joins a list of string values into a single string separated by a character delimiter. + /// @param[out] string Resulting concatenated string. + /// @param[in] string_list Input list of string values. + /// @param[in] delimiter Delimiter to insert between the individual values. + RMLUICORE_API void JoinString(String& string, const StringList& string_list, const char delimiter = ','); + + /// Converts upper-case characters in string to lower-case. + RMLUICORE_API String ToLower(const String& string); + /// Converts lower-case characters in string to upper-case. + RMLUICORE_API String ToUpper(const String& string); + + /// Encode RML characters, eg. '<' to '<' + RMLUICORE_API String EncodeRml(const String& string); + + // Replaces all occurences of 'search' in 'subject' with 'replace'. + RMLUICORE_API String Replace(String subject, const String& search, const String& replace); + // Replaces all occurences of 'search' in 'subject' with 'replace'. + RMLUICORE_API String Replace(String subject, char search, char replace); + + /// Checks if a given value is a whitespace character. + inline bool IsWhitespace(const char x) + { + return (x == '\r' || x == '\n' || x == ' ' || x == '\t'); + } + + /// Strip whitespace characters from the beginning and end of a string. + RMLUICORE_API String StripWhitespace(const String& string); + + /// Strip whitespace characters from the beginning and end of a string. + RMLUICORE_API String StripWhitespace(StringView string); + + /// Trim trailing zeros and the dot from a string-representation of a number with a decimal point. + /// @warning If the string does not represent a number _with_ a decimal point, the result will probably not be as desired. + RMLUICORE_API void TrimTrailingDotZeros(String& string); + + /// Case insensitive string comparison. Returns true if they compare equal. + RMLUICORE_API bool StringCompareCaseInsensitive(StringView lhs, StringView rhs); + + // Decode the first code point in a zero-terminated UTF-8 string. + RMLUICORE_API Character ToCharacter(const char* p); + + // Encode a single code point as a UTF-8 string. + RMLUICORE_API String ToUTF8(Character character); + + // Encode an array of code points as a UTF-8 string. + RMLUICORE_API String ToUTF8(const Character* characters, int num_characters); + + /// Returns number of characters in a UTF-8 string. + RMLUICORE_API size_t LengthUTF8(StringView string_view); + + // Seek forward in a UTF-8 string, skipping continuation bytes. + inline const char* SeekForwardUTF8(const char* p, const char* p_end) + { + while (p != p_end && (*p & 0b1100'0000) == 0b1000'0000) + ++p; + return p; + } + // Seek backward in a UTF-8 string, skipping continuation bytes. + inline const char* SeekBackwardUTF8(const char* p, const char* p_begin) + { + while ((p + 1) != p_begin && (*p & 0b1100'0000) == 0b1000'0000) + --p; + return p; + } + + /// Converts a string in UTF-8 encoding to a u16string in UTF-16 encoding. + /// Reports a warning if some or all characters could not be converted. + RMLUICORE_API U16String ToUTF16(const String& str); + + /// Converts a u16string in UTF-16 encoding into a string in UTF-8 encoding. + /// Reports a warning if some or all characters could not be converted. + RMLUICORE_API String ToUTF8(const U16String& u16str); +} + + +/* + A poor man's string view. + + The string view is agnostic to the underlying encoding, any operation will strictly operate on bytes. +*/ + +class RMLUICORE_API StringView { +public: + StringView(); + StringView(const char* p_begin, const char* p_end); + StringView(const String& string); + StringView(const String& string, size_t offset); + StringView(const String& string, size_t offset, size_t count); + + // String comparison to another view + bool operator==(const StringView& other) const; + inline bool operator!=(const StringView& other) const { return !(*this == other); } + + inline const char* begin() const { return p_begin; } + inline const char* end() const { return p_end; } + + inline size_t size() const { return size_t(p_end - p_begin); } + + explicit inline operator String() const { + return String(p_begin, p_end); + } + +private: + const char* p_begin; + const char* p_end; +}; + + +/* + An iterator for UTF-8 strings. + + The increment and decrement operations will move to the beginning of the next or the previous + UTF-8 character, respectively. The dereference operator will resolve the current code point. + +*/ + +class RMLUICORE_API StringIteratorU8 { +public: + StringIteratorU8(const char* p_begin, const char* p, const char* p_end); + StringIteratorU8(const String& string); + StringIteratorU8(const String& string, size_t offset); + StringIteratorU8(const String& string, size_t offset, size_t count); + + // Seeks forward to the next UTF-8 character. Iterator must be valid. + StringIteratorU8& operator++(); + // Seeks back to the previous UTF-8 character. Iterator must be valid. + StringIteratorU8& operator--(); + + // Returns the codepoint at the current position. The iterator must be dereferencable. + inline Character operator*() const { return StringUtilities::ToCharacter(p); } + + // Returns false when the iterator is located just outside the valid part of the string. + explicit inline operator bool() const { return (p != view.begin() - 1) && (p != view.end()); } + + bool operator==(const StringIteratorU8& other) const { return p == other.p; } + bool operator!=(const StringIteratorU8& other) const { return !(*this == other); } + + // Return a pointer to the current position. + inline const char* get() const { return p; } + + // Return offset from the beginning of string. Note: Can return negative if decremented. + std::ptrdiff_t offset() const { return p - view.begin(); } + +private: + StringView view; + // 'p' can be dereferenced if and only if inside [view.begin, view.end) + const char* p; + + inline void SeekForward(); + inline void SeekBack(); +}; + + + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/StyleSheet.h b/thirdparty/RmlUi/Include/RmlUi/Core/StyleSheet.h new file mode 100644 index 000000000..5e02d4482 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/StyleSheet.h @@ -0,0 +1,142 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEET_H +#define RMLUI_CORE_STYLESHEET_H + +#include "Traits.h" +#include "PropertyDictionary.h" +#include "Spritesheet.h" + +namespace Rml { + +class Element; +class ElementDefinition; +class StyleSheetNode; +class Decorator; +class FontEffect; +class SpritesheetList; +class Stream; +struct Sprite; +struct Spritesheet; + +struct KeyframeBlock { + KeyframeBlock(float normalized_time) : normalized_time(normalized_time) {} + float normalized_time; // [0, 1] + PropertyDictionary properties; +}; +struct Keyframes { + Vector property_ids; + Vector blocks; +}; +using KeyframesMap = UnorderedMap; + +struct DecoratorSpecification { + String decorator_type; + PropertyDictionary properties; + SharedPtr decorator; +}; +using DecoratorSpecificationMap = UnorderedMap; + +/** + StyleSheet maintains a single stylesheet definition. A stylesheet can be combined with another stylesheet to create + a new, merged stylesheet. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API StyleSheet : public NonCopyMoveable +{ +public: + typedef Vector< StyleSheetNode* > NodeList; + typedef UnorderedMap< size_t, NodeList > NodeIndex; + + StyleSheet(); + virtual ~StyleSheet(); + + /// Loads a style from a CSS definition. + bool LoadStyleSheet(Stream* stream, int begin_line_number = 1); + + /// Combines this style sheet with another one, producing a new sheet. + SharedPtr CombineStyleSheet(const StyleSheet& sheet) const; + /// Builds the node index for a combined style sheet, and optimizes some properties for faster retrieval. + /// Specifically, converts all decorator properties from strings to instanced decorator lists. + void BuildNodeIndexAndOptimizeProperties(); + + /// Returns the Keyframes of the given name, or null if it does not exist. + Keyframes* GetKeyframes(const String& name); + + /// Returns the Decorator of the given name, or null if it does not exist. + SharedPtr GetDecorator(const String& name) const; + + /// Parses the decorator property from a string and returns a list of instanced decorators. + DecoratorsPtr InstanceDecoratorsFromString(const String& decorator_string_value, const SharedPtr& source) const; + + /// Parses the font-effect property from a string and returns a list of instanced font-effects. + FontEffectsPtr InstanceFontEffectsFromString(const String& font_effect_string_value, const SharedPtr& source) const; + + /// Get sprite located in any spritesheet within this stylesheet. + const Sprite* GetSprite(const String& name) const; + + /// Returns the compiled element definition for a given element hierarchy. A reference count will be added for the + /// caller, so another should not be added. The definition should be released by removing the reference count. + SharedPtr GetElementDefinition(const Element* element) const; + + /// Retrieve the hash key used to look-up applicable nodes in the node index. + static size_t NodeHash(const String& tag, const String& id); + +private: + // Root level node, attributes from special nodes like "body" get added to this node + UniquePtr root; + + // The maximum specificity offset used in this style sheet to distinguish between properties in + // similarly-specific rules, but declared on different lines. When style sheets are merged, the + // more-specific style sheet (ie, coming further 'down' the include path) adds the offset of + // the less-specific style sheet onto its offset, thereby ensuring its properties take + // precedence in the event of a conflict. + int specificity_offset; + + // Name of every @keyframes mapped to their keys + KeyframesMap keyframes; + + // Name of every @decorator mapped to their specification + DecoratorSpecificationMap decorator_map; + + // Name of every @spritesheet and underlying sprites mapped to their values + SpritesheetList spritesheet_list; + + // Map of all styled nodes, that is, they have one or more properties. + NodeIndex styled_node_index; + + using ElementDefinitionCache = UnorderedMap< size_t, SharedPtr >; + // Index of node sets to element definitions. + mutable ElementDefinitionCache node_cache; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/StyleSheetSpecification.h b/thirdparty/RmlUi/Include/RmlUi/Core/StyleSheetSpecification.h new file mode 100644 index 000000000..543624bf2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/StyleSheetSpecification.h @@ -0,0 +1,139 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETSPECIFICATION_H +#define RMLUI_CORE_STYLESHEETSPECIFICATION_H + +#include "Header.h" +#include "PropertySpecification.h" +#include "Types.h" + +namespace Rml { + +class PropertyParser; +struct DefaultStyleSheetParsers; + +/** + @author Peter Curry + */ + +class RMLUICORE_API StyleSheetSpecification +{ +public: + /// Starts up the specification structure and registers default properties and type parsers. + /// @return True if the specification started up successfully, false if not. + static bool Initialise(); + /// Destroys the specification structure and releases the parsers. + static void Shutdown(); + + /// Registers a parser for use in property definitions. + /// @param[in] parser_name The name to register the new parser under. + /// @param[in] parser A non-owning pointer to the parser to register. + /// @return True if the parser was registered successfully, false otherwise. + /// @lifetime The parser must be kept alive until after the call to Rml::Shutdown. + static bool RegisterParser(const String& parser_name, PropertyParser* parser); + /// Returns the parser registered with a specific name. + /// @param[in] parser_name The name of the desired parser. + /// @return The parser registered under the given name, or nullptr if no such parser exists. + static PropertyParser* GetParser(const String& parser_name); + + /// Registers a custom property with a new definition. + /// @param[in] property_name The name to register the new property under. + /// @param[in] default_value The default value to be used for an element if it has no other definition provided. + /// @param[in] inherited True if this property is inherited from parent to child, false otherwise. + /// @param[in] forces_layout True if a change in this property on an element will cause the element's layout to possibly change. + /// @return The new property definition, ready to have parsers attached. + static PropertyDefinition& RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout = false); + /// Returns a property definition. + /// @param[in] property_name The name of the desired property. + /// @return The appropriate property definition if it could be found, nullptr otherwise. + static const PropertyDefinition* GetProperty(const String& property_name); + static const PropertyDefinition* GetProperty(PropertyId id); + + /// Returns the id set of all registered property definitions. + static const PropertyIdSet& GetRegisteredProperties(); + /// Returns the id set of all registered inherited property definitions. + static const PropertyIdSet& GetRegisteredInheritedProperties(); + /// Returns the id set of all registered property definitions that may dirty the layout. + static const PropertyIdSet& GetRegisteredPropertiesForcingLayout(); + + /// Registers a custom shorthand property definition. + /// @param[in] shorthand_name The name to register the new shorthand property under. + /// @param[in] properties A comma-separated list of the properties this definition is shorthand for. The order in which they are specified here is the order in which the values will be processed. + /// @param[in] type The type of shorthand to declare. + /// @param True if all the property names exist, false otherwise. + static ShorthandId RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type); + /// Returns a shorthand definition. + /// @param[in] shorthand_name The name of the desired shorthand. + /// @return The appropriate shorthand definition if it could be found, nullptr otherwise. + static const ShorthandDefinition* GetShorthand(const String& shorthand_name); + static const ShorthandDefinition* GetShorthand(ShorthandId id); + + /// Parses a property declaration, setting any parsed and validated properties on the given dictionary. + /// @param[in] dictionary The property dictionary which will hold all declared properties. + /// @param[in] property_name The name of the declared property. + /// @param[in] property_value The values the property is being set to. + /// @param[in] source_file The file where this property was declared. Used for error reporting, debugging and relative paths for referenced assets. + /// @param[in] line_number The location of the source file where this property was declared. Used for error reporting and debugging. + /// @return True if all properties were parsed successfully, false otherwise. + static bool ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value); + + static PropertyId GetPropertyId(const String& property_name); + static ShorthandId GetShorthandId(const String& shorthand_name); + static const String& GetPropertyName(PropertyId id); + static const String& GetShorthandName(ShorthandId id); + + // Get the underlying property ids associated by a shorthand. + static PropertyIdSet GetShorthandUnderlyingProperties(ShorthandId id); + + static const PropertySpecification& GetPropertySpecification(); + +private: + StyleSheetSpecification(); + ~StyleSheetSpecification(); + + PropertyDefinition& RegisterProperty(PropertyId id, const String& property_name, const String& default_value, bool inherited, bool forces_layout = false); + ShorthandId RegisterShorthand(ShorthandId id, const String& shorthand_name, const String& property_names, ShorthandType type); + + // Registers RmlUi's default parsers. + void RegisterDefaultParsers(); + // Registers RmlUi's default style properties. + void RegisterDefaultProperties(); + + // Parsers used by all property definitions. + typedef UnorderedMap< String, PropertyParser* > ParserMap; + ParserMap parsers; + + // The properties defined in the style sheet specification. + PropertySpecification properties; + + UniquePtr default_parsers; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/SystemInterface.h b/thirdparty/RmlUi/Include/RmlUi/Core/SystemInterface.h new file mode 100644 index 000000000..c3f39730b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/SystemInterface.h @@ -0,0 +1,102 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_SYSTEMINTERFACE_H +#define RMLUI_CORE_SYSTEMINTERFACE_H + +#include "Types.h" +#include "Log.h" +#include "Traits.h" +#include "Header.h" + +namespace Rml { + +/** + RmlUi's System Interface. + + This class provides interfaces for Time, Translation and Logging. + + Time is the only required implementation. + + The default implemention of Translation doesn't translate anything + + The default implementation of logging logs Windows Debug Console, + or Standard Error, depending on what platform you're using. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API SystemInterface : public NonCopyMoveable +{ +public: + SystemInterface(); + virtual ~SystemInterface(); + + /// Get the number of seconds elapsed since the start of the application. + /// @return Elapsed time, in seconds. + virtual double GetElapsedTime() = 0; + + /// Translate the input string into the translated string. + /// @param[out] translated Translated string ready for display. + /// @param[in] input String as received from XML. + /// @return Number of translations that occured. + virtual int TranslateString(String& translated, const String& input); + + /// Joins the path of an RML or RCSS file with the path of a resource specified within the file. + /// @param[out] translated_path The joined path. + /// @param[in] document_path The path of the source document (including the file name). + /// @param[in] path The path of the resource specified in the document. + virtual void JoinPath(String& translated_path, const String& document_path, const String& path); + + /// Log the specified message. + /// @param[in] type Type of log message, ERROR, WARNING, etc. + /// @param[in] message Message to log. + /// @return True to continue execution, false to break into the debugger. + virtual bool LogMessage(Log::Type type, const String& message); + + /// Set mouse cursor. + /// @param[in] cursor_name Cursor name to activate. + virtual void SetMouseCursor(const String& cursor_name); + + /// Set clipboard text. + /// @param[in] text Text to apply to clipboard. + virtual void SetClipboardText(const String& text); + + /// Get clipboard text. + /// @param[out] text Retrieved text from clipboard. + virtual void GetClipboardText(String& text); + + /// Activate keyboard (for touchscreen devices) + virtual void ActivateKeyboard(); + + /// Deactivate keyboard (for touchscreen devices) + virtual void DeactivateKeyboard(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Texture.h b/thirdparty/RmlUi/Include/RmlUi/Core/Texture.h new file mode 100644 index 000000000..1badca609 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Texture.h @@ -0,0 +1,92 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TEXTURE_H +#define RMLUI_CORE_TEXTURE_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +class TextureResource; +class RenderInterface; + +/* + Callback function for generating textures. + /// @param[in] name The name used to set the texture. + /// @param[out] data The raw data of the texture, each pixel has four 8-bit channels: red-green-blue-alpha. + /// @param[out] dimensions The width and height of the generated texture. + /// @return True on success. +*/ +using TextureCallback = Function& data, Vector2i& dimensions)>; + + +/** + Abstraction of a two-dimensional texture image, with an application-specific texture handle. + + @author Peter Curry + */ + +struct RMLUICORE_API Texture +{ +public: + /// Set the texture source and path. The texture is added to the global cache and only loaded on first use. + /// @param[in] source The source of the texture. + /// @param[in] source_path The path of the resource that is requesting the texture (ie, the RCSS file in which it was specified, etc). + void Set(const String& source, const String& source_path = ""); + + /// Set a callback function for generating the texture on first use. The texture is never added to the global cache. + /// @param[in] name The name of the texture. + /// @param[in] callback The callback function which generates the data of the texture, see TextureCallback. + void Set(const String& name, const TextureCallback& callback); + + /// Returns the texture's source name. This is usually the name of the file the texture was loaded from. + /// @return The name of the this texture's source. This will be the empty string if this texture is not loaded. + const String& GetSource() const; + /// Returns the texture's handle. + /// @param[in] The render interface that is requesting the handle. + /// @return The texture's handle. This will be nullptr if the texture isn't loaded. + TextureHandle GetHandle(RenderInterface* render_interface) const; + /// Returns the texture's dimensions. + /// @param[in] The render interface that is requesting the dimensions. + /// @return The texture's dimensions. This will be (0, 0) if the texture isn't loaded. + Vector2i GetDimensions(RenderInterface* render_interface) const; + + /// Returns true if the texture points to the same underlying resource. + bool operator==(const Texture&) const; + + /// Returns true if the underlying resource is set. + explicit operator bool() const; + +private: + SharedPtr resource; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Traits.h b/thirdparty/RmlUi/Include/RmlUi/Core/Traits.h new file mode 100644 index 000000000..1e8013f80 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Traits.h @@ -0,0 +1,161 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TRAITS_H +#define RMLUI_CORE_TRAITS_H + +#include "Header.h" +#include "../Config/Config.h" +#include + +namespace Rml { + +class RMLUICORE_API NonCopyMoveable { +public: + NonCopyMoveable() {} + ~NonCopyMoveable() {} + NonCopyMoveable(const NonCopyMoveable&) = delete; + NonCopyMoveable& operator=(const NonCopyMoveable&) = delete; + NonCopyMoveable(NonCopyMoveable&&) = delete; + NonCopyMoveable& operator=(NonCopyMoveable&&) = delete; +}; + + +class ReleaserBase; + +class RMLUICORE_API Releasable : public NonCopyMoveable { +protected: + virtual ~Releasable() = default; + virtual void Release() = 0; + friend class ReleaserBase; +}; + +class RMLUICORE_API ReleaserBase { +protected: + void Release(Releasable* target) const { + target->Release(); + } +}; + +template +class RMLUICORE_API Releaser : public ReleaserBase { +public: + void operator()(T* target) const { + static_assert(std::is_base_of::value, "Rml::Releaser can only operate with classes derived from ::Rml::Releasable."); + Release(static_cast(target)); + } +}; + + +enum class FamilyId : int {}; + +class RMLUICORE_API FamilyBase { +protected: + static int GetNewId() { + static int id = 0; + return id++; + } + template + static FamilyId GetId() { + static int id = GetNewId(); + return static_cast(id); + } +}; + +template +class Family : FamilyBase { +public: + // Get a unique ID for a given type. + // Note: IDs will be unique across DLL-boundaries even for the same type. + static FamilyId Id() { + return GetId< typename std::remove_cv< typename std::remove_reference< T >::type >::type >(); + } +}; + +} // namespace Rml + + + +#ifdef RMLUI_USE_CUSTOM_RTTI + +#define RMLUI_RTTI_Define( _NAME_ ) \ + using RttiClassType = _NAME_; \ + static void* GetStaticClassIdentifier() { static int dummy; return &dummy; } \ + virtual bool IsClass(void * type_identifier) const { return type_identifier == GetStaticClassIdentifier(); } + +#define RMLUI_RTTI_DefineWithParent( _NAME_, _PARENT_ ) \ + using RttiClassType = _NAME_; \ + static void* GetStaticClassIdentifier() { static int dummy; return &dummy; } \ + bool IsClass(void * type_identifier) const override { \ + static_assert(std::is_same::value, "Parent does not implement RMLUI_RTTI_Define or RMLUI_RTTI_DefineWithParent");\ + return type_identifier == GetStaticClassIdentifier() || _PARENT_::IsClass(type_identifier);\ + } + +template +Derived rmlui_dynamic_cast(Base base_instance) +{ + static_assert(std::is_pointer::value && std::is_pointer::value, "rmlui_dynamic_cast can only cast pointer types"); + using T_Derived = typename std::remove_cv::type>::type; + + static_assert(std::is_same::value, "Derived type does not implement RMLUI_RTTI_DefineWithParent"); + + if (base_instance->IsClass(T_Derived::GetStaticClassIdentifier())) + return static_cast(base_instance); + else + return nullptr; +} + +template +const char* rmlui_type_name(const T& /*var*/) +{ + return "(type name unavailable)"; +} + +#else + +#include + +#define RMLUI_RTTI_Define(_NAME_) +#define RMLUI_RTTI_DefineWithParent(_NAME_, _PARENT_) + +template +Derived rmlui_dynamic_cast(Base base_instance) +{ + static_assert(std::is_pointer::value && std::is_pointer::value, "rmlui_dynamic_cast can only cast pointer types"); + return dynamic_cast(base_instance); +} + +template +const char* rmlui_type_name(const T& var) +{ + return typeid(var).name(); +} + +#endif // RMLUI_USE_CUSTOM_RTTI + +#endif // RMLUI_CORE_TRAITS_H diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Transform.h b/thirdparty/RmlUi/Include/RmlUi/Core/Transform.h new file mode 100644 index 000000000..b2f3a9c0f --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Transform.h @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TRANSFORM_H +#define RMLUI_CORE_TRANSFORM_H + +#include "Header.h" +#include "Types.h" +#include "TransformPrimitive.h" + +namespace Rml { + +class Property; + +/** + The Transform class holds the information parsed from an element's `transform' property. + + The class holds a list of transform primitives making up a complete transformation specification + of an element. Each transform instance is relative to the element's parent coordinate system. + During the Context::Render call the transforms of the current element and its ancestors will be + used to find the final transformation matrix for the global coordinate system. + + @author Markus Schöngart + @see Rml::Variant + */ + +class RMLUICORE_API Transform +{ +public: + using PrimitiveList = Vector< TransformPrimitive >; + + /// Default constructor, initializes an identity transform + Transform(); + + /// Construct transform with a list of primitives + Transform(PrimitiveList primitives); + + /// Helper function to create a 'transform' Property from the given list of primitives + static Property MakeProperty(PrimitiveList primitives); + + /// Remove all Primitives from this Transform + void ClearPrimitives(); + + /// Add a Primitive to this Transform + void AddPrimitive(const TransformPrimitive& p); + + /// Return the number of Primitives in this Transform + int GetNumPrimitives() const noexcept; + + /// Return the i-th Primitive in this Transform + const TransformPrimitive& GetPrimitive(int i) const noexcept; + + PrimitiveList& GetPrimitives() noexcept { return primitives; } + const PrimitiveList& GetPrimitives() const noexcept { return primitives; } + +private: + PrimitiveList primitives; +}; + + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/TransformPrimitive.h b/thirdparty/RmlUi/Include/RmlUi/Core/TransformPrimitive.h new file mode 100644 index 000000000..c594a4cea --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/TransformPrimitive.h @@ -0,0 +1,283 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TRANSFORMPRIMITIVE_H +#define RMLUI_CORE_TRANSFORMPRIMITIVE_H + +#include "Header.h" +#include "Types.h" +#include "Property.h" + +namespace Rml { +namespace Transforms { + +struct RMLUICORE_API NumericValue { + NumericValue() noexcept : number(0.f), unit(Property::UNKNOWN) {} + NumericValue(float number, Property::Unit unit) noexcept : number(number), unit(unit) {} + + float number; + Property::Unit unit; +}; + +// A resolved primitive has values that are always independent of an element's properties or layout. +template< size_t N > +struct RMLUICORE_API ResolvedPrimitive +{ + Array values; + +protected: + ResolvedPrimitive(const float* values) noexcept; + ResolvedPrimitive(const NumericValue* values) noexcept; + ResolvedPrimitive(const NumericValue* values, Array base_units) noexcept; + ResolvedPrimitive(Array values, Array base_units) noexcept; + ResolvedPrimitive(Array values) noexcept; +}; + +// An unresolved primitive may have values that depend on the final layout of a given element, such as its width. +template< size_t N > +struct RMLUICORE_API UnresolvedPrimitive +{ + Array values; + +protected: + UnresolvedPrimitive(const NumericValue* values) noexcept; + UnresolvedPrimitive(Array values) noexcept; +}; + + +struct RMLUICORE_API Matrix2D : public ResolvedPrimitive< 6 > +{ + Matrix2D(const NumericValue* values) noexcept; +}; + +struct RMLUICORE_API Matrix3D : public ResolvedPrimitive< 16 > +{ + Matrix3D(const NumericValue* values) noexcept; + Matrix3D(const Matrix4f& matrix) noexcept; +}; + +struct RMLUICORE_API TranslateX : public UnresolvedPrimitive< 1 > +{ + TranslateX(const NumericValue* values) noexcept; + TranslateX(float x, Property::Unit unit = Property::PX) noexcept; +}; + +struct RMLUICORE_API TranslateY : public UnresolvedPrimitive< 1 > +{ + TranslateY(const NumericValue* values) noexcept; + TranslateY(float y, Property::Unit unit = Property::PX) noexcept; +}; + +struct RMLUICORE_API TranslateZ : public UnresolvedPrimitive< 1 > +{ + TranslateZ(const NumericValue* values) noexcept; + TranslateZ(float z, Property::Unit unit = Property::PX) noexcept; +}; + +struct RMLUICORE_API Translate2D : public UnresolvedPrimitive< 2 > +{ + Translate2D(const NumericValue* values) noexcept; + Translate2D(float x, float y, Property::Unit units = Property::PX) noexcept; +}; + +struct RMLUICORE_API Translate3D : public UnresolvedPrimitive< 3 > +{ + Translate3D(const NumericValue* values) noexcept; + Translate3D(NumericValue x, NumericValue y, NumericValue z) noexcept; + Translate3D(float x, float y, float z, Property::Unit units = Property::PX) noexcept; +}; + +struct RMLUICORE_API ScaleX : public ResolvedPrimitive< 1 > +{ + ScaleX(const NumericValue* values) noexcept; + ScaleX(float value) noexcept; +}; + +struct RMLUICORE_API ScaleY : public ResolvedPrimitive< 1 > +{ + ScaleY(const NumericValue* values) noexcept; + ScaleY(float value) noexcept; +}; + +struct RMLUICORE_API ScaleZ : public ResolvedPrimitive< 1 > +{ + ScaleZ(const NumericValue* values) noexcept; + ScaleZ(float value) noexcept; +}; + +struct RMLUICORE_API Scale2D : public ResolvedPrimitive< 2 > +{ + Scale2D(const NumericValue* values) noexcept; + Scale2D(float xy) noexcept; + Scale2D(float x, float y) noexcept; +}; + +struct RMLUICORE_API Scale3D : public ResolvedPrimitive< 3 > +{ + Scale3D(const NumericValue* values) noexcept; + Scale3D(float xyz) noexcept; + Scale3D(float x, float y, float z) noexcept; +}; + +struct RMLUICORE_API RotateX : public ResolvedPrimitive< 1 > +{ + RotateX(const NumericValue* values) noexcept; + RotateX(float angle, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API RotateY : public ResolvedPrimitive< 1 > +{ + RotateY(const NumericValue* values) noexcept; + RotateY(float angle, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API RotateZ : public ResolvedPrimitive< 1 > +{ + RotateZ(const NumericValue* values) noexcept; + RotateZ(float angle, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API Rotate2D : public ResolvedPrimitive< 1 > +{ + Rotate2D(const NumericValue* values) noexcept; + Rotate2D(float angle, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API Rotate3D : public ResolvedPrimitive< 4 > +{ + Rotate3D(const NumericValue* values) noexcept; + Rotate3D(float x, float y, float z, float angle, Property::Unit angle_unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API SkewX : public ResolvedPrimitive< 1 > +{ + SkewX(const NumericValue* values) noexcept; + SkewX(float angle, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API SkewY : public ResolvedPrimitive< 1 > +{ + SkewY(const NumericValue* values) noexcept; + SkewY(float angle, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API Skew2D : public ResolvedPrimitive< 2 > +{ + Skew2D(const NumericValue* values) noexcept; + Skew2D(float x, float y, Property::Unit unit = Property::DEG) noexcept; +}; + +struct RMLUICORE_API Perspective : public UnresolvedPrimitive< 1 > +{ + Perspective(const NumericValue* values) noexcept; +}; + +struct RMLUICORE_API DecomposedMatrix4 { + Vector4f perspective; + Vector4f quaternion; + Vector3f translation; + Vector3f scale; + Vector3f skew; +}; + +} // namespace Transforms + + +/** + The TransformPrimitive struct is the base struct of geometric transforms such as rotations, scalings and translations. + Instances of this struct are added to Rml::Transform during parsing of the 'transform' property. + + @author Markus Schöngart + @see Rml::Transform + @see Rml::PropertyParserTransform + */ +struct RMLUICORE_API TransformPrimitive { + + enum Type { + MATRIX2D, MATRIX3D, + TRANSLATEX, TRANSLATEY, TRANSLATEZ, TRANSLATE2D, TRANSLATE3D, + SCALEX, SCALEY, SCALEZ, SCALE2D, SCALE3D, + ROTATEX, ROTATEY, ROTATEZ, ROTATE2D, ROTATE3D, + SKEWX, SKEWY, SKEW2D, + PERSPECTIVE, DECOMPOSEDMATRIX4 + }; + + TransformPrimitive(Transforms::Matrix2D p) : type(MATRIX2D) { matrix_2d = p; } + TransformPrimitive(Transforms::Matrix3D p) : type(MATRIX3D) { matrix_3d = p; } + TransformPrimitive(Transforms::TranslateX p) : type(TRANSLATEX) { translate_x = p; } + TransformPrimitive(Transforms::TranslateY p) : type(TRANSLATEY) { translate_y = p; } + TransformPrimitive(Transforms::TranslateZ p) : type(TRANSLATEZ) { translate_z = p; } + TransformPrimitive(Transforms::Translate2D p) : type(TRANSLATE2D) { translate_2d = p; } + TransformPrimitive(Transforms::Translate3D p) : type(TRANSLATE3D) { translate_3d = p; } + TransformPrimitive(Transforms::ScaleX p) : type(SCALEX) { scale_x = p; } + TransformPrimitive(Transforms::ScaleY p) : type(SCALEY) { scale_y = p; } + TransformPrimitive(Transforms::ScaleZ p) : type(SCALEZ) { scale_z = p; } + TransformPrimitive(Transforms::Scale2D p) : type(SCALE2D) { scale_2d = p; } + TransformPrimitive(Transforms::Scale3D p) : type(SCALE3D) { scale_3d = p; } + TransformPrimitive(Transforms::RotateX p) : type(ROTATEX) { rotate_x = p; } + TransformPrimitive(Transforms::RotateY p) : type(ROTATEY) { rotate_y = p; } + TransformPrimitive(Transforms::RotateZ p) : type(ROTATEZ) { rotate_z = p; } + TransformPrimitive(Transforms::Rotate2D p) : type(ROTATE2D) { rotate_2d = p; } + TransformPrimitive(Transforms::Rotate3D p) : type(ROTATE3D) { rotate_3d = p; } + TransformPrimitive(Transforms::SkewX p) : type(SKEWX) { skew_x = p; } + TransformPrimitive(Transforms::SkewY p) : type(SKEWY) { skew_y = p; } + TransformPrimitive(Transforms::Skew2D p) : type(SKEW2D) { skew_2d = p; } + TransformPrimitive(Transforms::Perspective p) : type(PERSPECTIVE) { perspective = p; } + TransformPrimitive(Transforms::DecomposedMatrix4 p) : type(DECOMPOSEDMATRIX4) { decomposed_matrix_4 = p; } + + Type type; + + union { + Transforms::Matrix2D matrix_2d; + Transforms::Matrix3D matrix_3d; + Transforms::TranslateX translate_x; + Transforms::TranslateY translate_y; + Transforms::TranslateZ translate_z; + Transforms::Translate2D translate_2d; + Transforms::Translate3D translate_3d; + Transforms::ScaleX scale_x; + Transforms::ScaleY scale_y; + Transforms::ScaleZ scale_z; + Transforms::Scale2D scale_2d; + Transforms::Scale3D scale_3d; + Transforms::RotateX rotate_x; + Transforms::RotateY rotate_y; + Transforms::RotateZ rotate_z; + Transforms::Rotate2D rotate_2d; + Transforms::Rotate3D rotate_3d; + Transforms::SkewX skew_x; + Transforms::SkewY skew_y; + Transforms::Skew2D skew_2d; + Transforms::Perspective perspective; + Transforms::DecomposedMatrix4 decomposed_matrix_4; + }; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Tween.h b/thirdparty/RmlUi/Include/RmlUi/Core/Tween.h new file mode 100644 index 000000000..087c37ba1 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Tween.h @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TWEEN_H +#define RMLUI_CORE_TWEEN_H + +#include "Types.h" +#include "Header.h" + +namespace Rml { + +class RMLUICORE_API Tween { +public: + enum Type { None, Back, Bounce, Circular, Cubic, Elastic, Exponential, Linear, Quadratic, Quartic, Quintic, Sine, Callback, Count }; + enum Direction { In = 1, Out = 2, InOut = 3 }; + using CallbackFnc = float(*)(float); + + Tween(Type type = Linear, Direction direction = Out); + Tween(Type type_in, Type type_out); + Tween(CallbackFnc callback, Direction direction = In); + + // Evaluate the Tweening function at point t in [0, 1]. + float operator()(float t) const; + + // Reverse direction of the tweening function. + void reverse(); + + bool operator==(const Tween& other) const; + bool operator!=(const Tween& other) const; + + String to_string() const; + +private: + float tween(Type type, float t) const; + float in(float t) const; + float out(float t) const; + float in_out(float t) const; + + Type type_in = None; + Type type_out = None; + CallbackFnc callback = nullptr; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/TypeConverter.h b/thirdparty/RmlUi/Include/RmlUi/Core/TypeConverter.h new file mode 100644 index 000000000..c5fe61bc8 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/TypeConverter.h @@ -0,0 +1,125 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TYPECONVERTER_H +#define RMLUI_CORE_TYPECONVERTER_H + +#include "Platform.h" +#include "Types.h" +#include "Log.h" +#include "StringUtilities.h" +#include +#include +#include + +namespace Rml { + +/** + Templatised TypeConverters with Template Specialisation. + + These converters convert from source types to destination types. + They're mainly useful in things like dictionaries and serialisers. + + @author Lloyd Weehuizen + */ + +template +class TypeConverter +{ +public: + static bool Convert(const SourceType& src, DestType& dest); +}; + +template +inline String ToString(const T& value, String default_value = String()) { + String result = default_value; + TypeConverter::Convert(value, result); + return result; +} + +template +inline T FromString(const String& string, T default_value = T()) { + T result = default_value; + TypeConverter::Convert(string, result); + return result; +} + + +// Some more complex types are defined in cpp-file + +template<> class TypeConverter< TransformPtr, TransformPtr > { +public: + RMLUICORE_API static bool Convert(const TransformPtr& src, TransformPtr& dest); +}; + +template<> class TypeConverter< TransformPtr, String > { +public: + RMLUICORE_API static bool Convert(const TransformPtr& src, String& dest); +}; + +template<> class TypeConverter< TransitionList, TransitionList > { +public: + RMLUICORE_API static bool Convert(const TransitionList& src, TransitionList& dest); +}; +template<> class TypeConverter< TransitionList, String > { +public: + RMLUICORE_API static bool Convert(const TransitionList& src, String& dest); +}; + +template<> class TypeConverter< AnimationList, AnimationList > { +public: + RMLUICORE_API static bool Convert(const AnimationList& src, AnimationList& dest); +}; +template<> class TypeConverter< AnimationList, String > { +public: + RMLUICORE_API static bool Convert(const AnimationList& src, String& dest); +}; + +template<> class TypeConverter< DecoratorsPtr, DecoratorsPtr > { +public: + RMLUICORE_API static bool Convert(const DecoratorsPtr& src, DecoratorsPtr& dest); +}; +template<> class TypeConverter< DecoratorsPtr, String > { +public: + RMLUICORE_API static bool Convert(const DecoratorsPtr& src, String& dest); +}; + +template<> class TypeConverter< FontEffectsPtr, FontEffectsPtr> { +public: + RMLUICORE_API static bool Convert(const FontEffectsPtr& src, FontEffectsPtr& dest); +}; +template<> class TypeConverter< FontEffectsPtr, String > { +public: + RMLUICORE_API static bool Convert(const FontEffectsPtr& src, String& dest); +}; + +} // namespace Rml + +#include "TypeConverter.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/TypeConverter.inl b/thirdparty/RmlUi/Include/RmlUi/Core/TypeConverter.inl new file mode 100644 index 000000000..0d73f76c8 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/TypeConverter.inl @@ -0,0 +1,380 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { + +template +bool TypeConverter::Convert(const SourceType& /*src*/, DestType& /*dest*/) +{ + RMLUI_ERRORMSG("No converter specified."); + return false; +} + +/// +/// Full Specialisations +/// + +#define BASIC_CONVERTER(s, d) \ +template<> \ +class TypeConverter< s, d > \ +{ \ +public: \ + static bool Convert(const s& src, d& dest) \ + { \ + dest = (d)src; \ + return true; \ + } \ +} + +#define BASIC_CONVERTER_BOOL(s, d) \ +template<> \ +class TypeConverter< s, d > \ +{ \ +public: \ + static bool Convert(const s& src, d& dest) \ + { \ + dest = src != 0; \ + return true; \ + } \ +} + +#define PASS_THROUGH(t) BASIC_CONVERTER(t, t) + +///////////////////////////////////////////////// +// Simple pass through definitions for converting +// to the same type (direct copy) +///////////////////////////////////////////////// +PASS_THROUGH(int); +PASS_THROUGH(unsigned int); +PASS_THROUGH(int64_t); +PASS_THROUGH(float); +PASS_THROUGH(double); +PASS_THROUGH(bool); +PASS_THROUGH(char); +PASS_THROUGH(Character); +PASS_THROUGH(Vector2i); +PASS_THROUGH(Vector2f); +PASS_THROUGH(Vector3i); +PASS_THROUGH(Vector3f); +PASS_THROUGH(Vector4i); +PASS_THROUGH(Vector4f); +PASS_THROUGH(Colourf); +PASS_THROUGH(Colourb); +PASS_THROUGH(String); + +// Pointer types need to be typedef'd +class ScriptInterface; +typedef ScriptInterface* ScriptInterfacePtr; +PASS_THROUGH(ScriptInterfacePtr); +typedef void* voidPtr; +PASS_THROUGH(voidPtr); + +///////////////////////////////////////////////// +// Simple Types +///////////////////////////////////////////////// +BASIC_CONVERTER(bool, int); +BASIC_CONVERTER(bool, unsigned int); +BASIC_CONVERTER(bool, int64_t); +BASIC_CONVERTER(bool, float); +BASIC_CONVERTER(bool, double); + +BASIC_CONVERTER_BOOL(int, bool); +BASIC_CONVERTER(int, unsigned int); +BASIC_CONVERTER(int, int64_t); +BASIC_CONVERTER(int, float); +BASIC_CONVERTER(int, double); + +BASIC_CONVERTER_BOOL(int64_t, bool); +BASIC_CONVERTER(int64_t, int); +BASIC_CONVERTER(int64_t, float); +BASIC_CONVERTER(int64_t, double); +BASIC_CONVERTER(int64_t, unsigned int); + +BASIC_CONVERTER_BOOL(float, bool); +BASIC_CONVERTER(float, int); +BASIC_CONVERTER(float, int64_t); +BASIC_CONVERTER(float, double); +BASIC_CONVERTER(float, unsigned int); + +BASIC_CONVERTER_BOOL(double, bool); +BASIC_CONVERTER(double, int); +BASIC_CONVERTER(double, int64_t); +BASIC_CONVERTER(double, float); +BASIC_CONVERTER(double, unsigned int); + +BASIC_CONVERTER(char, Character); + +///////////////////////////////////////////////// +// From string converters +///////////////////////////////////////////////// + +#define STRING_FLOAT_CONVERTER(type) \ +template<> \ +class TypeConverter< String, type > \ +{ \ +public: \ + static bool Convert(const String& src, type& dest) \ + { \ + dest = (type) atof(src.c_str()); \ + return true; \ + } \ +} +STRING_FLOAT_CONVERTER(float); +STRING_FLOAT_CONVERTER(double); + +template<> +class TypeConverter< String, int > +{ +public: + static bool Convert(const String& src, int& dest) + { + return sscanf(src.c_str(), "%d", &dest) == 1; + } +}; + +template<> +class TypeConverter< String, unsigned int > +{ +public: + static bool Convert(const String& src, unsigned int& dest) + { + return sscanf(src.c_str(), "%u", &dest) == 1; + } +}; + +template<> +class TypeConverter< String, int64_t > +{ +public: + static bool Convert(const String& src, int64_t& dest) + { + return sscanf(src.c_str(), "%" SCNd64, &dest) == 1; + } +}; + +template<> +class TypeConverter< String, byte > +{ +public: + static bool Convert(const String& src, byte& dest) + { + return sscanf(src.c_str(), "%hhu", &dest) == 1; + } +}; + +template<> +class TypeConverter< String, bool > +{ +public: + static bool Convert(const String& src, bool& dest) + { + String lower = StringUtilities::ToLower(src); + if (lower == "1" || lower == "true") + { + dest = true; + return true; + } + else if (lower == "0" || lower == "false") + { + dest = false; + return true; + } + return false; + } +}; + +template< typename DestType, typename InternalType, int count > +class TypeConverterStringVector +{ +public: + static bool Convert(const String& src, DestType& dest) + { + StringList string_list; + StringUtilities::ExpandString(string_list, src); + if (string_list.size() < count) + return false; + for (int i = 0; i < count; i++) + { + if (!TypeConverter< String, InternalType >::Convert(string_list[i], dest[i])) + return false; + } + return true; + } +}; + +#define STRING_VECTOR_CONVERTER(type, internal_type, count) \ +template<> \ +class TypeConverter< String, type > \ +{ \ +public: \ + static bool Convert(const String& src, type& dest) \ + { \ + return TypeConverterStringVector< type, internal_type, count >::Convert(src, dest); \ + } \ +} + +STRING_VECTOR_CONVERTER(Vector2i, int, 2); +STRING_VECTOR_CONVERTER(Vector2f, float, 2); +STRING_VECTOR_CONVERTER(Vector3i, int, 3); +STRING_VECTOR_CONVERTER(Vector3f, float, 3); +STRING_VECTOR_CONVERTER(Vector4i, int, 4); +STRING_VECTOR_CONVERTER(Vector4f, float, 4); +STRING_VECTOR_CONVERTER(Colourf, float, 4); +STRING_VECTOR_CONVERTER(Colourb, byte, 4); + +///////////////////////////////////////////////// +// To String Converters +///////////////////////////////////////////////// + +#define FLOAT_STRING_CONVERTER(type) \ +template<> \ +class TypeConverter< type, String > \ +{ \ +public: \ + static bool Convert(const type& src, String& dest) \ + { \ + if(FormatString(dest, 32, "%.3f", src) == 0) \ + return false; \ + StringUtilities::TrimTrailingDotZeros(dest); \ + return true; \ + } \ +} +FLOAT_STRING_CONVERTER(float); +FLOAT_STRING_CONVERTER(double); + +template<> +class TypeConverter< int, String > +{ +public: + static bool Convert(const int& src, String& dest) + { + return FormatString(dest, 32, "%d", src) > 0; + } +}; + +template<> +class TypeConverter< unsigned int, String > +{ +public: + static bool Convert(const unsigned int& src, String& dest) + { + return FormatString(dest, 32, "%u", src) > 0; + } +}; + +template<> +class TypeConverter< int64_t, String > +{ +public: + static bool Convert(const int64_t& src, String& dest) + { + return FormatString(dest, 32, "%" PRId64, src) > 0; + } +}; + +template<> +class TypeConverter< byte, String > +{ +public: + static bool Convert(const byte& src, String& dest) + { + return FormatString(dest, 32, "%hhu", src) > 0; + } +}; + +template<> +class TypeConverter< bool, String > +{ +public: + static bool Convert(const bool& src, String& dest) + { + dest = src ? "1" : "0"; + return true; + } +}; + +template<> +class TypeConverter< char*, String > +{ +public: + static bool Convert(char* const & src, String& dest) + { + dest = src; + return true; + } +}; + +template< typename SourceType, typename InternalType, int count > +class TypeConverterVectorString +{ +public: + static bool Convert(const SourceType& src, String& dest) + { + dest = ""; + for (int i = 0; i < count; i++) + { + String value; + if (!TypeConverter< InternalType, String >::Convert(src[i], value)) + return false; + + dest += value; + if (i < count - 1) + dest += ", "; + } + return true; + } +}; + +#define VECTOR_STRING_CONVERTER(type, internal_type, count) \ +template<> \ +class TypeConverter< type, String > \ +{ \ +public: \ + static bool Convert(const type& src, String& dest) \ + { \ + return TypeConverterVectorString< type, internal_type, count >::Convert(src, dest); \ + } \ +} + +VECTOR_STRING_CONVERTER(Vector2i, int, 2); +VECTOR_STRING_CONVERTER(Vector2f, float, 2); +VECTOR_STRING_CONVERTER(Vector3i, int, 3); +VECTOR_STRING_CONVERTER(Vector3f, float, 3); +VECTOR_STRING_CONVERTER(Vector4i, int, 4); +VECTOR_STRING_CONVERTER(Vector4f, float, 4); +VECTOR_STRING_CONVERTER(Colourf, float, 4); +VECTOR_STRING_CONVERTER(Colourb, byte, 4); +#undef PASS_THROUGH +#undef BASIC_CONVERTER +#undef BASIC_CONVERTER_BOOL +#undef FLOAT_STRING_CONVERTER +#undef STRING_FLOAT_CONVERTER +#undef STRING_VECTOR_CONVERTER +#undef VECTOR_STRING_CONVERTER + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Types.h b/thirdparty/RmlUi/Include/RmlUi/Core/Types.h new file mode 100644 index 000000000..50f0183e7 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Types.h @@ -0,0 +1,162 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TYPES_H +#define RMLUI_CORE_TYPES_H + +#include "../Config/Config.h" + +#include +#include + +#include "Traits.h" + +namespace Rml { + +// Commonly used basic types +using byte = unsigned char; +using ScriptObject = void*; +using std::size_t; + +// Unicode code point +enum class Character : char32_t { Null, Replacement = 0xfffd }; + +} + +#include "Colour.h" +#include "Vector2.h" +#include "Vector3.h" +#include "Vector4.h" +#include "Matrix4.h" +#include "ObserverPtr.h" + +namespace Rml { + +// Color and linear algebra +using Colourf = Colour< float, 1 >; +using Colourb = Colour< byte, 255 >; +using Vector2i = Vector2< int >; +using Vector2f = Vector2< float >; +using Vector3i = Vector3< int >; +using Vector3f = Vector3< float >; +using Vector4i = Vector4< int >; +using Vector4f = Vector4< float >; +using ColumnMajorMatrix4f = Matrix4< float, ColumnMajorStorage< float > >; +using RowMajorMatrix4f = Matrix4< float, RowMajorStorage< float > >; +using Matrix4f = RMLUI_MATRIX4_TYPE; + +// Common classes +class Element; +class ElementInstancer; +class ElementAnimation; +class Context; +class Event; +class Property; +class Variant; +class Transform; +class PropertyIdSet; +class Decorator; +class FontEffect; +struct Animation; +struct Transition; +struct TransitionList; +struct Rectangle; +enum class EventId : uint16_t; +enum class PropertyId : uint8_t; +enum class FamilyId : int; + +// Types for external interfaces. +using FileHandle = uintptr_t; +using TextureHandle = uintptr_t; +using CompiledGeometryHandle = uintptr_t; +using DecoratorDataHandle = uintptr_t; +using FontFaceHandle = uintptr_t; +using FontEffectsHandle = uintptr_t; + +using ElementPtr = UniqueReleaserPtr; +using ContextPtr = UniqueReleaserPtr; +using EventPtr = UniqueReleaserPtr; + +// Container types for common classes +using ElementList = Vector< Element* >; +using OwnedElementList = Vector< ElementPtr >; +using VariantList = Vector< Variant >; +using ElementAnimationList = Vector< ElementAnimation >; + +using PseudoClassList = SmallUnorderedSet< String >; +using AttributeNameList = SmallUnorderedSet< String >; +using PropertyMap = UnorderedMap< PropertyId, Property >; + +using Dictionary = SmallUnorderedMap< String, Variant >; +using ElementAttributes = Dictionary; +using XMLAttributes = Dictionary; + +using AnimationList = Vector; +using DecoratorList = Vector>; +using FontEffectList = Vector>; + +struct Decorators { + DecoratorList list; + String value; +}; +struct FontEffects { + FontEffectList list; + String value; +}; + +// Additional smart pointers +using TransformPtr = SharedPtr< Transform >; +using DecoratorsPtr = SharedPtr; +using FontEffectsPtr = SharedPtr; + +// Data binding types +class DataView; +using DataViewPtr = UniqueReleaserPtr; +class DataController; +using DataControllerPtr = UniqueReleaserPtr; + +} // namespace Rml + + +namespace std { +// Hash specialization for enum class types (required on some older compilers) +template <> struct hash<::Rml::PropertyId> { + using utype = typename ::std::underlying_type<::Rml::PropertyId>::type; + size_t operator() (const ::Rml::PropertyId& t) const { ::Rml::Hash h; return h(static_cast(t)); } +}; +template <> struct hash<::Rml::Character> { + using utype = typename ::std::underlying_type<::Rml::Character>::type; + size_t operator() (const ::Rml::Character& t) const { ::Rml::Hash h; return h(static_cast(t)); } +}; +template <> struct hash<::Rml::FamilyId> { + using utype = typename ::std::underlying_type<::Rml::FamilyId>::type; + size_t operator() (const ::Rml::FamilyId& t) const { ::std::hash h; return h(static_cast(t)); } +}; +} + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/URL.h b/thirdparty/RmlUi/Include/RmlUi/Core/URL.h new file mode 100644 index 000000000..fa49a6aa6 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/URL.h @@ -0,0 +1,147 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_URL_H +#define RMLUI_CORE_URL_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class RMLUICORE_API URL +{ +public: + /// Constructs an empty URL. + URL(); + /// Constructs a new URL from the given string. + URL(const String& url); + /// Constructs a new URL from the given string. A little more scripting + /// engine friendly. + URL(const char* url); + /// Destroys the URL. + ~URL(); + + /// Assigns a new URL to the object. This will return false if the URL + /// is malformed. + bool SetURL(const String& url); + /// Returns the entire URL. + const String& GetURL() const; + + /// Sets the URL's protocol. + bool SetProtocol(const String& protocol); + /// Returns the protocol this URL is utilising. + const String& GetProtocol() const; + + /// Sets the URL's login + bool SetLogin( const String& login ); + /// Returns the URL's login + const String& GetLogin() const; + + /// Sets the URL's password + bool SetPassword( const String& password ); + /// Returns the URL's password + const String& GetPassword() const; + + /// Sets the URL's host. + bool SetHost(const String& host); + /// Returns the URL's host. + const String& GetHost() const; + + /// Sets the URL's port number. + bool SetPort(int port); + /// Returns the URL's port number. + int GetPort() const; + + /// Sets the URL's path. + bool SetPath(const String& path); + /// Prefixes the URL's existing path with the given prefix. + bool PrefixPath(const String& prefix); + /// Returns the URL's path. + const String& GetPath() const; + + /// Sets the URL's file name. + bool SetFileName(const String& file_name); + /// Returns the URL's file name. + const String& GetFileName() const; + + /// Sets the URL's file extension. + bool SetExtension(const String& extension); + /// Returns the URL's file extension. + const String& GetExtension() const; + + /// Access the url parameters + typedef UnorderedMap< String, String > Parameters; + const Parameters& GetParameters() const; + void SetParameter(const String& name, const String& value); + void SetParameters( const Parameters& parameters ); + void ClearParameters(); + + /// Returns the URL's path, file name and extension. + String GetPathedFileName() const; + /// Builds and returns a url query string ( key=value&key2=value2 ) + String GetQueryString() const; + + /// Less-than operator for use as a key in STL containers. + bool operator<(const URL& rhs) const; + + /// Since URLs often contain characters outside the ASCII set, + /// the URL has to be converted into a valid ASCII format and back. + static String UrlEncode(const String &value); + static String UrlDecode(const String &value); + +private: + void ConstructURL() const; + + /// Portable character check (remember EBCDIC). Do not use isalnum() because + /// its behavior is altered by the current locale. + /// See http://tools.ietf.org/html/rfc3986#section-2.3 + /// (copied from libcurl sources) + static bool IsUnreservedChar(const char c); + + mutable String url; + String protocol; + String login; + String password; + String host; + String path; + String file_name; + String extension; + + Parameters parameters; + + int port; + mutable int url_dirty; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Variant.h b/thirdparty/RmlUi/Include/RmlUi/Core/Variant.h new file mode 100644 index 000000000..93dee84a2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Variant.h @@ -0,0 +1,164 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUIVARIANT_H +#define RMLUIVARIANT_H + +#include "Header.h" +#include "Types.h" +#include "TypeConverter.h" +#include "Animation.h" + +namespace Rml { + +/** + Variant is a container that can store a selection of basic types. The variant will store the + value in the native form corresponding to the version of Set that was called. + + Get is templated to convert from the stored form to the requested form by using a TypeConverter. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API Variant +{ +public: + /// Type of data stored in the variant. We use size_t as base to avoid 'padding due to alignment specifier' warning. + enum Type : size_t + { + NONE = '-', + BOOL = 'B', + BYTE = 'b', + CHAR = 'c', + FLOAT = 'f', + DOUBLE = 'd', + INT = 'i', + INT64 = 'I', + STRING = 's', + VECTOR2 = '2', + VECTOR3 = '3', + VECTOR4 = '4', + COLOURF = 'g', + COLOURB = 'h', + SCRIPTINTERFACE = 'p', + TRANSFORMPTR = 't', + TRANSITIONLIST = 'T', + ANIMATIONLIST = 'A', + DECORATORSPTR = 'D', + FONTEFFECTSPTR = 'F', + VOIDPTR = '*', + }; + + Variant(); + Variant(const Variant&); + Variant(Variant&&) noexcept; + Variant& operator=(const Variant& copy); + Variant& operator=(Variant&& other) noexcept; + ~Variant(); + + // Construct by variant type + template< typename T > + explicit Variant(T&& t); + + // Assign by variant type + template + Variant& operator=(T&& t); + + void Clear(); + + inline Type GetType() const; + + /// Templatised data accessor. TypeConverters will be used to attempt to convert from the + /// internal representation to the requested representation. + /// @param[in] default_value The value returned if the conversion failed. + /// @return Data in the requested type. + template< typename T > + T Get(T default_value = T()) const; + + /// Templatised data accessor. TypeConverters will be used to attempt to convert from the + /// internal representation to the requested representation. + /// @param[out] value Data in the requested type. + /// @return True if the value was converted and returned, false if no data was stored in the variant. + template< typename T > + bool GetInto(T& value) const; + + /// Returns a reference to the variant's underlying type. + /// @warning: Undefined behavior if T does not represent the underlying type of the variant. + template< typename T> + const T& GetReference() const; + + bool operator==(const Variant& other) const; + bool operator!=(const Variant& other) const { return !(*this == other); } + +private: + + /// Copy another variant's data to this variant. + /// @warning Does not clear existing data. + void Set(const Variant& copy); + void Set(Variant&& other); + + void Set(const bool value); + void Set(const byte value); + void Set(const char value); + void Set(const float value); + void Set(const double value); + void Set(const int value); + void Set(const int64_t value); + void Set(const char* value); + void Set(void* value); + void Set(const Vector2f& value); + void Set(const Vector3f& value); + void Set(const Vector4f& value); + void Set(const Colourf& value); + void Set(const Colourb& value); + void Set(ScriptInterface* value); + + void Set(const String& value); + void Set(String&& value); + void Set(const TransformPtr& value); + void Set(TransformPtr&& value); + void Set(const TransitionList& value); + void Set(TransitionList&& value); + void Set(const AnimationList& value); + void Set(AnimationList&& value); + void Set(const DecoratorsPtr& value); + void Set(DecoratorsPtr&& value); + void Set(const FontEffectsPtr& value); + void Set(FontEffectsPtr&& value); + + static constexpr size_t LOCAL_DATA_SIZE = (sizeof(TransitionList) > sizeof(String) ? sizeof(TransitionList) : sizeof(String)); + + Type type; + alignas(TransitionList) char data[LOCAL_DATA_SIZE]; +}; + +} // namespace Rml + +#include "Variant.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Variant.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Variant.inl new file mode 100644 index 000000000..e05cc9a75 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Variant.inl @@ -0,0 +1,156 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { + +inline Variant::Type Variant::GetType() const +{ + return type; +} + +template< typename T > +Variant::Variant(T&& t) : type(NONE) +{ + Set(std::forward(t)); +} + +template< typename T > +Variant& Variant::operator=(T&& t) +{ + Clear(); + Set(std::forward(t)); + return *this; +} + +// Templatised data accessor. +template< typename T > +bool Variant::GetInto(T& value) const +{ + switch (type) + { + case BOOL: + return TypeConverter< bool, T >::Convert(*(bool*)data, value); + break; + + case BYTE: + return TypeConverter< byte, T >::Convert(*(byte*)data, value); + break; + + case CHAR: + return TypeConverter< char, T >::Convert(*(char*)data, value); + break; + + case FLOAT: + return TypeConverter< float, T >::Convert(*(float*)data, value); + break; + + case DOUBLE: + return TypeConverter< double, T >::Convert(*(double*)data, value); + break; + + case INT: + return TypeConverter< int, T >::Convert(*(int*)data, value); + break; + + case INT64: + return TypeConverter< int64_t, T >::Convert(*(int64_t*)data, value); + break; + + case STRING: + return TypeConverter< String, T >::Convert(*(String*)data, value); + break; + + case VECTOR2: + return TypeConverter< Vector2f, T >::Convert(*(Vector2f*)data, value); + break; + + case VECTOR3: + return TypeConverter< Vector3f, T >::Convert(*(Vector3f*)data, value); + break; + + case VECTOR4: + return TypeConverter< Vector4f, T >::Convert(*(Vector4f*)data, value); + break; + + case COLOURF: + return TypeConverter< Colourf, T >::Convert(*(Colourf*)data, value); + break; + + case COLOURB: + return TypeConverter< Colourb, T >::Convert(*(Colourb*)data, value); + break; + + case SCRIPTINTERFACE: + return TypeConverter< ScriptInterface*, T >::Convert(*(ScriptInterface * *)data, value); + break; + + case VOIDPTR: + return TypeConverter< void*, T >::Convert(*(void**)data, value); + break; + + case TRANSFORMPTR: + return TypeConverter< TransformPtr, T >::Convert(*(TransformPtr*)data, value); + break; + + case TRANSITIONLIST: + return TypeConverter< TransitionList, T >::Convert(*(TransitionList*)data, value); + break; + + case ANIMATIONLIST: + return TypeConverter< AnimationList, T >::Convert(*(AnimationList*)data, value); + break; + + case DECORATORSPTR: + return TypeConverter< DecoratorsPtr, T >::Convert(*(DecoratorsPtr*)data, value); + break; + + case FONTEFFECTSPTR: + return TypeConverter< FontEffectsPtr, T >::Convert(*(FontEffectsPtr*)data, value); + break; + case NONE: + break; + } + + return false; +} + +// Templatised data accessor. +template< typename T > +T Variant::Get(T default_value) const +{ + GetInto(default_value); + return default_value; +} + +template +inline const T& Variant::GetReference() const +{ + return *(T*)data; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vector2.h b/thirdparty/RmlUi/Include/RmlUi/Core/Vector2.h new file mode 100644 index 000000000..0f2e3b6fc --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vector2.h @@ -0,0 +1,160 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_VECTOR2_H +#define RMLUI_CORE_VECTOR2_H + +#include "Debug.h" +#include "Math.h" + +namespace Rml { + +/** + Templated class for a generic two-component vector. + @author Peter Curry + */ + +template < typename Type > +class Vector2 +{ + public: + /// Initialising constructor. + /// @param[in] v Initial value of each element in the vector. + explicit inline Vector2(Type v = Type{ 0 }); + /// Initialising constructor. + /// @param[in] x Initial x-value of the vector. + /// @param[in] y Initial y-value of the vector. + inline Vector2(Type x, Type y); + + /// Returns the magnitude of the vector. + /// @return The computed magnitude. + inline float Magnitude() const; + /// Returns the squared magnitude of the vector. + /// @return The computed squared magnitude. + inline Type SquaredMagnitude() const; + /// Generates a normalised vector from this vector. + /// @return The normalised vector. + inline Vector2 Normalise() const; + /// Generates a vector with values rounded to their nearest integer. + /// @return The rounded vector + inline Vector2 Round() const; + + /// Computes the dot-product between this vector and another. + /// @param[in] rhs The other vector to use in the dot-product. + /// @return The computed dot-product between the two vectors. + inline Type DotProduct(const Vector2& rhs) const; + + /// Returns this vector rotated around the origin. + /// @param[in] theta The angle to rotate by, in radians. + /// @return The rotated vector. + inline Vector2 Rotate(float theta) const; + + /// Returns the negation of this vector. + /// @return The negation of this vector. + inline Vector2 operator-() const; + + /// Returns the sum of this vector and another. + /// @param[in] rhs The vector to add this to. + /// @return The sum of the two vectors. + inline Vector2 operator+(const Vector2& rhs) const; + /// Returns the result of subtracting another vector from this vector. + /// @param[in] rhs The vector to subtract from this vector. + /// @return The result of the subtraction. + inline Vector2 operator-(const Vector2& rhs) const; + /// Returns the result of multiplying this vector by a scalar. + /// @param[in] rhs The scalar value to multiply by. + /// @return The result of the scale. + inline Vector2 operator*(Type rhs) const; + /// Returns the result of element-wise multiplication. + /// @param[in] rhs The vector to multiply by. + /// @return The result of the multiplication. + inline Vector2 operator*(const Vector2& rhs) const; + /// Returns the result of dividing this vector by a scalar. + /// @param[in] rhs The scalar value to divide by. + /// @return The result of the scale. + inline Vector2 operator/(Type rhs) const; + /// Returns the result of element-wise division. + /// @param[in] rhs The vector to divide by. + /// @return The result of the division. + inline Vector2 operator/(const Vector2& rhs) const; + + /// Adds another vector to this in-place. + /// @param[in] rhs The vector to add. + /// @return This vector, post-operation. + inline Vector2& operator+=(const Vector2& rhs); + /// Subtracts another vector from this in-place. + /// @param[in] rhs The vector to subtract. + /// @return This vector, post-operation. + inline Vector2& operator-=(const Vector2& rhs); + /// Scales this vector in-place. + /// @param[in] rhs The value to scale this vector's components by. + /// @return This vector, post-operation. + inline Vector2& operator*=(const Type& rhs); + /// Element-wise multiplication in-place. + /// @param[in] rhs The vector to multiply. + /// @return This vector, post-operation. + inline Vector2& operator*=(const Vector2& rhs); + /// Scales this vector in-place by the inverse of a value. + /// @param[in] rhs The value to divide this vector's components by. + /// @return This vector, post-operation. + inline Vector2& operator/=(const Type& rhs); + /// Element-wise division in-place. + /// @param[in] rhs The vector to divide by. + /// @return This vector, post-operation. + inline Vector2& operator/=(const Vector2& rhs); + + /// Equality operator. + /// @param[in] rhs The vector to compare this against. + /// @return True if the two vectors are equal, false otherwise. + inline bool operator==(const Vector2& rhs) const; + /// Inequality operator. + /// @param[in] rhs The vector to compare this against. + /// @return True if the two vectors are not equal, false otherwise. + inline bool operator!=(const Vector2& rhs) const; + + /// Auto-cast operator. + /// @return A pointer to the first value. + inline operator const Type*() const; + /// Constant auto-cast operator. + /// @return A constant pointer to the first value. + inline operator Type*(); + + // The components of the vector. + Type x; + Type y; + +#ifdef RMLUI_VECTOR2_USER_EXTRA + RMLUI_VECTOR2_USER_EXTRA +#endif +}; + +} // namespace Rml + +#include "Vector2.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vector2.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Vector2.inl new file mode 100644 index 000000000..459d233ec --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vector2.inl @@ -0,0 +1,241 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { + +// Initialising constructor. +template < typename Type > +Vector2< Type >::Vector2(Type v) : x(v), y(v) +{ +} + +// Initialising constructor. +template < typename Type > +Vector2< Type >::Vector2(Type x, Type y) : x(x), y(y) +{ +} + +// Returns the magnitude of the vector. +template < typename Type > +float Vector2< Type >::Magnitude() const +{ + float squared_magnitude = (float)SquaredMagnitude(); + if (Math::IsZero(squared_magnitude)) + return 0; + + return Math::SquareRoot(squared_magnitude); +} + +// Returns the squared magnitude of the vector. +template < typename Type > +Type Vector2< Type >::SquaredMagnitude() const +{ + return x * x + + y * y; +} + +// Generates a normalised vector from this vector. +template < typename Type > +Vector2< Type > Vector2< Type >::Normalise() const +{ + float magnitude = Magnitude(); + if (Math::IsZero(magnitude)) + return *this; + + return *this / magnitude; +} + +// Generates a rounded vector from this vector. +template < > +inline Vector2< float > Vector2< float >::Round() const +{ + Vector2 < float > result; + result.x = Math::RoundFloat(x); + result.y = Math::RoundFloat(y); + return result; +} + +// Generates a rounded vector from this vector. +template < > +inline Vector2< int > Vector2< int >::Round() const +{ + return *this; +} + +// Computes the dot-product between this vector and another. +template < typename Type > +Type Vector2< Type >::DotProduct(const Vector2< Type >& rhs) const +{ + return x * rhs.x + + y * rhs.y; +} + +// Returns this vector rotated around the origin. +template < typename Type > +Vector2< Type > Vector2< Type >::Rotate(float theta) const +{ + float cos_theta = Math::Cos(theta); + float sin_theta = Math::Sin(theta); + + return Vector2< Type >(((Type)(cos_theta * x - sin_theta * y)), + ((Type)(sin_theta * x + cos_theta * y))); +} + +// Returns the negation of this vector. +template < typename Type > +Vector2< Type > Vector2< Type >::operator-() const +{ + return Vector2(-x, -y); +} + +// Returns the sum of this vector and another. +template < typename Type > +Vector2< Type > Vector2< Type >::operator+(const Vector2< Type > & rhs) const +{ + return Vector2< Type >(x + rhs.x, y + rhs.y); +} + +// Returns the result of subtracting another vector from this vector. +template < typename Type > +Vector2< Type > Vector2< Type >::operator-(const Vector2< Type > & rhs) const +{ + return Vector2(x - rhs.x, y - rhs.y); +} + +// Returns the result of multiplying this vector by a scalar. +template < typename Type > +Vector2< Type > Vector2< Type >::operator*(Type rhs) const +{ + return Vector2(x * rhs, y * rhs); +} + +template +Vector2< Type > Vector2::operator*(const Vector2& rhs) const +{ + return Vector2(x * rhs.x, y * rhs.y); +} + +// Returns the result of dividing this vector by a scalar. +template < typename Type > +Vector2< Type > Vector2< Type >::operator/(Type rhs) const +{ + return Vector2(x / rhs, y / rhs); +} + +template +Vector2< Type > Vector2::operator/(const Vector2& rhs) const +{ + return Vector2(x / rhs.x, y / rhs.y); +} + +// Adds another vector to this in-place. +template < typename Type > +Vector2< Type >& Vector2< Type >::operator+=(const Vector2 & rhs) +{ + x += rhs.x; + y += rhs.y; + + return *this; +} + +// Subtracts another vector from this in-place. +template < typename Type > +Vector2< Type >& Vector2< Type >::operator-=(const Vector2 & rhs) +{ + x -= rhs.x; + y -= rhs.y; + + return *this; +} + +// Scales this vector in-place. +template < typename Type > +Vector2< Type >& Vector2< Type >::operator*=(const Type & rhs) +{ + x *= rhs; + y *= rhs; + + return *this; +} + +template +Vector2< Type >& Vector2::operator*=(const Vector2& rhs) +{ + x *= rhs.x; + y *= rhs.y; + + return *this; +} + +// Scales this vector in-place by the inverse of a value. +template < typename Type > +Vector2< Type >& Vector2< Type >::operator/=(const Type & rhs) +{ + x /= rhs; + y /= rhs; + + return *this; +} + +template +Vector2< Type >& Vector2::operator/=(const Vector2& rhs) +{ + x /= rhs.x; + y /= rhs.y; + return *this; +} + +// Equality operator. +template < typename Type > +bool Vector2< Type >::operator==(const Vector2 & rhs) const +{ + return (x == rhs.x && y == rhs.y); +} + +// Inequality operator. +template < typename Type > +bool Vector2< Type >::operator!=(const Vector2 & rhs) const +{ + return (x != rhs.x || y != rhs.y); +} + +// Auto-cast operator. +template < typename Type > +Vector2< Type >::operator const Type* () const +{ + return &x; +} + +// Constant auto-cast operator. +template < typename Type > +Vector2< Type >::operator Type* () +{ + return &x; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vector3.h b/thirdparty/RmlUi/Include/RmlUi/Core/Vector3.h new file mode 100644 index 000000000..701c8498a --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vector3.h @@ -0,0 +1,146 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_VECTOR3_H +#define RMLUI_CORE_VECTOR3_H + +#include "Debug.h" +#include "Math.h" + +namespace Rml { + +/** + Templated class for a generic three-component vector. + @author Markus Schöngart + */ + +template < typename Type > +class Vector3 +{ + public: + /// Initialising constructor. + /// @param[in] v Initial value of each element in the vector. + explicit inline Vector3(Type v = Type{ 0 }); + /// Initialising constructor. + /// @param[in] x Initial x-value of the vector. + /// @param[in] y Initial y-value of the vector. + /// @param[in] z Initial z-value of the vector. + inline Vector3(Type x, Type y, Type z); + + /// Returns the magnitude of the vector. + /// @return The computed magnitude. + inline float Magnitude() const; + /// Returns the squared magnitude of the vector. + /// @return The computed squared magnitude. + inline Type SquaredMagnitude() const; + /// Generates a normalised vector from this vector. + /// @return The normalised vector. + inline Vector3 Normalise() const; + + /// Computes the dot-product between this vector and another. + /// @param[in] rhs The other vector to use in the dot-product. + /// @return The computed dot-product between the two vectors. + inline Type DotProduct(const Vector3& rhs) const; + + /// Computes the cross-product between this vector and another. + /// @param[in] rhs The other vector to use in the dot-product. + /// @return The computed cross-product between the two vectors. + inline Vector3 CrossProduct(const Vector3& rhs) const; + + /// Returns the negation of this vector. + /// @return The negation of this vector. + inline Vector3 operator-() const; + + /// Returns the sum of this vector and another. + /// @param[in] rhs The vector to add this to. + /// @return The sum of the two vectors. + inline Vector3 operator+(const Vector3& rhs) const; + /// Returns the result of subtracting another vector from this vector. + /// @param[in] rhs The vector to subtract from this vector. + /// @return The result of the subtraction. + inline Vector3 operator-(const Vector3& rhs) const; + /// Returns the result of multiplying this vector by a scalar. + /// @param[in] rhs The scalar value to multiply by. + /// @return The result of the scale. + inline Vector3 operator*(Type rhs) const; + /// Returns the result of dividing this vector by a scalar. + /// @param[in] rhs The scalar value to divide by. + /// @return The result of the scale. + inline Vector3 operator/(Type rhs) const; + + /// Adds another vector to this in-place. + /// @param[in] rhs The vector to add. + /// @return This vector, post-operation. + inline Vector3& operator+=(const Vector3& rhs); + /// Subtracts another vector from this in-place. + /// @param[in] rhs The vector to subtract. + /// @return This vector, post-operation. + inline Vector3& operator-=(const Vector3& rhs); + /// Scales this vector in-place. + /// @param[in] rhs The value to scale this vector's components by. + /// @return This vector, post-operation. + inline Vector3& operator*=(const Type& rhs); + /// Scales this vector in-place by the inverse of a value. + /// @param[in] rhs The value to divide this vector's components by. + /// @return This vector, post-operation. + inline Vector3& operator/=(const Type& rhs); + + /// Equality operator. + /// @param[in] rhs The vector to compare this against. + /// @return True if the two vectors are equal, false otherwise. + inline bool operator==(const Vector3& rhs) const; + /// Inequality operator. + /// @param[in] rhs The vector to compare this against. + /// @return True if the two vectors are not equal, false otherwise. + inline bool operator!=(const Vector3& rhs) const; + + /// Constant auto-cast operator. + /// @return A pointer to the first value. + inline operator const Type*() const; + /// Auto-cast operator. + /// @return A constant pointer to the first value. + inline operator Type*(); + + // Cast to Vector2 + explicit inline operator Vector2< Type >() const; + + // The components of the vector. + Type x; + Type y; + Type z; + +#ifdef RMLUI_VECTOR3_USER_EXTRA + RMLUI_VECTOR3_USER_EXTRA +#endif +}; + +} // namespace Rml + +#include "Vector3.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vector3.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Vector3.inl new file mode 100644 index 000000000..c7d8afb67 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vector3.inl @@ -0,0 +1,212 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include + +namespace Rml { + +// Initialising constructor. +template < typename Type > +Vector3< Type >::Vector3(Type v) : x(v), y(v), z(v) +{ +} + +// Initialising constructor. +template < typename Type > +Vector3< Type >::Vector3(Type x, Type y, Type z) : x(x), y(y), z(z) +{ +} + +// Returns the magnitude of the vector. +template < typename Type > +float Vector3< Type >::Magnitude() const +{ + float squared_magnitude = (float)SquaredMagnitude(); + if (Math::IsZero(squared_magnitude)) + return 0; + + return Math::SquareRoot(squared_magnitude); +} + +// Returns the squared magnitude of the vector. +template < typename Type > +Type Vector3< Type >::SquaredMagnitude() const +{ + return x * x + y * y + z * z; +} + +// Generates a normalised vector from this vector. +template < typename Type > +Vector3< Type > Vector3< Type >::Normalise() const +{ + static_assert(std::is_floating_point< Type >::value, "Invalid operation"); + return *this; +} + +template <> +inline Vector3< float > Vector3< float >::Normalise() const +{ + float magnitude = Magnitude(); + if (Math::IsZero(magnitude)) + return *this; + + return *this / magnitude; +} + +// Computes the dot-product between this vector and another. +template < typename Type > +Type Vector3< Type >::DotProduct(const Vector3< Type >& rhs) const +{ + return x * rhs.x + y * rhs.y + z * rhs.z; +} + +// Computes the cross-product between this vector and another. +template < typename Type > +Vector3< Type> Vector3< Type >::CrossProduct(const Vector3< Type >& rhs) const +{ + return Vector3< Type >( + y * rhs.z - z * rhs.y, + z * rhs.x - x * rhs.z, + x * rhs.y - y * rhs.x + ); +} + +// Returns the negation of this vector. +template < typename Type > +Vector3< Type > Vector3< Type >::operator-() const +{ + return Vector3(-x, -y, -z); +} + +// Returns the sum of this vector and another. +template < typename Type > +Vector3< Type > Vector3< Type >::operator+(const Vector3< Type > & rhs) const +{ + return Vector3< Type >(x + rhs.x, y + rhs.y, z + rhs.z); +} + +// Returns the result of subtracting another vector from this vector. +template < typename Type > +Vector3< Type > Vector3< Type >::operator-(const Vector3< Type > & rhs) const +{ + return Vector3(x - rhs.x, y - rhs.y, z - rhs.z); +} + +// Returns the result of multiplying this vector by a scalar. +template < typename Type > +Vector3< Type > Vector3< Type >::operator*(Type rhs) const +{ + return Vector3(x * rhs, y * rhs, z * rhs); +} + +// Returns the result of dividing this vector by a scalar. +template < typename Type > +Vector3< Type > Vector3< Type >::operator/(Type rhs) const +{ + return Vector3(x / rhs, y / rhs, z / rhs); +} + +// Adds another vector to this in-place. +template < typename Type > +Vector3< Type >& Vector3< Type >::operator+=(const Vector3 & rhs) +{ + x += rhs.x; + y += rhs.y; + z += rhs.z; + + return *this; +} + +// Subtracts another vector from this in-place. +template < typename Type > +Vector3< Type >& Vector3< Type >::operator-=(const Vector3 & rhs) +{ + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + + return *this; +} + +// Scales this vector in-place. +template < typename Type > +Vector3< Type >& Vector3< Type >::operator*=(const Type & rhs) +{ + x *= rhs; + y *= rhs; + z *= rhs; + + return *this; +} + +// Scales this vector in-place by the inverse of a value. +template < typename Type > +Vector3< Type >& Vector3< Type >::operator/=(const Type & rhs) +{ + x /= rhs; + y /= rhs; + z /= rhs; + + return *this; +} + +// Equality operator. +template < typename Type > +bool Vector3< Type >::operator==(const Vector3 & rhs) const +{ + return (x == rhs.x && y == rhs.y && z == rhs.z); +} + +// Inequality operator. +template < typename Type > +bool Vector3< Type >::operator!=(const Vector3 & rhs) const +{ + return (x != rhs.x || y != rhs.y || z != rhs.z); +} + +// Constant auto-cast operator. +template < typename Type > +Vector3< Type >::operator const Type* () const +{ + return &x; +} + +// Auto-cast operator. +template < typename Type > +Vector3< Type >::operator Type* () +{ + return &x; +} + +template < typename Type > +Vector3< Type >::operator Vector2< Type >() const +{ + return Vector2< Type >(x, y); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vector4.h b/thirdparty/RmlUi/Include/RmlUi/Core/Vector4.h new file mode 100644 index 000000000..42d298087 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vector4.h @@ -0,0 +1,151 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_VECTOR4_H +#define RMLUI_CORE_VECTOR4_H + +#include "Debug.h" +#include "Math.h" +#include "Vector3.h" + +namespace Rml { + +/** + Templated class for a generic four-component vector. + @author Markus Schöngart + */ + +template < typename Type > +class Vector4 +{ + public: + /// Initialising constructor. + /// @param[in] v Initial value of each element in the vector. + explicit inline Vector4(Type v = Type{ 0 }); + /// Initialising constructor. + /// @param[in] x Initial x-value of the vector. + /// @param[in] y Initial y-value of the vector. + /// @param[in] z Initial z-value of the vector. + /// @param[in] w Initial omega-value of the vector. + inline Vector4(Type x, Type y, Type z, Type w); + /// Implicit conversion from a 3D Vector. + inline Vector4(Vector3< Type > const &v, Type w); + + /// Returns the magnitude of the vector. + /// @return The computed magnitude. + inline float Magnitude() const; + /// Returns the squared magnitude of the vector. + /// @return The computed squared magnitude. + inline Type SquaredMagnitude() const; + /// Generates a normalised vector from this vector. + /// @return The normalised vector. + inline Vector4 Normalise() const; + + /// Computes the dot-product between this vector and another. + /// @param[in] rhs The other vector to use in the dot-product. + /// @return The computed dot-product between the two vectors. + inline Type DotProduct(const Vector4& rhs) const; + + /// Returns the negation of this vector. + /// @return The negation of this vector. + inline Vector4 operator-() const; + + /// Returns the sum of this vector and another. + /// @param[in] rhs The vector to add this to. + /// @return The sum of the two vectors. + inline Vector4 operator+(const Vector4& rhs) const; + /// Returns the result of subtracting another vector from this vector. + /// @param[in] rhs The vector to subtract from this vector. + /// @return The result of the subtraction. + inline Vector4 operator-(const Vector4& rhs) const; + /// Returns the result of multiplying this vector by a scalar. + /// @param[in] rhs The scalar value to multiply by. + /// @return The result of the scale. + inline Vector4 operator*(Type rhs) const; + /// Returns the result of dividing this vector by a scalar. + /// @param[in] rhs The scalar value to divide by. + /// @return The result of the scale. + inline Vector4 operator/(Type rhs) const; + + /// Adds another vector to this in-place. + /// @param[in] rhs The vector to add. + /// @return This vector, post-operation. + inline Vector4& operator+=(const Vector4& rhs); + /// Subtracts another vector from this in-place. + /// @param[in] rhs The vector to subtract. + /// @return This vector, post-operation. + inline Vector4& operator-=(const Vector4& rhs); + /// Scales this vector in-place. + /// @param[in] rhs The value to scale this vector's components by. + /// @return This vector, post-operation. + inline Vector4& operator*=(const Type& rhs); + /// Scales this vector in-place by the inverse of a value. + /// @param[in] rhs The value to divide this vector's components by. + /// @return This vector, post-operation. + inline Vector4& operator/=(const Type& rhs); + + /// Equality operator. + /// @param[in] rhs The vector to compare this against. + /// @return True if the two vectors are equal, false otherwise. + inline bool operator==(const Vector4& rhs) const; + /// Inequality operator. + /// @param[in] rhs The vector to compare this against. + /// @return True if the two vectors are not equal, false otherwise. + inline bool operator!=(const Vector4& rhs) const; + + /// Auto-cast operator to array of components. + /// @return A pointer to the first value. + inline operator const Type*() const; + /// Constant auto-cast operator to array of components. + /// @return A constant pointer to the first value. + inline operator Type*(); + + /// Return a Vector3 after perspective divide + inline Vector3< Type > PerspectiveDivide() const; + + /// Cast to Vector3 + explicit inline operator Vector3< Type >() const; + /// Cast to Vector2 + explicit inline operator Vector2< Type >() const; + + // The components of the vector. + Type x; + Type y; + Type z; + Type w; + +#ifdef RMLUI_VECTOR4_USER_EXTRA + RMLUI_VECTOR4_USER_EXTRA +#endif +}; + +} // namespace Rml + +#include "Vector4.inl" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vector4.inl b/thirdparty/RmlUi/Include/RmlUi/Core/Vector4.inl new file mode 100644 index 000000000..a26ee445b --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vector4.inl @@ -0,0 +1,219 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include + +namespace Rml { + +// Initialising constructor. +template < typename Type > +Vector4< Type >::Vector4(Type v) + : x(v), y(v), z(v), w(v) +{ +} + +// Initialising constructor. +template < typename Type > +Vector4< Type >::Vector4(Type x, Type y, Type z, Type w) + : x(x), y(y), z(z), w(w) +{ +} + +// Implicit conversion from a 3D Vector. +template < typename Type > +Vector4< Type >::Vector4(Vector3< Type > const& v, Type w) + : x(v.x), y(v.y), z(v.z), w(w) +{ +} + +// Returns the magnitude of the vector. +template < typename Type > +float Vector4< Type >::Magnitude() const +{ + float squared_magnitude = (float)SquaredMagnitude(); + if (Math::IsZero(squared_magnitude)) + return 0; + + return Math::SquareRoot(squared_magnitude); +} + +// Returns the squared magnitude of the vector. +template < typename Type > +Type Vector4< Type >::SquaredMagnitude() const +{ + return x * x + y * y + z * z + w * w; +} + +// Generates a normalised vector from this vector. +template < typename Type > +Vector4< Type > Vector4< Type >::Normalise() const +{ + static_assert(std::is_floating_point< Type >::value, "Invalid operation"); + return *this; +} + +template <> +RMLUICORE_API Vector4< float > Vector4< float >::Normalise() const; + +// Computes the dot-product between this vector and another. +template < typename Type > +Type Vector4< Type >::DotProduct(const Vector4< Type >& rhs) const +{ + return x * rhs.x + y * rhs.y + z * rhs.z + w * rhs.w; +} + +// Returns the negation of this vector. +template < typename Type > +Vector4< Type > Vector4< Type >::operator-() const +{ + return Vector4(-x, -y, -z, -w); +} + +// Returns the sum of this vector and another. +template < typename Type > +Vector4< Type > Vector4< Type >::operator+(const Vector4< Type > & rhs) const +{ + return Vector4< Type >(x + rhs.x, y + rhs.y, z + rhs.z, w + rhs.w); +} + +// Returns the result of subtracting another vector from this vector. +template < typename Type > +Vector4< Type > Vector4< Type >::operator-(const Vector4< Type > & rhs) const +{ + return Vector4(x - rhs.x, y - rhs.y, z - rhs.z, w - rhs.w); +} + +// Returns the result of multiplying this vector by a scalar. +template < typename Type > +Vector4< Type > Vector4< Type >::operator*(Type rhs) const +{ + return Vector4(x * rhs, y * rhs, z * rhs, w * rhs); +} + +// Returns the result of dividing this vector by a scalar. +template < typename Type > +Vector4< Type > Vector4< Type >::operator/(Type rhs) const +{ + return Vector4(x / rhs, y / rhs, z / rhs, w / rhs); +} + +// Adds another vector to this in-place. +template < typename Type > +Vector4< Type >& Vector4< Type >::operator+=(const Vector4 & rhs) +{ + x += rhs.x; + y += rhs.y; + z += rhs.z; + w += rhs.w; + + return *this; +} + +// Subtracts another vector from this in-place. +template < typename Type > +Vector4< Type >& Vector4< Type >::operator-=(const Vector4 & rhs) +{ + x -= rhs.x; + y -= rhs.y; + z -= rhs.z; + w -= rhs.w; + + return *this; +} + +// Scales this vector in-place. +template < typename Type > +Vector4< Type >& Vector4< Type >::operator*=(const Type & rhs) +{ + x *= rhs; + y *= rhs; + z *= rhs; + w *= rhs; + + return *this; +} + +// Scales this vector in-place by the inverse of a value. +template < typename Type > +Vector4< Type >& Vector4< Type >::operator/=(const Type & rhs) +{ + x /= rhs; + y /= rhs; + z /= rhs; + w /= rhs; + + return *this; +} + +// Equality operator. +template < typename Type > +bool Vector4< Type >::operator==(const Vector4 & rhs) const +{ + return (x == rhs.x && y == rhs.y && z == rhs.z && w == rhs.w); +} + +// Inequality operator. +template < typename Type > +bool Vector4< Type >::operator!=(const Vector4 & rhs) const +{ + return (x != rhs.x || y != rhs.y || z != rhs.z || w != rhs.w); +} + +// Auto-cast operator. +template < typename Type > +Vector4< Type >::operator const Type* () const +{ + return &x; +} + +// Constant auto-cast operator. +template < typename Type > +Vector4< Type >::operator Type* () +{ + return &x; +} + +template < typename Type > +Vector3< Type > Vector4< Type >::PerspectiveDivide() const +{ + return Vector3< Type >(x / w, y / w, z / w); +} + +template < typename Type > +Vector4< Type >::operator Vector3< Type >() const +{ + return Vector3< Type >(x, y, z); +} + +template < typename Type > +Vector4< Type >::operator Vector2< Type >() const +{ + return Vector2< Type >(x, y); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/Vertex.h b/thirdparty/RmlUi/Include/RmlUi/Core/Vertex.h new file mode 100644 index 000000000..7f8e70a5e --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/Vertex.h @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_VERTEX_H +#define RMLUI_CORE_VERTEX_H + +#include "Header.h" +#include "Types.h" + +namespace Rml { + +/** + The element that makes up all geometry sent to the renderer. + + @author Peter Curry + */ + +struct RMLUICORE_API Vertex +{ + /// Two-dimensional position of the vertex (usually in pixels). + Vector2f position; + /// RGBA-ordered 8-bit / channel colour. + Colourb colour; + /// Texture coordinate for any associated texture. + Vector2f tex_coord; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/XMLNodeHandler.h b/thirdparty/RmlUi/Include/RmlUi/Core/XMLNodeHandler.h new file mode 100644 index 000000000..33a8e68a2 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/XMLNodeHandler.h @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLNODEHANDLER_H +#define RMLUI_CORE_XMLNODEHANDLER_H + +#include "Header.h" +#include "Traits.h" +#include "Types.h" + +namespace Rml { + +class Element; +class XMLParser; +enum class XMLDataType; + +/** + A handler gets ElementStart, ElementEnd and ElementData called by the XMLParser. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API XMLNodeHandler : public NonCopyMoveable +{ +public: + virtual ~XMLNodeHandler(); + + /// Called when a new element tag is opened. + /// @param parser The parser executing the parse. + /// @param name The XML tag name. + /// @param attributes The tag attributes. + /// @return The new element, may be nullptr if no element was created. + virtual Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) = 0; + + /// Called when an element is closed. + /// @param parser The parser executing the parse. + /// @param name The XML tag name. + virtual bool ElementEnd(XMLParser* parser, const String& name) = 0; + + /// Called for element data. + /// @param parser The parser executing the parse. + /// @param data The element data. + virtual bool ElementData(XMLParser* parser, const String& data, XMLDataType type) = 0; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Core/XMLParser.h b/thirdparty/RmlUi/Include/RmlUi/Core/XMLParser.h new file mode 100644 index 000000000..808c53d95 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Core/XMLParser.h @@ -0,0 +1,117 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLPARSER_H +#define RMLUI_CORE_XMLPARSER_H + +#include +#include "Header.h" +#include "BaseXMLParser.h" + +namespace Rml { + +class DocumentHeader; +class Element; +class XMLNodeHandler; +class URL; + +/** + RmlUi's XML parsing engine. The factory creates an instance of this class for each RML parse. + + @author Lloyd Weehuizen + */ + +class RMLUICORE_API XMLParser : public BaseXMLParser +{ +public: + XMLParser(Element* root); + ~XMLParser(); + + /// Registers a custom node handler to be used to a given tag. + /// @param[in] tag The tag the custom parser will handle. + /// @param[in] handler The custom handler. + /// @return The registered XML node handler. + static XMLNodeHandler* RegisterNodeHandler(const String& tag, SharedPtr handler); + /// Releases all registered node handlers. This is called internally. + static void ReleaseHandlers(); + + /// Returns the XML document's header. + /// @return The document header. + DocumentHeader* GetDocumentHeader(); + + // The parse stack. + struct ParseFrame + { + // Tag being parsed. + String tag; + + // Element representing this frame. + Element* element = nullptr; + + // Handler used for this frame. + XMLNodeHandler* node_handler = nullptr; + + // The default handler used for this frame's children. + XMLNodeHandler* child_handler = nullptr; + }; + + /// Pushes an element handler onto the parse stack for parsing child elements. + /// @param[in] tag The tag the handler was registered with. + /// @return True if an appropriate handler was found and pushed onto the stack, false if not. + bool PushHandler(const String& tag); + /// Pushes the default element handler onto the parse stack. + void PushDefaultHandler(); + + /// Access the current parse frame. + const ParseFrame* GetParseFrame() const; + + /// Returns the source URL of this parse. + const URL& GetSourceURL() const; + +protected: + /// Called when the parser finds the beginning of an element tag. + void HandleElementStart(const String& name, const XMLAttributes& attributes) override; + /// Called when the parser finds the end of an element tag. + void HandleElementEnd(const String& name) override; + /// Called when the parser encounters data. + void HandleData(const String& data, XMLDataType type) override; + +private: + // The header of the document being parsed. + UniquePtr header; + + // The active node handler. + XMLNodeHandler* active_handler; + + // The parser stack. + using ParserStack = Stack< ParseFrame >; + ParserStack stack; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Debugger.h b/thirdparty/RmlUi/Include/RmlUi/Debugger.h new file mode 100644 index 000000000..0c18e37d4 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Debugger.h @@ -0,0 +1,34 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_H +#define RMLUI_DEBUGGER_H + +#include "Debugger/Debugger.h" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Debugger/Debugger.h b/thirdparty/RmlUi/Include/RmlUi/Debugger/Debugger.h new file mode 100644 index 000000000..5361a0705 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Debugger/Debugger.h @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_DEBUGGER_H +#define RMLUI_DEBUGGER_DEBUGGER_H + +#include "Header.h" + +namespace Rml { + +class Context; + +namespace Debugger { + +/// Initialises the debug plugin. The debugger will be loaded into the given context. +/// @param[in] context The RmlUi context to load the debugger into. The debugging tools will be displayed on this context. If this context is destroyed, the debugger will be released. +/// @return True if the debugger was successfully initialised +RMLUIDEBUGGER_API bool Initialise(Context* context); + +/// Sets the context to be debugged. +/// @param[in] context The context to be debugged. +/// @return True if the debugger is initialised and the context was switched, false otherwise. +RMLUIDEBUGGER_API bool SetContext(Context* context); + +/// Sets the visibility of the debugger. +/// @param[in] visibility True to show the debugger, false to hide it. +RMLUIDEBUGGER_API void SetVisible(bool visibility); +/// Returns the visibility of the debugger. +/// @return True if the debugger is visible, false if not. +RMLUIDEBUGGER_API bool IsVisible(); + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Debugger/Header.h b/thirdparty/RmlUi/Include/RmlUi/Debugger/Header.h new file mode 100644 index 000000000..7d404fff7 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Debugger/Header.h @@ -0,0 +1,48 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_HEADER_H +#define RMLUI_DEBUGGER_HEADER_H + +#include "../Core/Platform.h" + +#if !defined RMLUI_STATIC_LIB + #ifdef RMLUI_PLATFORM_WIN32 + #ifdef RmlDebugger_EXPORTS + #define RMLUIDEBUGGER_API __declspec(dllexport) + #else + #define RMLUIDEBUGGER_API __declspec(dllimport) + #endif + #else + #define RMLUIDEBUGGER_API __attribute__((visibility("default"))) + #endif +#else + #define RMLUIDEBUGGER_API +#endif + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua.h b/thirdparty/RmlUi/Include/RmlUi/Lua.h new file mode 100644 index 000000000..8b4b04578 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua.h @@ -0,0 +1,38 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_H +#define RMLUI_LUA_H + +#include "Lua/Lua.h" + +#include "Lua/IncludeLua.h" +#include "Lua/LuaType.h" +#include "Lua/Interpreter.h" + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/Header.h b/thirdparty/RmlUi/Include/RmlUi/Lua/Header.h new file mode 100644 index 000000000..1aa6966f3 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/Header.h @@ -0,0 +1,52 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_HEADER_H +#define RMLUI_LUA_HEADER_H + +#include + +#ifdef RMLUILUA_API +#undef RMLUILUA_API +#endif + +#if !defined RMLUI_STATIC_LIB + #ifdef RMLUI_PLATFORM_WIN32 + #if defined RmlLua_EXPORTS + #define RMLUILUA_API __declspec(dllexport) + #else + #define RMLUILUA_API __declspec(dllimport) + #endif + #else + #define RMLUILUA_API __attribute__((visibility("default"))) + #endif +#else + #define RMLUILUA_API +#endif + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/IncludeLua.h b/thirdparty/RmlUi/Include/RmlUi/Lua/IncludeLua.h new file mode 100644 index 000000000..a2eb1723a --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/IncludeLua.h @@ -0,0 +1,39 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_INCLUDELUA_H +#define RMLUI_LUA_INCLUDELUA_H + +//The standard Lua headers +extern "C" { +#include +#include +#include +} + +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/Interpreter.h b/thirdparty/RmlUi/Include/RmlUi/Lua/Interpreter.h new file mode 100644 index 000000000..8c5ee217d --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/Interpreter.h @@ -0,0 +1,84 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_INTERPRETER_H +#define RMLUI_LUA_INTERPRETER_H + +#include "Header.h" +#include + +typedef struct lua_State lua_State; + +namespace Rml { +namespace Lua { + + +namespace Interpreter { + /** + @return The lua_State that the Interpreter created in Interpreter::Startup() + @remark This class lacks a SetLuaState for a reason. If you have to use a seperate Lua binding and want to keep the types + from RmlUi, then use this lua_State; it will already have all of the libraries loaded, and all of the types defined. + Alternatively, you can initialise the plugin with your own Lua state if you need them defined in it. */ + RMLUILUA_API lua_State* GetLuaState(); + + /** This function calls luaL_loadfile and then lua_pcall, reporting the errors (if any) + @param[in] file Fully qualified file name to execute. + @remark Somewhat misleading name if you are used to the Lua meaning of "load file". It behaves + exactly as luaL_dofile does. */ + RMLUILUA_API void LoadFile(const String& file); + /** Calls lua_dostring and reports the errors. + @param[in] code String to execute + @param[in] name Name for the code that will show up in the Log */ + RMLUILUA_API void DoString(const String& code, const String& name = ""); + /** Same as DoString, except does NOT call pcall on it. It will leave the compiled (but not executed) string + on top of the stack. It behaves exactly like luaL_loadstring, but you get to specify the name + @param[in] code String to compile + @param[in] name Name for the code that will show up in the Log */ + RMLUILUA_API void LoadString(const String& code, const String& name = ""); + + /** Clears all of the items on the stack, and pushes the function from funRef on top of the stack. Only use + this if you used lua_ref instead of luaL_ref + @param[in] funRef Lua reference that you would recieve from calling lua_ref */ + RMLUILUA_API void BeginCall(int funRef); + /** Uses lua_pcall on a function, which executes the function with params number of parameters and pushes + res number of return values on to the stack. + @pre Before you call this, your stack should look like: + [1] function to call; + [2...top] parameters to pass to the function (if any). + Or, in words, make sure to push the function on the stack before the parameters. + @post After this function, the params and function will be popped off, and 'res' + number of items will be pushed. */ + RMLUILUA_API bool ExecuteCall(int params = 0, int res = 0); + /** removes 'res' number of items from the stack + @param[in] res Number of results to remove from the stack. */ + RMLUILUA_API void EndCall(int res = 0); +} + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/Lua.h b/thirdparty/RmlUi/Include/RmlUi/Lua/Lua.h new file mode 100644 index 000000000..cc7d675f1 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/Lua.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUA_H +#define RMLUI_LUA_LUA_H + +#include "Header.h" + +typedef struct lua_State lua_State; + +namespace Rml { +namespace Lua { + +/** Initialise the Lua plugin. + @remark This is equivalent to calling Initialise(nullptr). */ +RMLUILUA_API void Initialise(); + +/** Initialise the Lua plugin and add RmlUi to an existing Lua state if one is provided. + @remark If nullptr is passed as an argument, the plugin will automatically create the lua state during initialisation + and close the state during the call to Rml::Shutdown(). Otherwise, if a Lua state is provided, the user is + responsible for closing the provided Lua state. The state must then be closed after the call to Rml::Shutdown(). + @remark The plugin registers the "body" tag to generate a LuaDocument rather than a ElementDocument. */ +RMLUILUA_API void Initialise(lua_State* L); + + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/LuaType.h b/thirdparty/RmlUi/Include/RmlUi/Lua/LuaType.h new file mode 100644 index 000000000..d18fb8536 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/LuaType.h @@ -0,0 +1,172 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUATYPE_H +#define RMLUI_LUA_LUATYPE_H + +#include "Header.h" +#include "IncludeLua.h" + +//As an example, if you used this macro like +//RMLUI_LUAMETHOD(Unit,GetId) +//it would result in code that looks like +//{ "GetId", UnitGetId }, +//Which would force you to create a global function named UnitGetId in C with the correct function signature, usually int(*)(lua_State*,type*); +#define RMLUI_LUAMETHOD(type,name) { #name, type##name }, + +//See above, but the method must match the function signature int(*)(lua_State*) and as example: +//RMLUI_LUAGETTER(Unit,Id) would mean you need a function named UnitGetAttrId +//The first stack position will be the userdata +#define RMLUI_LUAGETTER(type,varname) { #varname, type##GetAttr##varname }, + +//Same method signature as above, but as example: +//RMLUI_LUASETTER(Unit,Id) would mean you need a function named UnitSetAttrId +//The first stack position will be the userdata, and the second will be value on the other side of the equal sign +#define RMLUI_LUASETTER(type,varname) { #varname, type##SetAttr##varname }, + +#define RMLUI_CHECK_BOOL(L,narg) (lua_toboolean((L),(narg)) > 0 ? true : false ) +#define RMLUI_CHECK_OBJ(obj) if((obj) == nullptr) { lua_pushnil(L); return 1; } + + /** Used to remove repetitive typing at the cost of flexibility. When you use this, you @em must have + functions with the same name as defined in the macro. For example, if you used @c Element as type, you would + have to have functions named @c ElementMethods, @c ElementGetters, @c ElementSetters that return the appropriate + types.*/ +#define RMLUI_LUATYPE_DEFINE(type) \ + template<> const char* GetTClassName() { return #type; } \ + template<> RegType* GetMethodTable() { return type##Methods; } \ + template<> luaL_Reg* GetAttrTable() { return type##Getters; } \ + template<> luaL_Reg* SetAttrTable() { return type##Setters; } \ + +/** Used to remove repetitive typing at the cost of flexibility. It creates function prototypes for +getting the name of the type, method tables, and if it is reference counted. +When you use this, you either must also use +the RMLUI_LUATYPE_DEFINE macro, or make sure that the function signatures are @em exact.*/ +#define RMLUI_LUATYPE_DECLARE(type) \ + template<> RMLUILUA_API const char* GetTClassName(); \ + template<> RMLUILUA_API RegType* GetMethodTable(); \ + template<> RMLUILUA_API luaL_Reg* GetAttrTable(); \ + template<> RMLUILUA_API luaL_Reg* SetAttrTable(); \ + + +namespace Rml { +namespace Lua { +//replacement for luaL_Reg that uses a different function pointer signature, but similar syntax +template +struct RMLUILUA_API RegType +{ + const char* name; + int (*ftnptr)(lua_State*,T*); +}; + +/** For all of the methods available from Lua that call to the C functions. */ +template RMLUILUA_API RegType* GetMethodTable(); +/** For all of the function that 'get' an attribute/property */ +template RMLUILUA_API luaL_Reg* GetAttrTable(); +/** For all of the functions that 'set' an attribute/property */ +template RMLUILUA_API luaL_Reg* SetAttrTable(); +/** String representation of the class */ +template RMLUILUA_API const char* GetTClassName(); + +/** gets called from the LuaType::Register function, right before @c _regfunctions. +If you want to inherit from another class, in the function you would want +to call @c _regfunctions, where method is metatable_index - 1. Anything +that has the same name in the subclass will be overwrite whatever had the +same name in the superclass. */ +template RMLUILUA_API void ExtraInit(lua_State* L, int metatable_index); + +/** + This is mostly the definition of the Lua userdata that C++ gives to the user, plus + some helper functions. + + @author Nathan Starkey +*/ +template +class RMLUILUA_API LuaType +{ +public: + typedef int (*ftnptr)(lua_State* L, T* ptr); + /** replacement for luaL_Reg that uses a different function pointer signature, but similar syntax */ + typedef struct { const char* name; ftnptr func; } RegType; + + /** Registers the type T as a type in the Lua global namespace by creating a + metatable with the same name as the class, setting the metatmethods, and adding the + functions from _regfunctions */ + static inline void Register(lua_State *L); + /** Pushes on to the Lua stack a userdata representing a pointer of T + @param obj[in] The object to push to the stack + @param gc[in] If the obj should be deleted or decrease reference count upon the garbage collection + metamethod being called from the object in Lua + @return Position on the stack where the userdata resides */ + static inline int push(lua_State *L, T* obj, bool gc=false); + /** Statically casts the item at the position on the Lua stack + @param narg[in] Position of the item to cast on the Lua stack + @return A pointer to an object of type T or @c nullptr */ + static inline T* check(lua_State* L, int narg); + + /** For calling a C closure with upvalues. Used by the functions defined by RegType + @return The value that RegType.func returns */ + static inline int thunk(lua_State* L); + /** String representation of the pointer. Called by the __tostring metamethod */ + static inline void tostring(char* buff, size_t buff_size, void* obj); + //these are metamethods + /** The __gc metamethod. If the object was pushed by push(lua_State*,T*,bool) with the third + argument as true, it will either decrease the reference count or call delete depending on if + the type is reference counted. If the third argument to push was false, then this does nothing. + @return 0, since it pushes nothing on to the stack*/ + static inline int gc_T(lua_State* L); + /** The __tostring metamethod. + @return 1, because it pushes a string representation of the userdata on to the stack */ + static inline int tostring_T(lua_State* L); + /** The __index metamethod. Called whenever the user attempts to access a variable that is + not in the immediate table. This handles the method calls and calls tofunctions in __getters */ + static inline int index(lua_State* L); + /** The __newindex metamethod. Called when the user attempts to set a variable that is not + int the immediate table. This handles the calls to functions in __setters */ + static inline int newindex(lua_State* L); + + /** Registers methods,getters,and setters to the type. In Lua, the methods exist in the Type name's + metatable, and the getters exist in __getters and setters in __setters. The reason for __getters and __setters + is to have the objects use a 'dot' syntax for properties and a 'colon' syntax for methods.*/ + static inline void _regfunctions(lua_State* L, int meta, int method); + +private: + static constexpr size_t max_pointer_string_size = 32; + + LuaType(); //hide constructor +}; + +namespace LuaTypeImpl { +RMLUILUA_API int index(lua_State* L, const char* class_name); +RMLUILUA_API int newindex(lua_State* L, const char* class_name); +} + +} // namespace Lua +} // namespace Rml + +#include "LuaType.inl" +#endif \ No newline at end of file diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/LuaType.inl b/thirdparty/RmlUi/Include/RmlUi/Lua/LuaType.inl new file mode 100644 index 000000000..ab01f6625 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/LuaType.inl @@ -0,0 +1,261 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +namespace Rml { +namespace Lua { + +template +void LuaType::Register(lua_State* L) +{ + //for annotations, starting at 1, but it is a relative value, not always 1 + lua_newtable(L); //[1] = table + int methods = lua_gettop(L); //methods = 1 + + luaL_newmetatable(L, GetTClassName()); //[2] = metatable named , referred in here by ClassMT + int metatable = lua_gettop(L); //metatable = 2 + + luaL_newmetatable(L, "DO NOT TRASH"); //[3] = metatable named "DO NOT TRASH" + lua_pop(L,1); //remove the above metatable -> [-1 = 2] + + //store method table in globals so that scripts can add functions written in Lua + lua_pushvalue(L, methods); //[methods = 1] -> [3] = copy (reference) of methods table + lua_setglobal(L, GetTClassName()); // -> = [3 = 1], pop top [3] + + //hide metatable from Lua getmetatable() + lua_pushvalue(L, methods); //[methods = 1] -> [3] = copy of methods table, including modifications above + lua_setfield(L, metatable, "__metatable"); //[metatable = 2] -> t[k] = v; t = [2 = ClassMT], k = "__metatable", v = [3 = 1]; pop [3] + + lua_pushcfunction(L, index); //index = cfunction -> [3] = cfunction + lua_setfield(L, metatable, "__index"); //[metatable = 2] -> t[k] = v; t = [2], k = "__index", v = cfunc; pop [3] + + lua_pushcfunction(L, newindex); + lua_setfield(L, metatable, "__newindex"); + + lua_pushcfunction(L, gc_T); + lua_setfield(L, metatable, "__gc"); + + lua_pushcfunction(L, tostring_T); + lua_setfield(L, metatable, "__tostring"); + + ExtraInit(L,metatable); //optionally implemented by individual types + + lua_newtable(L); //for method table -> [3] = this table + lua_setmetatable(L, methods); //[methods = 1] -> metatable for [1] is [3]; [3] is popped off, top = [2] + + _regfunctions(L,metatable,methods); + + lua_pop(L, 2); //remove the two items from the stack, [1 = methods] and [2 = metatable] +} + + +template +int LuaType::push(lua_State *L, T* obj, bool gc) +{ + //for annotations, starting at index 1, but it is a relative number, not always 1 + if (!obj) { lua_pushnil(L); return lua_gettop(L); } + luaL_getmetatable(L, GetTClassName()); // lookup metatable in Lua registry ->[1] = metatable of + if (lua_isnil(L, -1)) luaL_error(L, "%s missing metatable", GetTClassName()); + int mt = lua_gettop(L); //mt = 1 + T** ptrHold = (T**)lua_newuserdata(L,sizeof(T**)); //->[2] = empty userdata + int ud = lua_gettop(L); //ud = 2 + if(ptrHold != nullptr) + { + *ptrHold = obj; + lua_pushvalue(L, mt); // ->[3] = copy of [1] + lua_setmetatable(L, -2); //[-2 = 2] -> [2]'s metatable = [3]; pop [3] + char name[max_pointer_string_size]; + tostring(name, max_pointer_string_size, obj); + lua_getfield(L,LUA_REGISTRYINDEX,"DO NOT TRASH"); //->[3] = value returned from function + if(lua_isnil(L,-1) ) //if [3] hasn't been created yet, then create it + { + luaL_newmetatable(L,"DO NOT TRASH"); //[4] = the new metatable + lua_pop(L,1); //pop [4] + } + lua_pop(L,1); //pop [3] + lua_getfield(L,LUA_REGISTRYINDEX,"DO NOT TRASH"); //->[3] = value returned from function + if(gc == false) //if we shouldn't garbage collect it, then put the name in to [3] + { + lua_pushboolean(L,1);// ->[4] = true + lua_setfield(L,-2,name); //represents t[k] = v, [-2 = 3] = t -> v = [4], k = ; pop [4] + } + else + { + //In case this is an address that has been pushed + //to lua before, we need to set it to nil + lua_pushnil(L); // ->[4] = nil + lua_setfield(L,-2,name); //represents t[k] = v, [-2 = 3] = t -> v = [4], k = ; pop [4] + } + + lua_pop(L,1); // -> pop [3] + } + lua_settop(L,ud); //[ud = 2] -> remove everything that is above 2, top = [2] + lua_replace(L, mt); //[mt = 1] -> move [2] to pos [1], and pop previous [1] + lua_settop(L, mt); //remove everything above [1] + return mt; // index of userdata containing pointer to T object +} + + +template +T* LuaType::check(lua_State* L, int narg) +{ + T** ptrHold = static_cast(lua_touserdata(L,narg)); + if(ptrHold == nullptr) + return nullptr; + return (*ptrHold); +} + + +//private members + +template +int LuaType::thunk(lua_State* L) +{ + // stack has userdata, followed by method args + T *obj = check(L, 1); // get 'self', or if you prefer, 'this' + lua_remove(L, 1); // remove self so member function args start at index 1 + // get member function from upvalue + RegType *l = static_cast(lua_touserdata(L, lua_upvalueindex(1))); + //at the moment, there isn't a case where nullptr is acceptable to be used in the function, so check + //for it here, rather than individually for each function + if(obj == nullptr) + { + lua_pushnil(L); + return 1; + } + else + return l->func(L,obj); // call member function +} + + + +template +void LuaType::tostring(char* buff, size_t buff_size, void* obj) +{ + snprintf(buff, buff_size, "%p", obj); +} + + +template +int LuaType::gc_T(lua_State* L) +{ + T * obj = check(L,1); //[1] = this userdata + if(obj == nullptr) + return 0; + + lua_getfield(L,LUA_REGISTRYINDEX,"DO NOT TRASH"); //->[2] = return value from this + if(lua_istable(L,-1) ) //[-1 = 2], if it is a table + { + char name[max_pointer_string_size]; + tostring(name, max_pointer_string_size, obj); + lua_getfield(L,-1,name); //[-1 = 2] -> [3] = the value returned from if exists in the table to not gc + if(lua_isnoneornil(L,-1) ) //[-1 = 3] if it doesn't exist, then we are free to garbage collect c++ side + { + delete obj; + obj = nullptr; + } + } + lua_pop(L,3); //balance function + return 0; +} + + +template +int LuaType::tostring_T(lua_State* L) +{ + char buff[max_pointer_string_size]; + T** ptrHold = (T**)lua_touserdata(L,1); + void* obj = static_cast(*ptrHold); + snprintf(buff, max_pointer_string_size, "%p", obj); + lua_pushfstring(L, "%s (%s)", GetTClassName(), buff); + return 1; +} + + +template +int LuaType::index(lua_State* L) +{ + const char* class_name = GetTClassName(); + return LuaTypeImpl::index(L, class_name); +} + +template +int LuaType::newindex(lua_State* L) +{ + const char* class_name = GetTClassName(); + return LuaTypeImpl::newindex(L, class_name); +} + + +template +void LuaType::_regfunctions(lua_State* L, int /*meta*/, int methods) +{ + //fill method table with methods. + for(RegType* m = (RegType*)GetMethodTable(); m->name; m++) + { + lua_pushstring(L, m->name); // ->[1] = name of function Lua side + lua_pushlightuserdata(L, (void*)m); // ->[2] = pointer to the object containing the name and the function pointer as light userdata + lua_pushcclosure(L, thunk, 1); //thunk = function pointer -> pop 1 item from stack, [2] = closure + lua_settable(L, methods); // represents t[k] = v, t = [methods] -> pop [2 = closure] to be v, pop [1 = name] to be k + } + + + lua_getfield(L,methods, "__getters"); // -> table[1] + if(lua_isnoneornil(L,-1)) + { + lua_pop(L,1); //pop unsuccessful get + lua_newtable(L); // -> table [1] + lua_setfield(L,methods,"__getters"); // pop [1] + lua_getfield(L,methods,"__getters"); // -> table [1] + } + for(luaL_Reg* m = (luaL_Reg*)GetAttrTable(); m->name; m++) + { + lua_pushcfunction(L,m->func); // -> [2] is this function + lua_setfield(L,-2,m->name); //[-2 = 1] -> __getters.name = function + } + lua_pop(L,1); //pop __getters + + + lua_getfield(L,methods, "__setters"); // -> table[1] + if(lua_isnoneornil(L,-1)) + { + lua_pop(L,1); //pop unsuccessful get + lua_newtable(L); // -> table [1] + lua_setfield(L,methods,"__setters"); // pop [1] + lua_getfield(L,methods,"__setters"); // -> table [1] + } + for(luaL_Reg* m = (luaL_Reg*)SetAttrTable(); m->name; m++) + { + lua_pushcfunction(L,m->func); // -> [2] is this function + lua_setfield(L,-2,m->name); //[-2 = 1] -> __setters.name = function + } + lua_pop(L,1); //pop __setters +} + + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Include/RmlUi/Lua/Utilities.h b/thirdparty/RmlUi/Include/RmlUi/Lua/Utilities.h new file mode 100644 index 000000000..b202f1971 --- /dev/null +++ b/thirdparty/RmlUi/Include/RmlUi/Lua/Utilities.h @@ -0,0 +1,80 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_UTILITIES_H +#define RMLUI_LUA_UTILITIES_H +/* + This file is for free-floating functions that are used across more than one file. +*/ +#include "Header.h" +#include "IncludeLua.h" +#include "LuaType.h" +#include + +namespace Rml { +namespace Lua { + +/** casts the variant to its specific type before pushing it to the stack +@relates LuaType */ +void RMLUILUA_API PushVariant(lua_State* L, const Variant* var); + +/** If there are errors on the top of the stack, this will print those out to the log. +@param L A Lua state, and if not passed in, will use the Interpreter's state +@param place A string that will be printed to the log right before the error message, seperated by a space. Set +this when you would get no information about where the error happens. +@relates Interpreter */ +void RMLUILUA_API Report(lua_State* L = nullptr, const String& place = ""); + +//Helper function, so that the types don't have to define individual functions themselves +// to fill the Elements.As table +template +int CastFromElementTo(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + LuaType::push(L,(ToType*)ele,false); + return 1; +} + +//Adds to the Element.As table the name of the type, and the function to use to cast +template +void AddTypeToElementAsTable(lua_State* L) +{ + int top = lua_gettop(L); + lua_getglobal(L,"Element"); + lua_getfield(L,-1,"As"); + if(!lua_isnoneornil(L,-1)) + { + lua_pushcfunction(L,CastFromElementTo); + lua_setfield(L,-2,GetTClassName()); + } + lua_settop(L,top); //pop "As" and "Element" +} +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/LICENSE b/thirdparty/RmlUi/LICENSE new file mode 100644 index 000000000..9f07e5fb9 --- /dev/null +++ b/thirdparty/RmlUi/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2008-2014 CodePoint Ltd, Shift Technology Ltd, and contributors +Copyright (c) 2019 The RmlUi Team, and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/thirdparty/RmlUi/Source/Core/BaseXMLParser.cpp b/thirdparty/RmlUi/Source/Core/BaseXMLParser.cpp new file mode 100644 index 000000000..5a7e24e1b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/BaseXMLParser.cpp @@ -0,0 +1,563 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/BaseXMLParser.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/Stream.h" +#include "XMLParseTools.h" +#include + +namespace Rml { + +BaseXMLParser::BaseXMLParser() +{} + +BaseXMLParser::~BaseXMLParser() +{} + +// Registers a tag as containing general character data. +void BaseXMLParser::RegisterCDATATag(const String& tag) +{ + if (!tag.empty()) + cdata_tags.insert(StringUtilities::ToLower(tag)); +} + +void BaseXMLParser::RegisterInnerXMLAttribute(const String& attribute_name) +{ + attributes_for_inner_xml_data.insert(attribute_name); +} + +// Parses the given stream as an XML file, and calls the handlers when +// interesting phenomenon are encountered. +void BaseXMLParser::Parse(Stream* stream) +{ + source_url = &stream->GetSourceURL(); + + xml_source.clear(); + + // We read in the whole XML file here. + // TODO: It doesn't look like the Stream interface is used for anything useful. We + // might as well just use a span or StringView, and get completely rid of it. + // @performance Otherwise, use the temporary allocator. + const size_t source_size = stream->Length(); + stream->Read(xml_source, source_size); + + xml_index = 0; + line_number = 1; + line_number_open_tag = 1; + + inner_xml_data = false; + inner_xml_data_terminate_depth = 0; + inner_xml_data_index_begin = 0; + + // Read (er ... skip) the header, if one exists. + ReadHeader(); + // Read the XML body. + ReadBody(); + + xml_source.clear(); + source_url = nullptr; +} + +// Get the current file line number +int BaseXMLParser::GetLineNumber() const +{ + return line_number; +} + +int BaseXMLParser::GetLineNumberOpenTag() const +{ + return line_number_open_tag; +} + +// Called when the parser finds the beginning of an element tag. +void BaseXMLParser::HandleElementStart(const String& RMLUI_UNUSED_PARAMETER(name), const XMLAttributes& RMLUI_UNUSED_PARAMETER(attributes)) +{ + RMLUI_UNUSED(name); + RMLUI_UNUSED(attributes); +} + +// Called when the parser finds the end of an element tag. +void BaseXMLParser::HandleElementEnd(const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(name); +} + +// Called when the parser encounters data. +void BaseXMLParser::HandleData(const String& RMLUI_UNUSED_PARAMETER(data), XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(data); + RMLUI_UNUSED(type); +} + +/// Returns the source URL of this parse. Only valid during parsing. + +const URL* BaseXMLParser::GetSourceURLPtr() const +{ + return source_url; +} + +void BaseXMLParser::Next() { + xml_index += 1; +} + +bool BaseXMLParser::AtEnd() const { + return xml_index >= xml_source.size(); +} + +char BaseXMLParser::Look() const { + RMLUI_ASSERT(!AtEnd()); + return xml_source[xml_index]; +} + +void BaseXMLParser::HandleElementStartInternal(const String& name, const XMLAttributes& attributes) +{ + if (!inner_xml_data) + HandleElementStart(name, attributes); +} + +void BaseXMLParser::HandleElementEndInternal(const String& name) +{ + if (!inner_xml_data) + HandleElementEnd(name); +} + +void BaseXMLParser::HandleDataInternal(const String& data, XMLDataType type) +{ + if (!inner_xml_data) + HandleData(data, type); +} + +void BaseXMLParser::ReadHeader() +{ + if (PeekString("", temp); + } +} + +void BaseXMLParser::ReadBody() +{ + RMLUI_ZoneScoped; + + open_tag_depth = 0; + line_number_open_tag = 0; + + for(;;) + { + // Find the next open tag. + if (!FindString("<", data, true)) + break; + + const size_t xml_index_tag = xml_index - 1; + + // Check what kind of tag this is. + if (PeekString("!--")) + { + // Comment. + String temp; + if (!FindString("-->", temp)) + break; + } + else if (PeekString("![CDATA[")) + { + // CDATA tag; read everything (including markup) until the ending + // CDATA tag. + if (!ReadCDATA()) + break; + } + else if (PeekString("/")) + { + if (!ReadCloseTag(xml_index_tag)) + break; + + // Bail if we've hit the end of the XML data. + if (open_tag_depth == 0) + break; + } + else + { + if (ReadOpenTag()) + line_number_open_tag = line_number; + else + break; + } + } + + // Check for error conditions + if (open_tag_depth > 0) + { + Log::Message(Log::LT_WARNING, "XML parse error on line %d of %s.", GetLineNumber(), source_url->GetURL().c_str()); + } +} + +bool BaseXMLParser::ReadOpenTag() +{ + // Increase the open depth + open_tag_depth++; + + // Opening tag; send data immediately and open the tag. + if (!data.empty()) + { + HandleDataInternal(data, XMLDataType::Text); + data.clear(); + } + + String tag_name; + if (!FindWord(tag_name, "/>")) + return false; + + bool section_opened = false; + + if (PeekString(">")) + { + // Simple open tag. + HandleElementStartInternal(tag_name, XMLAttributes()); + section_opened = true; + } + else if (PeekString("/") && + PeekString(">")) + { + // Empty open tag. + HandleElementStartInternal(tag_name, XMLAttributes()); + HandleElementEndInternal(tag_name); + + // Tag immediately closed, reduce count + open_tag_depth--; + } + else + { + // It appears we have some attributes. Let's parse them. + bool parse_inner_xml_as_data = false; + XMLAttributes attributes; + if (!ReadAttributes(attributes, parse_inner_xml_as_data)) + return false; + + if (PeekString(">")) + { + HandleElementStartInternal(tag_name, attributes); + section_opened = true; + } + else if (PeekString("/") && + PeekString(">")) + { + HandleElementStartInternal(tag_name, attributes); + HandleElementEndInternal(tag_name); + + // Tag immediately closed, reduce count + open_tag_depth--; + } + else + { + return false; + } + + if (section_opened && parse_inner_xml_as_data && !inner_xml_data) + { + inner_xml_data = true; + inner_xml_data_terminate_depth = open_tag_depth; + inner_xml_data_index_begin = xml_index; + } + } + + // Check if this tag needs to be processed as CDATA. + if (section_opened) + { + const String lcase_tag_name = StringUtilities::ToLower(tag_name); + bool is_cdata_tag = (cdata_tags.find(lcase_tag_name) != cdata_tags.end()); + + if (is_cdata_tag) + { + if (ReadCDATA(lcase_tag_name.c_str())) + { + open_tag_depth--; + if (!data.empty()) + { + HandleDataInternal(data, XMLDataType::CData); + data.clear(); + } + HandleElementEndInternal(tag_name); + + return true; + } + + return false; + } + } + + return true; +} + +bool BaseXMLParser::ReadCloseTag(const size_t xml_index_tag) +{ + if (inner_xml_data && open_tag_depth == inner_xml_data_terminate_depth) + { + // Closing the tag that initiated the inner xml data parsing. Set all its contents as Data to be + // submitted next, and disable the mode to resume normal parsing behavior. + RMLUI_ASSERT(inner_xml_data_index_begin <= xml_index_tag); + inner_xml_data = false; + data = xml_source.substr(inner_xml_data_index_begin, xml_index_tag - inner_xml_data_index_begin); + HandleDataInternal(data, XMLDataType::InnerXML); + data.clear(); + } + + // Closing tag; send data immediately and close the tag. + if (!data.empty()) + { + HandleDataInternal(data, XMLDataType::Text); + data.clear(); + } + + String tag_name; + if (!FindString(">", tag_name)) + return false; + + HandleElementEndInternal(StringUtilities::StripWhitespace(tag_name)); + + + // Tag closed, reduce count + open_tag_depth--; + + + return true; +} + +bool BaseXMLParser::ReadAttributes(XMLAttributes& attributes, bool& parse_raw_xml_content) +{ + for (;;) + { + String attribute; + String value; + + // Get the attribute name + if (!FindWord(attribute, "=/>")) + { + return false; + } + + // Check if theres an assigned value + if (PeekString("=")) + { + if (PeekString("\"")) + { + if (!FindString("\"", value)) + return false; + } + else if (PeekString("'")) + { + if (!FindString("'", value)) + return false; + } + else if (!FindWord(value, "/>")) + { + return false; + } + } + + if (attributes_for_inner_xml_data.count(attribute) == 1) + parse_raw_xml_content = true; + + attributes[attribute] = value; + + // Check for the end of the tag. + if (PeekString("/", false) || PeekString(">", false)) + return true; + } +} + +bool BaseXMLParser::ReadCDATA(const char* tag_terminator) +{ + String cdata; + if (tag_terminator == nullptr) + { + FindString("]]>", cdata); + data += cdata; + return true; + } + else + { + for (;;) + { + // Search for the next tag opening. + if (!FindString("<", cdata)) + return false; + + if (PeekString("/", false)) + { + String tag; + if (FindString(">", tag)) + { + size_t slash_pos = tag.find('/'); + String tag_name = StringUtilities::StripWhitespace(slash_pos == String::npos ? tag : tag.substr(slash_pos + 1)); + if (StringUtilities::ToLower(tag_name) == tag_terminator) + { + data += cdata; + return true; + } + else + { + cdata += '<' + tag + '>'; + } + } + else + cdata += "<"; + } + else + cdata += "<"; + } + } +} + +// Reads from the stream until a complete word is found. +bool BaseXMLParser::FindWord(String& word, const char* terminators) +{ + while (!AtEnd()) + { + char c = Look(); + + // Ignore white space + if (StringUtilities::IsWhitespace(c)) + { + if (word.empty()) + { + Next(); + continue; + } + else + return true; + } + + // Check for termination condition + if (terminators && strchr(terminators, c)) + { + return !word.empty(); + } + + word += c; + Next(); + } + + return false; +} + +// Reads from the stream until the given character set is found. +bool BaseXMLParser::FindString(const char* string, String& data, bool escape_brackets) +{ + int index = 0; + bool in_brackets = false; + char previous = 0; + + while (string[index]) + { + if (AtEnd()) + return false; + + const char c = Look(); + + // Count line numbers + if (c == '\n') + { + line_number++; + } + + if(escape_brackets) + { + const char* error_str = XMLParseTools::ParseDataBrackets(in_brackets, c, previous); + if (error_str) + { + Log::Message(Log::LT_WARNING, "XML parse error. %s", error_str); + return false; + } + } + + if (c == string[index] && !in_brackets) + { + index += 1; + } + else + { + if (index > 0) + { + data += String(string, index); + index = 0; + } + + data += c; + } + + previous = c; + Next(); + } + + return true; +} + +// Returns true if the next sequence of characters in the stream matches the +// given string. +bool BaseXMLParser::PeekString(const char* string, bool consume) +{ + const size_t start_index = xml_index; + bool success = true; + int i = 0; + while (string[i]) + { + if (AtEnd()) + { + success = false; + break; + } + + const char c = Look(); + + // Seek past all the whitespace if we haven't hit the initial character yet. + if (i == 0 && StringUtilities::IsWhitespace(c)) + { + Next(); + } + else + { + if (c != string[i]) + { + success = false; + break; + } + + i++; + Next(); + } + } + + // Set the index to the start index unless we are consuming. + if (!consume || !success) + xml_index = start_index; + + return success; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Box.cpp b/thirdparty/RmlUi/Source/Core/Box.cpp new file mode 100644 index 000000000..020d56c11 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Box.cpp @@ -0,0 +1,129 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Box.h" +#include + +namespace Rml { + +// Initialises a zero-sized box. +Box::Box() : content(0, 0), offset(0, 0) +{ + memset(area_edges, 0, sizeof(area_edges)); +} + +// Initialises a box with a default content area and no padding, borders and margins. +Box::Box(const Vector2f& content) : content(content), offset(0, 0) +{ + memset(area_edges, 0, sizeof(area_edges)); +} + +Box::~Box() +{ +} + +// Returns the offset of this box. This will usually be (0, 0). +const Vector2f& Box::GetOffset() const +{ + return offset; +} + +// Returns the top-left position of one of the areas. +Vector2f Box::GetPosition(Area area) const +{ + Vector2f area_position(offset.x - area_edges[MARGIN][LEFT], offset.y - area_edges[MARGIN][TOP]); + for (int i = 0; i < area; i++) + { + area_position.x += area_edges[i][LEFT]; + area_position.y += area_edges[i][TOP]; + } + + return area_position; +} + +// Returns the size of one of the box's areas. This will include all inner areas. +Vector2f Box::GetSize(Area area) const +{ + Vector2f area_size(content); + for (int i = PADDING; i >= area; i--) + { + area_size.x += (area_edges[i][LEFT] + area_edges[i][RIGHT]); + area_size.y += (area_edges[i][TOP] + area_edges[i][BOTTOM]); + } + + return area_size; +} + +// Sets the offset of the box, relative usually to the owning element. +void Box::SetOffset(const Vector2f& _offset) +{ + offset = _offset; +} + +// Sets the size of the content area. +void Box::SetContent(const Vector2f& _content) +{ + content = _content; +} + +// Sets the size of one of the segments of one of the box's outer areas. +void Box::SetEdge(Area area, Edge edge, float size) +{ + area_edges[area][edge] = size; +} + +// Returns the size of one of the area segments. +float Box::GetEdge(Area area, Edge edge) const +{ + return area_edges[area][edge]; +} + +// Returns the cumulative size of one edge up to one of the box's areas. +float Box::GetCumulativeEdge(Area area, Edge edge) const +{ + float size = 0; + int max_area = Math::Min((int)area, (int)PADDING); + for (int i = 0; i <= max_area; i++) + size += area_edges[i][edge]; + + return size; +} + +// Compares the size of the content area and the other area edges. +bool Box::operator==(const Box& rhs) const +{ + return content == rhs.content && memcmp(area_edges, rhs.area_edges, sizeof(area_edges)) == 0; +} + +// Compares the size of the content area and the other area edges. +bool Box::operator!=(const Box& rhs) const +{ + return !(*this == rhs); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Clock.cpp b/thirdparty/RmlUi/Source/Core/Clock.cpp new file mode 100644 index 000000000..26027aeea --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Clock.cpp @@ -0,0 +1,44 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Clock.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" + +namespace Rml { + +RMLUICORE_API double Clock::GetElapsedTime() +{ + SystemInterface* system_interface = GetSystemInterface(); + if (system_interface != nullptr) + return system_interface->GetElapsedTime(); + else + return 0; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Clock.h b/thirdparty/RmlUi/Source/Core/Clock.h new file mode 100644 index 000000000..2223a4f46 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Clock.h @@ -0,0 +1,50 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_CLOCK_H +#define RMLUI_CORE_CLOCK_H + +#include "../../Include/RmlUi/Core/Header.h" + +namespace Rml { + +/** + RmlUi's Interface to Time. + + @author Lloyd Weehuizen + */ +class Clock +{ +public: + /// Get the elapsed time since application startup + /// @return Seconds elapsed since application startup. + RMLUICORE_API static double GetElapsedTime(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ComputeProperty.cpp b/thirdparty/RmlUi/Source/Core/ComputeProperty.cpp new file mode 100644 index 000000000..051af9752 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ComputeProperty.cpp @@ -0,0 +1,301 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Property.h" +#include "ComputeProperty.h" + +namespace Rml { + +const Style::ComputedValues DefaultComputedValues = Style::ComputedValues{}; + +static constexpr float PixelsPerInch = 96.0f; + + + +float ResolveValue(Style::LengthPercentageAuto length, float base_value) +{ + if (length.type == Style::LengthPercentageAuto::Length) + return length.value; + else if (length.type == Style::LengthPercentageAuto::Percentage) + return length.value * 0.01f * base_value; + return 0.0f; +} + +float ResolveValue(Style::LengthPercentage length, float base_value) +{ + if (length.type == Style::LengthPercentage::Length) + return length.value; + else if (length.type == Style::LengthPercentage::Percentage) + return length.value * 0.01f * base_value; + return 0.0f; +} + + +float ComputeLength(const Property* property, float font_size, float document_font_size, float dp_ratio) +{ + RMLUI_ASSERT(property); + + float value = property->value.Get(); + + switch (property->unit) + { + case Property::NUMBER: + case Property::PX: + case Property::RAD: + return value; + + case Property::EM: + return value * font_size; + case Property::REM: + return value * document_font_size; + case Property::DP: + return value * dp_ratio; + + case Property::DEG: + return Math::DegreesToRadians(value); + default: + break; + } + + // Values based on pixels-per-inch. + if (property->unit & Property::PPI_UNIT) + { + float inch = value * PixelsPerInch; + + switch (property->unit) + { + case Property::INCH: // inch + return inch; + case Property::CM: // centimeter + return inch * (1.0f / 2.54f); + case Property::MM: // millimeter + return inch * (1.0f / 25.4f); + case Property::PT: // point + return inch * (1.0f / 72.0f); + case Property::PC: // pica + return inch * (1.0f / 6.0f); + default: + break; + } + } + + // We're not a numeric property; return 0. + return 0.0f; +} + +float ComputeAbsoluteLength(const Property& property, float dp_ratio) +{ + RMLUI_ASSERT(property.unit & Property::ABSOLUTE_LENGTH); + + switch (property.unit) + { + case Property::PX: + return property.value.Get< float >(); + case Property::DP: + return property.value.Get< float >()* dp_ratio; + default: + // Values based on pixels-per-inch. + if (property.unit & Property::PPI_UNIT) + { + float inch = property.value.Get< float >() * PixelsPerInch; + + switch (property.unit) + { + case Property::INCH: // inch + return inch; + case Property::CM: // centimeter + return inch * (1.0f / 2.54f); + case Property::MM: // millimeter + return inch * (1.0f / 25.4f); + case Property::PT: // point + return inch * (1.0f / 72.0f); + case Property::PC: // pica + return inch * (1.0f / 6.0f); + default: + break; + } + } + } + + RMLUI_ERROR; + return 0.0f; +} + +float ComputeAngle(const Property& property) +{ + float value = property.value.Get(); + + switch (property.unit) + { + case Property::NUMBER: + case Property::RAD: + return value; + + case Property::DEG: + return Math::DegreesToRadians(value); + default: + break; + } + + return 0.0f; +} + +float ComputeFontsize(const Property& property, const Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, float dp_ratio) +{ + // The calculated value of the font-size property is inherited, so we need to check if this + // is an inherited property. If so, then we return our parent's font size instead. + if (property.unit & Property::RELATIVE_UNIT) + { + float multiplier = 1.0f; + + switch (property.unit) + { + case Property::PERCENT: + multiplier = 0.01f; + //-fallthrough + case Property::EM: + if (!parent_values) + return 0; + return property.value.Get< float >() * multiplier * parent_values->font_size; + + case Property::REM: + if (!document_values) + return 0; + // If the current element is a document, the rem unit is relative to the default size + if(&values == document_values) + return property.value.Get< float >() * DefaultComputedValues.font_size; + // Otherwise it is relative to the document font size + return property.value.Get< float >() * document_values->font_size; + default: + RMLUI_ERRORMSG("A relative unit must be percentage, em or rem."); + } + } + + return ComputeAbsoluteLength(property, dp_ratio); +} + +Style::Clip ComputeClip(const Property* property) +{ + int value = property->Get(); + if (property->unit == Property::KEYWORD) + return Style::Clip(static_cast(value)); + else if (property->unit == Property::NUMBER) + return Style::Clip(Style::Clip::Type::Number, value); + RMLUI_ERRORMSG("Invalid clip type"); + return Style::Clip(); +} + +Style::LineHeight ComputeLineHeight(const Property* property, float font_size, float document_font_size, float dp_ratio) +{ + if (property->unit & Property::LENGTH) + { + float value = ComputeLength(property, font_size, document_font_size, dp_ratio); + return Style::LineHeight(value, Style::LineHeight::Length, value); + } + + float scale_factor = 1.0f; + + switch (property->unit) + { + case Property::NUMBER: + scale_factor = property->value.Get< float >(); + break; + case Property::PERCENT: + scale_factor = property->value.Get< float >() * 0.01f; + break; + default: + RMLUI_ERRORMSG("Invalid unit for line-height"); + } + + float value = font_size * scale_factor; + return Style::LineHeight(value, Style::LineHeight::Number, scale_factor); +} + +Style::VerticalAlign ComputeVerticalAlign(const Property* property, float line_height, float font_size, float document_font_size, float dp_ratio) +{ + if (property->unit & Property::LENGTH) + { + float value = ComputeLength(property, font_size, document_font_size, dp_ratio); + return Style::VerticalAlign(value); + } + else if (property->unit & Property::PERCENT) + { + return Style::VerticalAlign(property->Get() * line_height); + } + + RMLUI_ASSERT(property->unit & Property::KEYWORD); + return Style::VerticalAlign((Style::VerticalAlign::Type)property->Get()); +} + +Style::LengthPercentage ComputeLengthPercentage(const Property* property, float font_size, float document_font_size, float dp_ratio) +{ + using namespace Style; + if (property->unit & Property::PERCENT) + return LengthPercentage(LengthPercentage::Percentage, property->Get()); + + return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio)); +} + + +Style::LengthPercentageAuto ComputeLengthPercentageAuto(const Property* property, float font_size, float document_font_size, float dp_ratio) +{ + using namespace Style; + // Assuming here that 'auto' is the only possible keyword + if (property->unit & Property::PERCENT) + return LengthPercentageAuto(LengthPercentageAuto::Percentage, property->Get()); + else if (property->unit & Property::KEYWORD) + return LengthPercentageAuto(LengthPercentageAuto::Auto); + + return LengthPercentageAuto(LengthPercentageAuto::Length, ComputeLength(property, font_size, document_font_size, dp_ratio)); +} + +Style::LengthPercentage ComputeOrigin(const Property* property, float font_size, float document_font_size, float dp_ratio) +{ + using namespace Style; + static_assert((int)OriginX::Left == (int)OriginY::Top && (int)OriginX::Center == (int)OriginY::Center && (int)OriginX::Right == (int)OriginY::Bottom, ""); + + if (property->unit & Property::KEYWORD) + { + float percent = 0.0f; + OriginX origin = (OriginX)property->Get(); + switch (origin) + { + case OriginX::Left: percent = 0.0f; break; + case OriginX::Center: percent = 50.0f; break; + case OriginX::Right: percent = 100.f; break; + } + return LengthPercentage(LengthPercentage::Percentage, percent); + } + else if (property->unit & Property::PERCENT) + return LengthPercentage(LengthPercentage::Percentage, property->Get()); + + return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio)); +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ComputeProperty.h b/thirdparty/RmlUi/Source/Core/ComputeProperty.h new file mode 100644 index 000000000..bb9217d90 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ComputeProperty.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_COMPUTEPROPERTY_H +#define RMLUI_CORE_COMPUTEPROPERTY_H + +#include "../../Include/RmlUi/Core/ComputedValues.h" + +namespace Rml { + +class Property; + +// Note that percentages are not lengths! They have to be resolved elsewhere. +float ComputeLength(const Property* property, float font_size, float document_font_size, float dp_ratio); + +float ComputeAbsoluteLength(const Property& property, float dp_ratio); + +float ComputeAngle(const Property& property); + +float ComputeFontsize(const Property& property, const Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, float dp_ratio); + +Style::Clip ComputeClip(const Property* property); + +Style::LineHeight ComputeLineHeight(const Property* property, float font_size, float document_font_size, float dp_ratio); + +Style::VerticalAlign ComputeVerticalAlign(const Property* property, float line_height, float font_size, float document_font_size, float dp_ratio); + +Style::LengthPercentage ComputeLengthPercentage(const Property* property, float font_size, float document_font_size, float dp_ratio); + +Style::LengthPercentageAuto ComputeLengthPercentageAuto(const Property* property, float font_size, float document_font_size, float dp_ratio); + +Style::LengthPercentage ComputeOrigin(const Property* property, float font_size, float document_font_size, float dp_ratio); + +extern const Style::ComputedValues DefaultComputedValues; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Context.cpp b/thirdparty/RmlUi/Source/Core/Context.cpp new file mode 100644 index 000000000..73db8d474 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Context.cpp @@ -0,0 +1,1311 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/ContextInstancer.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/RenderInterface.h" +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "EventDispatcher.h" +#include "EventIterators.h" +#include "PluginRegistry.h" +#include "StreamFile.h" +#include +#include + + +namespace Rml { + +static constexpr float DOUBLE_CLICK_TIME = 0.5f; // [s] +static constexpr float DOUBLE_CLICK_MAX_DIST = 3.f; // [dp] + +Context::Context(const String& name) : name(name), dimensions(0, 0), density_independent_pixel_ratio(1.0f), mouse_position(0, 0), clip_origin(-1, -1), clip_dimensions(-1, -1) +{ + instancer = nullptr; + + // Initialise this to nullptr; this will be set in Rml::CreateContext(). + render_interface = nullptr; + + root = Factory::InstanceElement(nullptr, "*", "#root", XMLAttributes()); + root->SetId(name); + root->SetOffset(Vector2f(0, 0), nullptr); + root->SetProperty(PropertyId::ZIndex, Property(0, Property::NUMBER)); + + cursor_proxy = Factory::InstanceElement(nullptr, documents_base_tag, documents_base_tag, XMLAttributes()); + ElementDocument* cursor_proxy_document = rmlui_dynamic_cast< ElementDocument* >(cursor_proxy.get()); + if (cursor_proxy_document) + cursor_proxy_document->context = this; + else + cursor_proxy.reset(); + + enable_cursor = true; + + document_focus_history.push_back(root.get()); + focus = root.get(); + hover = nullptr; + active = nullptr; + drag = nullptr; + + drag_started = false; + drag_verbose = false; + drag_clone = nullptr; + drag_hover = nullptr; + + last_click_element = nullptr; + last_click_time = 0; + last_click_mouse_position = Vector2i(0, 0); +} + +Context::~Context() +{ + PluginRegistry::NotifyContextDestroy(this); + + UnloadAllDocuments(); + + ReleaseUnloadedDocuments(); + + cursor_proxy.reset(); + + root.reset(); + + instancer = nullptr; + + render_interface = nullptr; +} + +// Returns the name of the context. +const String& Context::GetName() const +{ + return name; +} + +// Changes the dimensions of the screen. +void Context::SetDimensions(const Vector2i& _dimensions) +{ + if (dimensions != _dimensions) + { + dimensions = _dimensions; + root->SetBox(Box(Vector2f((float) dimensions.x, (float) dimensions.y))); + root->DirtyLayout(); + + for (int i = 0; i < root->GetNumChildren(); ++i) + { + ElementDocument* document = root->GetChild(i)->GetOwnerDocument(); + if (document != nullptr) + { + document->DirtyLayout(); + document->DirtyPosition(); + document->DispatchEvent(EventId::Resize, Dictionary()); + } + } + + clip_dimensions = dimensions; + } +} + +// Returns the dimensions of the screen. +const Vector2i& Context::GetDimensions() const +{ + return dimensions; +} + +void Context::SetDensityIndependentPixelRatio(float _density_independent_pixel_ratio) +{ + if (density_independent_pixel_ratio != _density_independent_pixel_ratio) + { + density_independent_pixel_ratio = _density_independent_pixel_ratio; + + for (int i = 0; i < root->GetNumChildren(); ++i) + { + ElementDocument* document = root->GetChild(i)->GetOwnerDocument(); + if (document != nullptr) + { + document->DirtyDpProperties(); + } + } + } +} + +float Context::GetDensityIndependentPixelRatio() const +{ + return density_independent_pixel_ratio; +} + +// Updates all elements in the element tree. +bool Context::Update() +{ + RMLUI_ZoneScoped; + + root->Update(density_independent_pixel_ratio); + + for (int i = 0; i < root->GetNumChildren(); ++i) + if (auto doc = root->GetChild(i)->GetOwnerDocument()) + { + doc->UpdateLayout(); + doc->UpdatePosition(); + } + + // Release any documents that were unloaded during the update. + ReleaseUnloadedDocuments(); + + return true; +} + +// Renders all visible elements in the element tree. +bool Context::Render() +{ + RMLUI_ZoneScoped; + + RenderInterface* render_interface = GetRenderInterface(); + if (render_interface == nullptr) + return false; + + render_interface->context = this; + ElementUtilities::ApplyActiveClipRegion(this, render_interface); + + root->Render(); + + ElementUtilities::SetClippingRegion(nullptr, this); + + // Render the cursor proxy so any elements attached the cursor will be rendered below the cursor. + if (cursor_proxy) + { + static_cast(*cursor_proxy).UpdateDocument(); + cursor_proxy->SetOffset(Vector2f((float)Math::Clamp(mouse_position.x, 0, dimensions.x), + (float)Math::Clamp(mouse_position.y, 0, dimensions.y)), + nullptr); + cursor_proxy->Render(); + } + + render_interface->context = nullptr; + + return true; +} + +// Creates a new, empty document and places it into this context. +ElementDocument* Context::CreateDocument(const String& instancer_name) +{ + ElementPtr element = Factory::InstanceElement(nullptr, instancer_name, documents_base_tag, XMLAttributes()); + if (!element) + { + Log::Message(Log::LT_ERROR, "Failed to instance document on instancer_name '%s', instancer returned nullptr.", instancer_name.c_str()); + return nullptr; + } + + ElementDocument* document = rmlui_dynamic_cast< ElementDocument* >(element.get()); + if (!document) + { + Log::Message(Log::LT_ERROR, "Failed to instance document on instancer_name '%s', Found type '%s', was expecting derivative of ElementDocument.", instancer_name.c_str(), rmlui_type_name(*element)); + return nullptr; + } + + document->context = this; + root->AppendChild(std::move(element)); + + PluginRegistry::NotifyDocumentLoad(document); + + return document; +} + +// Load a document into the context. +ElementDocument* Context::LoadDocument(const String& document_path) +{ + auto stream = MakeUnique(); + + if (!stream->Open(document_path)) + return nullptr; + + ElementDocument* document = LoadDocument(stream.get()); + + return document; +} + +// Load a document into the context. +ElementDocument* Context::LoadDocument(Stream* stream) +{ + PluginRegistry::NotifyDocumentOpen(this, stream->GetSourceURL().GetURL()); + + ElementPtr element = Factory::InstanceDocumentStream(this, stream); + if (!element) + return nullptr; + + ElementDocument* document = static_cast(element.get()); + + root->AppendChild(std::move(element)); + + ElementUtilities::BindEventAttributes(document); + + // The 'load' event is fired before updating the document, because the user might + // need to initalize things before running an update. The drawback is that computed + // values and layouting are not performed yet, resulting in default values when + // querying such information in the event handler. + PluginRegistry::NotifyDocumentLoad(document); + document->DispatchEvent(EventId::Load, Dictionary()); + + document->UpdateDocument(); + + return document; +} + +// Load a document into the context. +ElementDocument* Context::LoadDocumentFromMemory(const String& string) +{ + // Open the stream based on the string contents. + auto stream = MakeUnique((byte*)string.c_str(), string.size()); + stream->SetSourceURL("[document from memory]"); + + // Load the document from the stream. + ElementDocument* document = LoadDocument(stream.get()); + + return document; +} + +// Unload the given document +void Context::UnloadDocument(ElementDocument* _document) +{ + // Has this document already been unloaded? + for (size_t i = 0; i < unloaded_documents.size(); ++i) + { + if (unloaded_documents[i].get() == _document) + return; + } + + ElementDocument* document = _document; + + if (document->GetParentNode() == root.get()) + { + // Dispatch the unload notifications. + document->DispatchEvent(EventId::Unload, Dictionary()); + PluginRegistry::NotifyDocumentUnload(document); + + // Move document to a temporary location to be released later. + unloaded_documents.push_back( root->RemoveChild(document) ); + } + + // Remove the item from the focus history. + ElementList::iterator itr = std::find(document_focus_history.begin(), document_focus_history.end(), document); + if (itr != document_focus_history.end()) + document_focus_history.erase(itr); + + // Focus to the previous document if the old document is the current focus. + if (focus && focus->GetOwnerDocument() == document) + { + focus = nullptr; + document_focus_history.back()->GetFocusLeafNode()->Focus(); + } + + // Clear the active element if the old document is the active element. + if (active && active->GetOwnerDocument() == document) + { + active = nullptr; + } + + // Clear other pointers to elements whose owner was deleted + if (drag && drag->GetOwnerDocument() == document) + { + drag = nullptr; + } + + if (drag_hover && drag_hover->GetOwnerDocument() == document) + { + drag_hover = nullptr; + } + + // Rebuild the hover state. + UpdateHoverChain(Dictionary(), Dictionary(), mouse_position); +} + +// Unload all the currently loaded documents +void Context::UnloadAllDocuments() +{ + // Unload all children. + while (root->GetNumChildren(true) > 0) + UnloadDocument(root->GetChild(0)->GetOwnerDocument()); + + // The element lists may point to elements that are getting removed. + active_chain.clear(); + hover_chain.clear(); + drag_hover_chain.clear(); +} + +// Enables or disables the mouse cursor. +void Context::EnableMouseCursor(bool enable) +{ + // The cursor is set to an invalid name so that it is forced to update in the next update loop. + cursor_name = ":reset:"; + enable_cursor = enable; +} + +// Returns the first document found in the root with the given id. +ElementDocument* Context::GetDocument(const String& id) +{ + for (int i = 0; i < root->GetNumChildren(); i++) + { + ElementDocument* document = root->GetChild(i)->GetOwnerDocument(); + if (document == nullptr) + continue; + + if (document->GetId() == id) + return document; + } + + return nullptr; +} + +// Returns a document in the context by index. +ElementDocument* Context::GetDocument(int index) +{ + Element* element = root->GetChild(index); + if (element == nullptr) + return nullptr; + + return element->GetOwnerDocument(); +} + +// Returns the number of documents in the context. +int Context::GetNumDocuments() const +{ + return root->GetNumChildren(); +} + +// Returns the hover element. +Element* Context::GetHoverElement() +{ + return hover; +} + +// Returns the focus element. +Element* Context::GetFocusElement() +{ + return focus; +} + +// Returns the root element. +Element* Context::GetRootElement() +{ + return root.get(); +} + +// Brings the document to the front of the document stack. +void Context::PullDocumentToFront(ElementDocument* document) +{ + if (document != root->GetLastChild()) + { + // Calling RemoveChild() / AppendChild() would be cleaner, but that dirties the document's layout + // unnecessarily, so we'll go under the hood here. + for (int i = 0; i < root->GetNumChildren(); ++i) + { + if (root->GetChild(i) == document) + { + ElementPtr element = std::move(root->children[i]); + root->children.erase(root->children.begin() + i); + root->children.insert(root->children.begin() + root->GetNumChildren(), std::move(element)); + + root->DirtyStackingContext(); + } + } + } +} + +// Sends the document to the back of the document stack. +void Context::PushDocumentToBack(ElementDocument* document) +{ + if (document != root->GetFirstChild()) + { + // See PullDocumentToFront(). + for (int i = 0; i < root->GetNumChildren(); ++i) + { + if (root->GetChild(i) == document) + { + ElementPtr element = std::move(root->children[i]); + root->children.erase(root->children.begin() + i); + root->children.insert(root->children.begin(), std::move(element)); + + root->DirtyStackingContext(); + } + } + } +} + +void Context::UnfocusDocument(ElementDocument* document) +{ + auto it = std::find(document_focus_history.begin(), document_focus_history.end(), document); + if (it != document_focus_history.end()) + document_focus_history.erase(it); + + if (!document_focus_history.empty()) + document_focus_history.back()->GetFocusLeafNode()->Focus(); +} + +// Adds an event listener to the root element. +void Context::AddEventListener(const String& event, EventListener* listener, bool in_capture_phase) +{ + root->AddEventListener(event, listener, in_capture_phase); +} + +// Removes an event listener from the root element. +void Context::RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase) +{ + root->RemoveEventListener(event, listener, in_capture_phase); +} + +// Sends a key down event into RmlUi. +bool Context::ProcessKeyDown(Input::KeyIdentifier key_identifier, int key_modifier_state) +{ + // Generate the parameters for the key event. + Dictionary parameters; + GenerateKeyEventParameters(parameters, key_identifier); + GenerateKeyModifierEventParameters(parameters, key_modifier_state); + + if (focus) + return focus->DispatchEvent(EventId::Keydown, parameters); + else + return root->DispatchEvent(EventId::Keydown, parameters); +} + +// Sends a key up event into RmlUi. +bool Context::ProcessKeyUp(Input::KeyIdentifier key_identifier, int key_modifier_state) +{ + // Generate the parameters for the key event. + Dictionary parameters; + GenerateKeyEventParameters(parameters, key_identifier); + GenerateKeyModifierEventParameters(parameters, key_modifier_state); + + if (focus) + return focus->DispatchEvent(EventId::Keyup, parameters); + else + return root->DispatchEvent(EventId::Keyup, parameters); +} + +bool Context::ProcessTextInput(char character) +{ + // Only the standard ASCII character set is a valid subset of UTF-8. + if (static_cast(character) > 127) + return false; + return ProcessTextInput(static_cast(character)); +} + +// Sends a single character of text as text input into RmlUi. +bool Context::ProcessTextInput(Character character) +{ + // Generate the parameters for the key event. + String text = StringUtilities::ToUTF8(character); + return ProcessTextInput(text); +} + +// Sends a string of text as text input into RmlUi. +bool Context::ProcessTextInput(const String& string) +{ + Element* target = (focus ? focus : root.get()); + + Dictionary parameters; + parameters["text"] = string; + + bool consumed = target->DispatchEvent(EventId::Textinput, parameters); + + return consumed; +} + +// Sends a mouse movement event into RmlUi. +void Context::ProcessMouseMove(int x, int y, int key_modifier_state) +{ + // Check whether the mouse moved since the last event came through. + Vector2i old_mouse_position = mouse_position; + bool mouse_moved = (x != mouse_position.x) || (y != mouse_position.y); + if (mouse_moved) + { + mouse_position.x = x; + mouse_position.y = y; + } + + // Generate the parameters for the mouse events (there could be a few!). + Dictionary parameters; + GenerateMouseEventParameters(parameters, -1); + GenerateKeyModifierEventParameters(parameters, key_modifier_state); + + Dictionary drag_parameters; + GenerateMouseEventParameters(drag_parameters); + GenerateDragEventParameters(drag_parameters); + GenerateKeyModifierEventParameters(drag_parameters, key_modifier_state); + + // Update the current hover chain. This will send all necessary 'onmouseout', 'onmouseover', 'ondragout' and + // 'ondragover' messages. + UpdateHoverChain(parameters, drag_parameters, old_mouse_position); + + // Dispatch any 'onmousemove' events. + if (mouse_moved) + { + if (hover) + { + hover->DispatchEvent(EventId::Mousemove, parameters); + + if (drag_hover && + drag_verbose) + drag_hover->DispatchEvent(EventId::Dragmove, drag_parameters); + } + } +} + +static Element* FindFocusElement(Element* element) +{ + ElementDocument* owner_document = element->GetOwnerDocument(); + if (!owner_document || owner_document->GetComputedValues().focus == Style::Focus::None) + return nullptr; + + while (element && element->GetComputedValues().focus == Style::Focus::None) + { + element = element->GetParentNode(); + } + + return element; +} + +// Sends a mouse-button down event into RmlUi. +void Context::ProcessMouseButtonDown(int button_index, int key_modifier_state) +{ + Dictionary parameters; + GenerateMouseEventParameters(parameters, button_index); + GenerateKeyModifierEventParameters(parameters, key_modifier_state); + + if (button_index == 0) + { + Element* new_focus = hover; + + // Set the currently hovered element to focus if it isn't already the focus. + if (hover) + { + new_focus = FindFocusElement(hover); + if (new_focus && new_focus != focus) + { + if (!new_focus->Focus()) + return; + } + } + + // Save the just-pressed-on element as the pressed element. + active = new_focus; + + bool propagate = true; + + // Call 'onmousedown' on every item in the hover chain, and copy the hover chain to the active chain. + if (hover) + propagate = hover->DispatchEvent(EventId::Mousedown, parameters); + + if (propagate) + { + // Check for a double-click on an element; if one has occured, we send the 'dblclick' event to the hover + // element. If not, we'll start a timer to catch the next one. + float mouse_distance_squared = float((mouse_position - last_click_mouse_position).SquaredMagnitude()); + float max_mouse_distance = DOUBLE_CLICK_MAX_DIST * density_independent_pixel_ratio; + + double click_time = GetSystemInterface()->GetElapsedTime(); + + if (active == last_click_element && + float(click_time - last_click_time) < DOUBLE_CLICK_TIME && + mouse_distance_squared < max_mouse_distance * max_mouse_distance) + { + if (hover) + propagate = hover->DispatchEvent(EventId::Dblclick, parameters); + + last_click_element = nullptr; + last_click_time = 0; + } + else + { + last_click_element = active; + last_click_time = click_time; + } + } + + last_click_mouse_position = mouse_position; + + for (ElementSet::iterator itr = hover_chain.begin(); itr != hover_chain.end(); ++itr) + active_chain.push_back((*itr)); + + if (propagate) + { + // Traverse down the hierarchy of the newly focussed element (if any), and see if we can begin dragging it. + drag_started = false; + drag = hover; + while (drag) + { + Style::Drag drag_style = drag->GetComputedValues().drag; + switch (drag_style) + { + case Style::Drag::None: drag = drag->GetParentNode(); continue; + case Style::Drag::Block: drag = nullptr; continue; + default: drag_verbose = (drag_style == Style::Drag::DragDrop || drag_style == Style::Drag::Clone); + } + + break; + } + } + } + else + { + // Not the primary mouse button, so we're not doing any special processing. + if (hover) + hover->DispatchEvent(EventId::Mousedown, parameters); + } +} + +// Sends a mouse-button up event into RmlUi. +void Context::ProcessMouseButtonUp(int button_index, int key_modifier_state) +{ + Dictionary parameters; + GenerateMouseEventParameters(parameters, button_index); + GenerateKeyModifierEventParameters(parameters, key_modifier_state); + + // Process primary click. + if (button_index == 0) + { + // The elements in the new hover chain have the 'onmouseup' event called on them. + if (hover) + hover->DispatchEvent(EventId::Mouseup, parameters); + + // If the active element (the one that was being hovered over when the mouse button was pressed) is still being + // hovered over, we click it. + if (hover && active && active == FindFocusElement(hover)) + { + active->DispatchEvent(EventId::Click, parameters); + } + + // Unset the 'active' pseudo-class on all the elements in the active chain; because they may not necessarily + // have had 'onmouseup' called on them, we can't guarantee this has happened already. + auto func = PseudoClassFunctor("active", false); + std::for_each(active_chain.begin(), active_chain.end(), func); + active_chain.clear(); + + if (drag) + { + if (drag_started) + { + Dictionary drag_parameters; + GenerateMouseEventParameters(drag_parameters); + GenerateDragEventParameters(drag_parameters); + GenerateKeyModifierEventParameters(drag_parameters, key_modifier_state); + + if (drag_hover) + { + if (drag_verbose) + { + drag_hover->DispatchEvent(EventId::Dragdrop, drag_parameters); + // User may have removed the element, do an extra check. + if(drag_hover) + drag_hover->DispatchEvent(EventId::Dragout, drag_parameters); + } + } + + if(drag) + drag->DispatchEvent(EventId::Dragend, drag_parameters); + + ReleaseDragClone(); + } + + drag = nullptr; + drag_hover = nullptr; + drag_hover_chain.clear(); + + // We may have changes under our mouse, this ensures that the hover chain is properly updated + ProcessMouseMove(mouse_position.x, mouse_position.y, key_modifier_state); + } + } + else + { + // Not the left mouse button, so we're not doing any special processing. + if (hover) + hover->DispatchEvent(EventId::Mouseup, parameters); + } +} + +// Sends a mouse-wheel movement event into RmlUi. +bool Context::ProcessMouseWheel(float wheel_delta, int key_modifier_state) +{ + if (hover) + { + Dictionary scroll_parameters; + GenerateKeyModifierEventParameters(scroll_parameters, key_modifier_state); + scroll_parameters["wheel_delta"] = wheel_delta; + + return hover->DispatchEvent(EventId::Mousescroll, scroll_parameters); + } + + return true; +} + +// Gets the context's render interface. +RenderInterface* Context::GetRenderInterface() const +{ + return render_interface; +} + +// Gets the current clipping region for the render traversal +bool Context::GetActiveClipRegion(Vector2i& origin, Vector2i& dimensions) const +{ + if (clip_dimensions.x < 0 || clip_dimensions.y < 0) + return false; + + origin = clip_origin; + dimensions = clip_dimensions; + + return true; +} + +// Sets the current clipping region for the render traversal +void Context::SetActiveClipRegion(const Vector2i& origin, const Vector2i& dimensions) +{ + clip_origin = origin; + clip_dimensions = dimensions; +} + +// Sets the instancer to use for releasing this object. +void Context::SetInstancer(ContextInstancer* _instancer) +{ + RMLUI_ASSERT(instancer == nullptr); + instancer = _instancer; +} + +DataModelConstructor Context::CreateDataModel(const String& name) +{ + if (!data_type_register) + data_type_register = MakeUnique(); + + auto result = data_models.emplace(name, MakeUnique(data_type_register->GetTransformFuncRegister())); + bool inserted = result.second; + if (inserted) + return DataModelConstructor(result.first->second.get(), data_type_register.get()); + + Log::Message(Log::LT_ERROR, "Data model name '%s' already exists.", name.c_str()); + return DataModelConstructor(); +} + +DataModelConstructor Context::GetDataModel(const String& name) +{ + if (data_type_register) + { + if (DataModel* model = GetDataModelPtr(name)) + return DataModelConstructor(model, data_type_register.get()); + } + + Log::Message(Log::LT_ERROR, "Data model name '%s' could not be found.", name.c_str()); + return DataModelConstructor(); +} + +bool Context::RemoveDataModel(const String& name) +{ + auto it = data_models.find(name); + if (it == data_models.end()) + return false; + + DataModel* model = it->second.get(); + ElementList elements = model->GetAttachedModelRootElements(); + + for (Element* element : elements) + element->SetDataModel(nullptr); + + data_models.erase(it); + + return true; +} + +// Internal callback for when an element is removed from the hierarchy. +void Context::OnElementDetach(Element* element) +{ + auto it_hover = hover_chain.find(element); + if (it_hover != hover_chain.end()) + { + Dictionary parameters; + GenerateMouseEventParameters(parameters, -1); + element->DispatchEvent(EventId::Mouseout, parameters); + + hover_chain.erase(it_hover); + + if (hover == element) + hover = nullptr; + } + + auto it_active = std::find(active_chain.begin(), active_chain.end(), element); + if (it_active != active_chain.end()) + { + active_chain.erase(it_active); + + if (active == element) + active = nullptr; + } + + if (drag) + { + auto it = drag_hover_chain.find(element); + if (it != drag_hover_chain.end()) + { + drag_hover_chain.erase(it); + + if (drag_hover == element) + drag_hover = nullptr; + } + + if (drag == element) + { + // The dragged element is being removed, silently cancel the drag operation + if (drag_started) + ReleaseDragClone(); + + drag = nullptr; + drag_hover = nullptr; + drag_hover_chain.clear(); + } + } + + // Focus normally cleared and set by parent during Element::RemoveChild. + // However, there are some exceptions, such as when an there are multiple + // ElementDocuments in the hierarchy above the current element. + if (element == focus) + focus = nullptr; + + // If the element is a document lower down in the hierarchy, we may need to remove it from the focus history. + if (element->GetOwnerDocument() == element) + { + auto it = std::find(document_focus_history.begin(), document_focus_history.end(), element); + if (it != document_focus_history.end()) + document_focus_history.erase(it); + } +} + +// Internal callback for when a new element gains focus +bool Context::OnFocusChange(Element* new_focus) +{ + RMLUI_ASSERT(new_focus); + + ElementSet old_chain; + ElementSet new_chain; + + Element* old_focus = focus; + ElementDocument* old_document = old_focus ? old_focus->GetOwnerDocument() : nullptr; + ElementDocument* new_document = new_focus->GetOwnerDocument(); + + // If the current focus is modal and the new focus is not modal, deny the request + if (old_document && old_document->IsModal() && (!new_document || !new_document->GetOwnerDocument()->IsModal())) + return false; + + // Build the old chains + Element* element = old_focus; + while (element) + { + old_chain.insert(element); + element = element->GetParentNode(); + } + + // Build the new chain + element = new_focus; + while (element) + { + new_chain.insert(element); + element = element->GetParentNode(); + } + + Dictionary parameters; + + // Send out blur/focus events. + SendEvents(old_chain, new_chain, EventId::Blur, parameters); + SendEvents(new_chain, old_chain, EventId::Focus, parameters); + + focus = new_focus; + + // Raise the element's document to the front, if desired. + ElementDocument* document = focus->GetOwnerDocument(); + if (document != nullptr) + { + Style::ZIndex z_index_property = document->GetComputedValues().z_index; + if (z_index_property.type == Style::ZIndex::Auto) + document->PullToFront(); + } + + // Update the focus history + if (old_document != new_document) + { + // If documents have changed, add the new document to the end of the history + ElementList::iterator itr = std::find(document_focus_history.begin(), document_focus_history.end(), new_document); + if (itr != document_focus_history.end()) + document_focus_history.erase(itr); + + if (new_document != nullptr) + document_focus_history.push_back(new_document); + } + + return true; +} + +// Generates an event for faking clicks on an element. +void Context::GenerateClickEvent(Element* element) +{ + Dictionary parameters; + GenerateMouseEventParameters(parameters, 0); + + element->DispatchEvent(EventId::Click, parameters); +} + +// Updates the current hover elements, sending required events. +void Context::UpdateHoverChain(const Dictionary& parameters, const Dictionary& drag_parameters, const Vector2i& old_mouse_position) +{ + Vector2f position((float) mouse_position.x, (float) mouse_position.y); + + // Send out drag events. + if (drag) + { + if (mouse_position != old_mouse_position) + { + if (!drag_started) + { + Dictionary drag_start_parameters = drag_parameters; + drag_start_parameters["mouse_x"] = old_mouse_position.x; + drag_start_parameters["mouse_y"] = old_mouse_position.y; + drag->DispatchEvent(EventId::Dragstart, drag_start_parameters); + drag_started = true; + + if (drag->GetComputedValues().drag == Style::Drag::Clone) + { + // Clone the element and attach it to the mouse cursor. + CreateDragClone(drag); + } + } + + drag->DispatchEvent(EventId::Drag, drag_parameters); + } + } + + hover = GetElementAtPoint(position); + + if(enable_cursor) + { + String new_cursor_name; + + if(drag) + new_cursor_name = drag->GetComputedValues().cursor; + else if (hover) + new_cursor_name = hover->GetComputedValues().cursor; + + if(new_cursor_name != cursor_name) + { + GetSystemInterface()->SetMouseCursor(new_cursor_name); + cursor_name = new_cursor_name; + } + } + + // Build the new hover chain. + ElementSet new_hover_chain; + Element* element = hover; + while (element != nullptr) + { + new_hover_chain.insert(element); + element = element->GetParentNode(); + } + + // Send mouseout / mouseover events. + SendEvents(hover_chain, new_hover_chain, EventId::Mouseout, parameters); + SendEvents(new_hover_chain, hover_chain, EventId::Mouseover, parameters); + + // Send out drag events. + if (drag) + { + drag_hover = GetElementAtPoint(position, drag); + + ElementSet new_drag_hover_chain; + element = drag_hover; + while (element != nullptr) + { + new_drag_hover_chain.insert(element); + element = element->GetParentNode(); + } + + if (drag_started && + drag_verbose) + { + // Send out ondragover and ondragout events as appropriate. + SendEvents(drag_hover_chain, new_drag_hover_chain, EventId::Dragout, drag_parameters); + SendEvents(new_drag_hover_chain, drag_hover_chain, EventId::Dragover, drag_parameters); + } + + drag_hover_chain.swap(new_drag_hover_chain); + } + + // Swap the new chain in. + hover_chain.swap(new_hover_chain); +} + +// Returns the youngest descendent of the given element which is under the given point in screen coodinates. +Element* Context::GetElementAtPoint(Vector2f point, const Element* ignore_element, Element* element) const +{ + if (element == nullptr) + { + if (ignore_element == root.get()) + return nullptr; + + element = root.get(); + } + + // Check if any documents have modal focus; if so, only check down than document. + if (element == root.get()) + { + if (focus) + { + ElementDocument* focus_document = focus->GetOwnerDocument(); + if (focus_document != nullptr && + focus_document->IsModal()) + { + element = focus_document; + } + } + } + + + // Check any elements within our stacking context. We want to return the lowest-down element + // that is under the cursor. + if (element->local_stacking_context) + { + if (element->stacking_context_dirty) + element->BuildLocalStackingContext(); + + for (int i = (int) element->stacking_context.size() - 1; i >= 0; --i) + { + if (ignore_element != nullptr) + { + Element* element_hierarchy = element->stacking_context[i]; + while (element_hierarchy != nullptr) + { + if (element_hierarchy == ignore_element) + break; + + element_hierarchy = element_hierarchy->GetParentNode(); + } + + if (element_hierarchy != nullptr) + continue; + } + + Element* child_element = GetElementAtPoint(point, ignore_element, element->stacking_context[i]); + if (child_element != nullptr) + return child_element; + } + } + + // Ignore elements whose pointer events are disabled. + if (element->GetComputedValues().pointer_events == Style::PointerEvents::None) + return nullptr; + + // Projection may fail if we have a singular transformation matrix. + bool projection_result = element->Project(point); + + // Check if the point is actually within this element. + bool within_element = (projection_result && element->IsPointWithinElement(point)); + if (within_element) + { + Vector2i clip_origin, clip_dimensions; + if (ElementUtilities::GetClippingRegion(clip_origin, clip_dimensions, element)) + { + within_element = point.x >= clip_origin.x && + point.y >= clip_origin.y && + point.x <= (clip_origin.x + clip_dimensions.x) && + point.y <= (clip_origin.y + clip_dimensions.y); + } + } + + if (within_element) + return element; + + return nullptr; +} + +// Creates the drag clone from the given element. +void Context::CreateDragClone(Element* element) +{ + if (!cursor_proxy) + { + Log::Message(Log::LT_ERROR, "Unable to create drag clone, no cursor proxy document."); + return; + } + + ReleaseDragClone(); + + // Instance the drag clone. + ElementPtr element_drag_clone = element->Clone(); + if (!element_drag_clone) + { + Log::Message(Log::LT_ERROR, "Unable to duplicate drag clone."); + return; + } + + drag_clone = element_drag_clone.get(); + + // Append the clone to the cursor proxy element. + cursor_proxy->AppendChild(std::move(element_drag_clone)); + + // Set the style sheet on the cursor proxy. + static_cast(*cursor_proxy).SetStyleSheet(element->GetStyleSheet()); + + // Set all the required properties and pseudo-classes on the clone. + drag_clone->SetPseudoClass("drag", true); + drag_clone->SetProperty(PropertyId::Position, Property(Style::Position::Absolute)); + drag_clone->SetProperty(PropertyId::Left, Property(element->GetAbsoluteLeft() - element->GetBox().GetEdge(Box::MARGIN, Box::LEFT) - mouse_position.x, Property::PX)); + drag_clone->SetProperty(PropertyId::Top, Property(element->GetAbsoluteTop() - element->GetBox().GetEdge(Box::MARGIN, Box::TOP) - mouse_position.y, Property::PX)); +} + +// Releases the drag clone, if one exists. +void Context::ReleaseDragClone() +{ + if (drag_clone) + { + cursor_proxy->RemoveChild(drag_clone); + drag_clone = nullptr; + } +} + +DataModel* Context::GetDataModelPtr(const String& name) const +{ + auto it = data_models.find(name); + if (it != data_models.end()) + return it->second.get(); + return nullptr; +} + +// Builds the parameters for a generic key event. +void Context::GenerateKeyEventParameters(Dictionary& parameters, Input::KeyIdentifier key_identifier) +{ + parameters["key_identifier"] = (int)key_identifier; +} + +// Builds the parameters for a generic mouse event. +void Context::GenerateMouseEventParameters(Dictionary& parameters, int button_index) +{ + parameters.reserve(3); + parameters["mouse_x"] = mouse_position.x; + parameters["mouse_y"] = mouse_position.y; + if (button_index >= 0) + parameters["button"] = button_index; +} + +// Builds the parameters for the key modifier state. +void Context::GenerateKeyModifierEventParameters(Dictionary& parameters, int key_modifier_state) +{ + static const String property_names[] = { + "ctrl_key", + "shift_key", + "alt_key", + "meta_key", + "caps_lock_key", + "num_lock_key", + "scroll_lock_key" + }; + + for (int i = 0; i < 7; i++) + parameters[property_names[i]] = (int)((key_modifier_state & (1 << i)) > 0); +} + +// Builds the parameters for a drag event. +void Context::GenerateDragEventParameters(Dictionary& parameters) +{ + parameters["drag_element"] = (void*)drag; +} + +// Releases all unloaded documents pending destruction. +void Context::ReleaseUnloadedDocuments() +{ + if (!unloaded_documents.empty()) + { + OwnedElementList documents = std::move(unloaded_documents); + unloaded_documents.clear(); + + // Clear the deleted list. + for (size_t i = 0; i < documents.size(); ++i) + documents[i]->GetEventDispatcher()->DetachAllEvents(); + documents.clear(); + } +} + +using ElementObserverList = Vector< ObserverPtr >; + +class ElementObserverListBackInserter { +public: + using iterator_category = std::output_iterator_tag; + using value_type = void; + using difference_type = void; + using pointer = void; + using reference = void; + using container_type = ElementObserverList; + + ElementObserverListBackInserter(ElementObserverList& elements) : elements(&elements) {} + ElementObserverListBackInserter& operator=(const Element* element) { + elements->push_back(element->GetObserverPtr()); + return *this; + } + ElementObserverListBackInserter& operator*() { return *this; } + ElementObserverListBackInserter& operator++() { return *this; } + ElementObserverListBackInserter& operator++(int) { return *this; } + +private: + ElementObserverList* elements; +}; + +// Sends the specified event to all elements in new_items that don't appear in old_items. +void Context::SendEvents(const ElementSet& old_items, const ElementSet& new_items, EventId id, const Dictionary& parameters) +{ + // We put our elements in observer pointers in case some of them are deleted during dispatch. + ElementObserverList elements; + std::set_difference(old_items.begin(), old_items.end(), new_items.begin(), new_items.end(), ElementObserverListBackInserter(elements)); + for (auto& element : elements) + { + if (element) + element->DispatchEvent(id, parameters); + } +} + +void Context::Release() +{ + if (instancer) + { + instancer->ReleaseContext(this); + } +} + +void Context::SetDocumentsBaseTag(const String& tag) +{ + documents_base_tag = tag; +} + +const String& Context::GetDocumentsBaseTag() +{ + return documents_base_tag; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ContextInstancer.cpp b/thirdparty/RmlUi/Source/Core/ContextInstancer.cpp new file mode 100644 index 000000000..472215251 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ContextInstancer.cpp @@ -0,0 +1,37 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ContextInstancer.h" + +namespace Rml { + +ContextInstancer::~ContextInstancer() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ContextInstancerDefault.cpp b/thirdparty/RmlUi/Source/Core/ContextInstancerDefault.cpp new file mode 100644 index 000000000..6d1f8949b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ContextInstancerDefault.cpp @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ContextInstancerDefault.h" +#include "../../Include/RmlUi/Core/Context.h" + +namespace Rml { + +ContextInstancerDefault::ContextInstancerDefault() +{ +} + +ContextInstancerDefault::~ContextInstancerDefault() +{ +} + +ContextPtr ContextInstancerDefault::InstanceContext(const String& name) +{ + return ContextPtr(new Context(name)); +} + +// Releases a context previously created by this context. +void ContextInstancerDefault::ReleaseContext(Context* context) +{ + delete context; +} + +void ContextInstancerDefault::Release() +{ + delete this; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ContextInstancerDefault.h b/thirdparty/RmlUi/Source/Core/ContextInstancerDefault.h new file mode 100644 index 000000000..034b8e36a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ContextInstancerDefault.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_CONTEXTINSTANCERDEFAULT_H +#define RMLUI_CORE_CONTEXTINSTANCERDEFAULT_H + +#include "../../Include/RmlUi/Core/ContextInstancer.h" + +namespace Rml { + +/** + Default instancer for instancing contexts. + + @author Peter Curry + */ + +class ContextInstancerDefault : public ContextInstancer +{ +public: + ContextInstancerDefault(); + virtual ~ContextInstancerDefault(); + + /// Instances a context. + /// @param[in] name Name of this context. + /// @return The instanced context. + ContextPtr InstanceContext(const String& name) override; + + /// Releases a context previously created by this context. + /// @param[in] context The context to release. + void ReleaseContext(Context* context) override; + + /// Releases this context instancer. + void Release() override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ConvolutionFilter.cpp b/thirdparty/RmlUi/Source/Core/ConvolutionFilter.cpp new file mode 100644 index 000000000..46aa4dc6a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ConvolutionFilter.cpp @@ -0,0 +1,129 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ConvolutionFilter.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include +#include + +namespace Rml { + +ConvolutionFilter::ConvolutionFilter() +{} + +ConvolutionFilter::~ConvolutionFilter() +{} + +bool ConvolutionFilter::Initialise(int _kernel_radius, FilterOperation _operation) +{ + return Initialise(Vector2i(_kernel_radius), _operation); +} + +bool ConvolutionFilter::Initialise(Vector2i _kernel_radii, FilterOperation _operation) +{ + if (_kernel_radii.x < 0 || _kernel_radii.y < 0) + { + RMLUI_ERRORMSG("Invalid input parameters to convolution filter."); + return false; + } + + kernel_size = _kernel_radii * 2 + Vector2i(1); + + kernel = UniquePtr(new float[kernel_size.x * kernel_size.y]); + memset(kernel.get(), 0, kernel_size.x * kernel_size.y * sizeof(float)); + + operation = _operation; + return true; +} + +float* ConvolutionFilter::operator[](int kernel_y_index) +{ + RMLUI_ASSERT(kernel != nullptr && kernel_y_index >= 0 && kernel_y_index < kernel_size.y); + + kernel_y_index = Math::Clamp(kernel_y_index, 0, kernel_size.y - 1); + + return kernel.get() + kernel_size.x * kernel_y_index; +} + +void ConvolutionFilter::Run(byte* destination, const Vector2i destination_dimensions, const int destination_stride, const ColorFormat destination_color_format, const byte* source, const Vector2i source_dimensions, const Vector2i source_offset) const +{ + RMLUI_ZoneScopedNC("ConvFilter::Run", 0xd6bf49); + + const float initial_opacity = (operation == FilterOperation::Erosion ? FLT_MAX : 0.f); + + const Vector2i kernel_radius = (kernel_size - Vector2i(1)) / 2; + + for (int y = 0; y < destination_dimensions.y; ++y) + { + for (int x = 0; x < destination_dimensions.x; ++x) + { + float opacity = initial_opacity; + + for (int kernel_y = 0; kernel_y < kernel_size.y; ++kernel_y) + { + int source_y = y - source_offset.y - kernel_radius.y + kernel_y; + + for (int kernel_x = 0; kernel_x < kernel_size.x; ++kernel_x) + { + float pixel_opacity; + + int source_x = x - source_offset.x - kernel_radius.x + kernel_x; + if (source_y >= 0 && source_y < source_dimensions.y && + source_x >= 0 && source_x < source_dimensions.x) + { + pixel_opacity = float(source[source_y * source_dimensions.x + source_x]) * kernel[kernel_y * kernel_size.x + kernel_x]; + } + else + pixel_opacity = 0; + + switch (operation) + { + case FilterOperation::Sum: opacity += pixel_opacity; break; + case FilterOperation::Dilation: opacity = Math::Max(opacity, pixel_opacity); break; + case FilterOperation::Erosion: opacity = Math::Min(opacity, pixel_opacity); break; + } + } + } + + opacity = Math::Min(255.f, opacity); + + int destination_index = 0; + switch (destination_color_format) + { + case ColorFormat::RGBA8: destination_index = x * 4 + 3; break; + case ColorFormat::A8: destination_index = x; break; + } + + destination[destination_index] = byte(opacity); + } + + destination += destination_stride; + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Core.cpp b/thirdparty/RmlUi/Source/Core/Core.cpp new file mode 100644 index 000000000..25301bed6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Core.cpp @@ -0,0 +1,335 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/FileInterface.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/Plugin.h" +#include "../../Include/RmlUi/Core/RenderInterface.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/Types.h" + +#include "EventSpecification.h" +#include "FileInterfaceDefault.h" +#include "GeometryDatabase.h" +#include "PluginRegistry.h" +#include "StyleSheetFactory.h" +#include "TemplateCache.h" +#include "TextureDatabase.h" +#include "EventSpecification.h" + +#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT +#include "FontEngineDefault/FontEngineInterfaceDefault.h" +#endif + + +namespace Rml { + +// RmlUi's renderer interface. +static RenderInterface* render_interface = nullptr; +/// RmlUi's system interface. +static SystemInterface* system_interface = nullptr; +// RmlUi's file I/O interface. +static FileInterface* file_interface = nullptr; +// RmlUi's font engine interface. +static FontEngineInterface* font_interface = nullptr; + +// Default interfaces should be created and destroyed on Initialise and Shutdown, respectively. +static UniquePtr default_file_interface; +static UniquePtr default_font_interface; + +static bool initialised = false; + +using ContextMap = UnorderedMap< String, ContextPtr >; +static ContextMap contexts; + +#ifndef RMLUI_VERSION + #define RMLUI_VERSION "custom" +#endif + + +bool Initialise() +{ + // Check for valid interfaces, or install default interfaces as appropriate. + if (!system_interface) + { + Log::Message(Log::LT_ERROR, "No system interface set!"); + return false; + } + + if (!file_interface) + { +#ifndef RMLUI_NO_FILE_INTERFACE_DEFAULT + default_file_interface = MakeUnique(); + file_interface = default_file_interface.get(); +#else + Log::Message(Log::LT_ERROR, "No file interface set!"); + return false; +#endif + } + + Log::Initialise(); + + EventSpecificationInterface::Initialize(); + + TextureDatabase::Initialise(); + + if (!font_interface) + { +#ifndef RMLUI_NO_FONT_INTERFACE_DEFAULT + default_font_interface = MakeUnique(); + font_interface = default_font_interface.get(); +#else + Log::Message(Log::LT_ERROR, "No font interface set!"); + return false; +#endif + } + + StyleSheetSpecification::Initialise(); + StyleSheetFactory::Initialise(); + + TemplateCache::Initialise(); + + Factory::Initialise(); + + // Notify all plugins we're starting up. + PluginRegistry::NotifyInitialise(); + + initialised = true; + + return true; +} + +void Shutdown() +{ + // Clear out all contexts, which should also clean up all attached elements. + contexts.clear(); + + // Notify all plugins we're being shutdown. + PluginRegistry::NotifyShutdown(); + + TemplateCache::Shutdown(); + StyleSheetFactory::Shutdown(); + StyleSheetSpecification::Shutdown(); + TextureDatabase::Shutdown(); + Factory::Shutdown(); + + Log::Shutdown(); + + initialised = false; + + render_interface = nullptr; + file_interface = nullptr; + system_interface = nullptr; + font_interface = nullptr; + + default_file_interface.reset(); + default_font_interface.reset(); +} + +// Returns the version of this RmlUi library. +String GetVersion() +{ + return RMLUI_VERSION; +} + +// Sets the interface through which all RmlUi messages will be routed. +void SetSystemInterface(SystemInterface* _system_interface) +{ + system_interface = _system_interface; +} + +// Returns RmlUi's system interface. +SystemInterface* GetSystemInterface() +{ + return system_interface; +} + +// Sets the interface through which all rendering requests are made. +void SetRenderInterface(RenderInterface* _render_interface) +{ + render_interface = _render_interface; +} + +// Returns RmlUi's render interface. +RenderInterface* GetRenderInterface() +{ + return render_interface; +} + +// Sets the interface through which all file I/O requests are made. +void SetFileInterface(FileInterface* _file_interface) +{ + file_interface = _file_interface; +} + +// Returns RmlUi's file interface. +FileInterface* GetFileInterface() +{ + return file_interface; +} + +// Sets the interface through which all font requests are made. +void SetFontEngineInterface(FontEngineInterface* _font_interface) +{ + font_interface = _font_interface; +} + +// Returns RmlUi's file interface. +FontEngineInterface* GetFontEngineInterface() +{ + return font_interface; +} + +// Creates a new element context. +Context* CreateContext(const String& name, const Vector2i& dimensions, RenderInterface* custom_render_interface) +{ + if (!initialised) + return nullptr; + + if (!custom_render_interface && !render_interface) + { + Log::Message(Log::LT_WARNING, "Failed to create context '%s', no render interface specified and no default render interface exists.", name.c_str()); + return nullptr; + } + + if (GetContext(name)) + { + Log::Message(Log::LT_WARNING, "Failed to create context '%s', context already exists.", name.c_str()); + return nullptr; + } + + ContextPtr new_context = Factory::InstanceContext(name); + if (!new_context) + { + Log::Message(Log::LT_WARNING, "Failed to instance context '%s', instancer returned nullptr.", name.c_str()); + return nullptr; + } + + // Set the render interface on the context, and add a reference onto it. + if (custom_render_interface) + new_context->render_interface = custom_render_interface; + else + new_context->render_interface = render_interface; + + new_context->SetDimensions(dimensions); + + Context* new_context_raw = new_context.get(); + contexts[name] = std::move(new_context); + + PluginRegistry::NotifyContextCreate(new_context_raw); + + return new_context_raw; +} + +bool RemoveContext(const String& name) +{ + auto it = contexts.find(name); + if (it != contexts.end()) + { + contexts.erase(it); + return true; + } + return false; +} + +// Fetches a previously constructed context by name. +Context* GetContext(const String& name) +{ + ContextMap::iterator i = contexts.find(name); + if (i == contexts.end()) + return nullptr; + + return i->second.get(); +} + +// Fetches a context by index. +Context* GetContext(int index) +{ + ContextMap::iterator i = contexts.begin(); + int count = 0; + + if (index >= GetNumContexts()) + index = GetNumContexts() - 1; + + while (count < index) + { + ++i; + ++count; + } + + if (i == contexts.end()) + return nullptr; + + return i->second.get(); +} + +// Returns the number of active contexts. +int GetNumContexts() +{ + return (int) contexts.size(); +} + +bool LoadFontFace(const String& file_name, bool fallback_face) +{ + return font_interface->LoadFontFace(file_name, fallback_face); +} + +bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face) +{ + return font_interface->LoadFontFace(data, data_size, font_family, style, weight, fallback_face); +} + +// Registers a generic rmlui plugin +void RegisterPlugin(Plugin* plugin) +{ + if (initialised) + plugin->OnInitialise(); + + PluginRegistry::RegisterPlugin(plugin); +} + +EventId RegisterEventType(const String& type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase) +{ + return EventSpecificationInterface::InsertOrReplaceCustom(type, interruptible, bubbles, default_action_phase); +} + +void ReleaseTextures() +{ + TextureDatabase::ReleaseTextures(); +} + +void ReleaseCompiledGeometry() +{ + return GeometryDatabase::ReleaseAll(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataController.cpp b/thirdparty/RmlUi/Source/Core/DataController.cpp new file mode 100644 index 000000000..7b7c0e726 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataController.cpp @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/DataController.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "EventSpecification.h" + +namespace Rml { + +DataController::DataController(Element* element) : attached_element(element->GetObserverPtr()) +{} + +DataController::~DataController() +{} +Element* DataController::GetElement() const { + return attached_element.get(); +} + +bool DataController::IsValid() const { + return static_cast(attached_element); +} + + + +DataControllers::DataControllers() +{} + +DataControllers::~DataControllers() +{} + +void DataControllers::Add(DataControllerPtr controller) { + RMLUI_ASSERT(controller); + + Element* element = controller->GetElement(); + RMLUI_ASSERTMSG(element, "Invalid controller, make sure it is valid before adding"); + if (!element) + return; + + controllers.emplace(element, std::move(controller)); +} + +void DataControllers::OnElementRemove(Element* element) +{ + controllers.erase(element); +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataControllerDefault.cpp b/thirdparty/RmlUi/Source/Core/DataControllerDefault.cpp new file mode 100644 index 000000000..aee6a94b3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataControllerDefault.cpp @@ -0,0 +1,156 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DataControllerDefault.h" +#include "../../Include/RmlUi/Core/DataController.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "DataExpression.h" +#include "EventSpecification.h" + +namespace Rml { + +DataControllerValue::DataControllerValue(Element* element) : DataController(element) +{} + +DataControllerValue::~DataControllerValue() +{ + if (Element* element = GetElement()) + { + element->RemoveEventListener(EventId::Change, this); + } +} + +bool DataControllerValue::Initialize(DataModel& model, Element* element, const String& variable_name, const String& /*modifier*/) +{ + RMLUI_ASSERT(element); + + DataAddress variable_address = model.ResolveAddress(variable_name, element); + if (variable_address.empty()) + return false; + + if (model.GetVariable(variable_address)) + address = std::move(variable_address); + + element->AddEventListener(EventId::Change, this); + + return true; +} + +void DataControllerValue::ProcessEvent(Event& event) +{ + if (Element* element = GetElement()) + { + const auto& parameters = event.GetParameters(); + auto it = parameters.find("value"); + if (it == parameters.end()) + { + Log::Message(Log::LT_WARNING, "A 'change' event was received, but it did not contain a value. During processing of 'data-value' in %s", element->GetAddress().c_str()); + return; + } + + SetValue(it->second); + } +} + +void DataControllerValue::Release() +{ + delete this; +} + +void DataControllerValue::SetValue(const Variant& value) +{ + Element* element = GetElement(); + if (!element) + return; + + DataModel* model = element->GetDataModel(); + if (!model) + return; + + if (DataVariable variable = model->GetVariable(address)) + { + variable.Set(value); + model->DirtyVariable(address.front().name); + } +} + + +DataControllerEvent::DataControllerEvent(Element* element) : DataController(element) +{} + +DataControllerEvent::~DataControllerEvent() +{ + if (Element* element = GetElement()) + { + if (id != EventId::Invalid) + element->RemoveEventListener(id, this); + } +} + +bool DataControllerEvent::Initialize(DataModel& model, Element* element, const String& expression_str, const String& modifier) +{ + RMLUI_ASSERT(element); + + expression = MakeUnique(expression_str); + DataExpressionInterface interface(&model, element); + + if (!expression->Parse(interface, true)) + return false; + + id = EventSpecificationInterface::GetIdOrInsert(modifier); + if (id == EventId::Invalid) + { + Log::Message(Log::LT_WARNING, "Event type '%s' could not be recognized, while adding 'data-event' to %s", modifier.c_str(), element->GetAddress().c_str()); + return false; + } + + element->AddEventListener(id, this); + + return true; +} + +void DataControllerEvent::ProcessEvent(Event& event) +{ + if (!expression) + return; + + if (Element* element = GetElement()) + { + DataExpressionInterface interface(element->GetDataModel(), element, &event); + Variant unused_value_out; + expression->Run(interface, unused_value_out); + } +} + +void DataControllerEvent::Release() +{ + delete this; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataControllerDefault.h b/thirdparty/RmlUi/Source/Core/DataControllerDefault.h new file mode 100644 index 000000000..6a0cc5213 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataControllerDefault.h @@ -0,0 +1,87 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATACONTROLLERDEFAULT_H +#define RMLUI_CORE_DATACONTROLLERDEFAULT_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/EventListener.h" +#include "../../Include/RmlUi/Core/DataVariable.h" +#include "../../Include/RmlUi/Core/DataController.h" + +namespace Rml { + +class Element; +class DataModel; +class DataExpression; +using DataExpressionPtr = UniquePtr; + + +class DataControllerValue final : public DataController, private EventListener { +public: + DataControllerValue(Element* element); + ~DataControllerValue(); + + bool Initialize(DataModel& model, Element* element, const String& expression, const String& modifier) override; + +protected: + // Responds to 'Change' events. + void ProcessEvent(Event& event) override; + + // Delete this. + void Release() override; + +private: + void SetValue(const Variant& new_value); + + DataAddress address; +}; + + +class DataControllerEvent final : public DataController, private EventListener { +public: + DataControllerEvent(Element* element); + ~DataControllerEvent(); + + bool Initialize(DataModel& model, Element* element, const String& expression, const String& modifier) override; + +protected: + // Responds to the event type specified in the attribute modifier. + void ProcessEvent(Event& event) override; + + // Delete this. + void Release() override; + +private: + EventId id = EventId::Invalid; + DataExpressionPtr expression; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DataExpression.cpp b/thirdparty/RmlUi/Source/Core/DataExpression.cpp new file mode 100644 index 000000000..4d83217cb --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataExpression.cpp @@ -0,0 +1,1189 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DataExpression.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/Variant.h" +#include + +#ifdef _MSC_VER +#pragma warning(default : 4061) +#pragma warning(default : 4062) +#endif + +namespace Rml { + +class DataParser; + +/* + The abstract machine for RmlUi data scripts. + + The machine can execute a program which contains a list of instructions listed below. + + The abstract machine has three registers: + R Typically results and right-hand side arguments. + L Typically left-hand side arguments. + C Typically center arguments (eg. in ternary operator). + + And two stacks: + S The main program stack. + A The arguments stack, only used to pass arguments to an external transform function. + + In addition, each instruction has an optional payload: + D Instruction data (payload). + + Notation used in the instruction list below: + S+ Push to stack S. + S- Pop stack S (returns the popped value). +*/ +enum class Instruction { // Assignment (register/stack) = Read (register R/L/C, instruction data D, or stack) + Push = 'P', // S+ = R + Pop = 'o', // = S- (D determines R/L/C) + Literal = 'D', // R = D + Variable = 'V', // R = DataModel.GetVariable(D) (D is an index into the variable address list) + Add = '+', // R = L + R + Subtract = '-', // R = L - R + Multiply = '*', // R = L * R + Divide = '/', // R = L / R + Not = '!', // R = !R + And = '&', // R = L && R + Or = '|', // R = L || R + Less = '<', // R = L < R + LessEq = 'L', // R = L <= R + Greater = '>', // R = L > R + GreaterEq = 'G', // R = L >= R + Equal = '=', // R = L == R + NotEqual = 'N', // R = L != R + Ternary = '?', // R = L ? C : R + Arguments = 'a', // A+ = S- (Repeated D times, where D gives the num. arguments) + TransformFnc = 'T', // R = DataModel.Execute( D, R, A ); A.Clear(); (D determines function name, R the input value, A the arguments) + EventFnc = 'E', // DataModel.EventCallback(D, A); A.Clear(); + Assign = 'A', // DataModel.SetVariable(D, R) +}; +enum class Register { + R, + L, + C +}; + +struct InstructionData { + Instruction instruction; + Variant data; +}; + +namespace Parse { + static void Assignment(DataParser& parser); + static void Expression(DataParser& parser); +} + + +class DataParser { +public: + DataParser(String expression, DataExpressionInterface expression_interface) : expression(std::move(expression)), expression_interface(expression_interface) {} + + char Look() { + if (reached_end) + return '\0'; + return expression[index]; + } + + bool Match(char c, bool skip_whitespace = true) { + if (c == Look()) { + Next(); + if (skip_whitespace) + SkipWhitespace(); + return true; + } + Expected(c); + return false; + } + + char Next() { + ++index; + if (index >= expression.size()) + reached_end = true; + return Look(); + } + + void SkipWhitespace() { + char c = Look(); + while (StringUtilities::IsWhitespace(c)) + c = Next(); + } + + void Error(const String message) + { + parse_error = true; + Log::Message(Log::LT_WARNING, "Error in data expression at %d. %s", index, message.c_str()); + Log::Message(Log::LT_WARNING, " \"%s\"", expression.c_str()); + + const size_t cursor_offset = size_t(index) + 3; + const String cursor_string = String(cursor_offset, ' ') + '^'; + Log::Message(Log::LT_WARNING, cursor_string.c_str()); + } + void Expected(String expected_symbols) { + const char c = Look(); + if (c == '\0') + Error(CreateString(expected_symbols.size() + 50, "Expected %s but found end of string.", expected_symbols.c_str())); + else + Error(CreateString(expected_symbols.size() + 50, "Expected %s but found character '%c'.", expected_symbols.c_str(), c)); + } + void Expected(char expected) { + Expected(String(1, '\'') + expected + '\''); + } + + bool Parse(bool is_assignment_expression) + { + program.clear(); + variable_addresses.clear(); + index = 0; + reached_end = false; + parse_error = false; + if (expression.empty()) + reached_end = true; + + SkipWhitespace(); + + if (is_assignment_expression) + Parse::Assignment(*this); + else + Parse::Expression(*this); + + if (!reached_end) { + parse_error = true; + Error(CreateString(50, "Unexpected character '%c' encountered.", Look())); + } + if (!parse_error && program_stack_size != 0) { + parse_error = true; + Error(CreateString(120, "Internal parser error, inconsistent stack operations. Stack size is %d at parse end.", program_stack_size)); + } + + return !parse_error; + } + + Program ReleaseProgram() { + RMLUI_ASSERT(!parse_error); + return std::move(program); + } + AddressList ReleaseAddresses() { + RMLUI_ASSERT(!parse_error); + return std::move(variable_addresses); + } + + void Emit(Instruction instruction, Variant data = Variant()) + { + RMLUI_ASSERTMSG(instruction != Instruction::Push && instruction != Instruction::Pop && + instruction != Instruction::Arguments && instruction != Instruction::Variable && instruction != Instruction::Assign, + "Use the Push(), Pop(), Arguments(), Variable(), and Assign() procedures for stack manipulation and variable instructions."); + program.push_back(InstructionData{ instruction, std::move(data) }); + } + void Push() { + program_stack_size += 1; + program.push_back(InstructionData{ Instruction::Push, Variant() }); + } + void Pop(Register destination) { + if (program_stack_size <= 0) { + Error("Internal parser error: Tried to pop an empty stack."); + return; + } + program_stack_size -= 1; + program.push_back(InstructionData{ Instruction::Pop, Variant(int(destination)) }); + } + void Arguments(int num_arguments) { + if (program_stack_size < num_arguments) { + Error(CreateString(128, "Internal parser error: Popping %d arguments, but the stack contains only %d elements.", num_arguments, program_stack_size)); + return; + } + program_stack_size -= num_arguments; + program.push_back(InstructionData{ Instruction::Arguments, Variant(int(num_arguments)) }); + } + void Variable(const String& name) { + VariableGetSet(name, false); + } + void Assign(const String& name) { + VariableGetSet(name, true); + } + +private: + void VariableGetSet(const String& name, bool is_assignment) + { + DataAddress address = expression_interface.ParseAddress(name); + if (address.empty()) { + Error(CreateString(name.size() + 50, "Could not find data variable with name '%s'.", name.c_str())); + return; + } + int index = int(variable_addresses.size()); + variable_addresses.push_back(std::move(address)); + program.push_back(InstructionData{ is_assignment ? Instruction::Assign : Instruction::Variable, Variant(int(index)) }); + } + + const String expression; + DataExpressionInterface expression_interface; + + size_t index = 0; + bool reached_end = false; + bool parse_error = true; + int program_stack_size = 0; + + Program program; + + AddressList variable_addresses; +}; + + +namespace Parse { + + // Forward declare all parse functions. + static void Assignment(DataParser& parser); + + // The following in order of precedence. + static void Expression(DataParser& parser); + static void Relational(DataParser& parser); + static void Additive(DataParser& parser); + static void Term(DataParser& parser); + static void Factor(DataParser& parser); + + static void NumberLiteral(DataParser& parser); + static void StringLiteral(DataParser& parser); + static void Variable(DataParser& parser); + + static void Add(DataParser& parser); + static void Subtract(DataParser& parser); + static void Multiply(DataParser& parser); + static void Divide(DataParser& parser); + + static void Not(DataParser& parser); + static void And(DataParser& parser); + static void Or(DataParser& parser); + static void Less(DataParser& parser); + static void Greater(DataParser& parser); + static void Equal(DataParser& parser); + static void NotEqual(DataParser& parser); + + static void Ternary(DataParser& parser); + static void Function(DataParser& parser, Instruction function_type, const String& name); + + // Helper functions + static bool IsVariableCharacter(char c, bool is_first_character) + { + const bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + + if (is_first_character) + return is_alpha; + + if (is_alpha || (c >= '0' && c <= '9')) + return true; + + for (char valid_char : "_.[] ") + { + if (c == valid_char && valid_char != '\0') + return true; + } + + return false; + } + static String VariableName(DataParser& parser) + { + String name; + + bool is_first_character = true; + char c = parser.Look(); + + while (IsVariableCharacter(c, is_first_character)) + { + name += c; + c = parser.Next(); + is_first_character = false; + } + + // Right trim spaces in name + size_t new_size = String::npos; + for (int i = int(name.size()) - 1; i >= 1; i--) + { + if (name[i] == ' ') + new_size = size_t(i); + else + break; + } + if (new_size != String::npos) + name.resize(new_size); + + return name; + } + + // Parser functions + static void Assignment(DataParser& parser) + { + bool looping = true; + while (looping) + { + if (parser.Look() != '\0') + { + const String variable_name = VariableName(parser); + if (variable_name.empty()) { + parser.Error("Expected a variable for assignment but got an empty name."); + return; + } + + const char c = parser.Look(); + if (c == '=') + { + parser.Match('='); + Expression(parser); + parser.Assign(variable_name); + } + else if (c == '(' || c == ';' || c == '\0') + { + Function(parser, Instruction::EventFnc, variable_name); + } + else + { + parser.Expected("one of = ; ( or end of string"); + return; + } + } + + const char c = parser.Look(); + if (c == ';') + parser.Match(';'); + else if (c == '\0') + looping = false; + else + { + parser.Expected("';' or end of string"); + looping = false; + } + } + } + static void Expression(DataParser& parser) + { + Relational(parser); + + bool looping = true; + while (looping) + { + switch (parser.Look()) + { + case '&': And(parser); break; + case '|': + { + parser.Match('|', false); + if (parser.Look() == '|') + Or(parser); + else + { + parser.SkipWhitespace(); + const String fnc_name = VariableName(parser); + if (fnc_name.empty()) { + parser.Error("Expected a transform function name but got an empty name."); + return; + } + + Function(parser, Instruction::TransformFnc, fnc_name); + } + } + break; + case '?': Ternary(parser); break; + default: + looping = false; + } + } + } + + static void Relational(DataParser& parser) + { + Additive(parser); + + bool looping = true; + while (looping) + { + switch (parser.Look()) + { + case '=': Equal(parser); break; + case '!': NotEqual(parser); break; + case '<': Less(parser); break; + case '>': Greater(parser); break; + default: + looping = false; + } + } + } + + static void Additive(DataParser& parser) + { + Term(parser); + + bool looping = true; + while (looping) + { + switch (parser.Look()) + { + case '+': Add(parser); break; + case '-': Subtract(parser); break; + default: + looping = false; + } + } + } + + + static void Term(DataParser& parser) + { + Factor(parser); + + bool looping = true; + while (looping) + { + switch (parser.Look()) + { + case '*': Multiply(parser); break; + case '/': Divide(parser); break; + default: + looping = false; + } + } + } + static void Factor(DataParser& parser) + { + const char c = parser.Look(); + + if (c == '(') + { + parser.Match('('); + Expression(parser); + parser.Match(')'); + } + else if (c == '\'') + { + parser.Match('\'', false); + StringLiteral(parser); + parser.Match('\''); + } + else if (c == '!') + { + Not(parser); + parser.SkipWhitespace(); + } + else if (c == '-' || (c >= '0' && c <= '9')) + { + NumberLiteral(parser); + parser.SkipWhitespace(); + } + else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + { + Variable(parser); + parser.SkipWhitespace(); + } + else + parser.Expected("literal, variable name, parenthesis, or '!'"); + } + + static void NumberLiteral(DataParser& parser) + { + String str; + + bool first_match = false; + bool has_dot = false; + char c = parser.Look(); + if (c == '-') + { + str += c; + c = parser.Next(); + } + + while ((c >= '0' && c <= '9') || (c == '.' && !has_dot)) + { + first_match = true; + str += c; + if (c == '.') + has_dot = true; + c = parser.Next(); + } + + if (!first_match) + { + parser.Error(CreateString(100, "Invalid number literal. Expected '0-9' or '.' but found '%c'.", c)); + return; + } + + const double number = FromString(str, 0.0); + + parser.Emit(Instruction::Literal, Variant(number)); + } + static void StringLiteral(DataParser& parser) + { + String str; + + char c = parser.Look(); + char c_prev = '\0'; + + while (c != '\0' && (c != '\'' || c_prev == '\\')) + { + if (c_prev == '\\' && (c == '\\' || c == '\'')) { + str.pop_back(); + c_prev = '\0'; + } + else { + c_prev = c; + } + + str += c; + c = parser.Next(); + } + + parser.Emit(Instruction::Literal, Variant(str)); + } + static void Variable(DataParser& parser) + { + String name = VariableName(parser); + if (name.empty()) { + parser.Error("Expected a variable but got an empty name."); + return; + } + + // Keywords are parsed like variables, but are really literals. + // Check for them here. + if (name == "true") + parser.Emit(Instruction::Literal, Variant(true)); + else if (name == "false") + parser.Emit(Instruction::Literal, Variant(false)); + else + parser.Variable(name); + } + + static void Add(DataParser& parser) + { + parser.Match('+'); + parser.Push(); + Term(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::Add); + } + static void Subtract(DataParser& parser) + { + parser.Match('-'); + parser.Push(); + Term(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::Subtract); + } + static void Multiply(DataParser& parser) + { + parser.Match('*'); + parser.Push(); + Factor(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::Multiply); + } + static void Divide(DataParser& parser) + { + parser.Match('/'); + parser.Push(); + Factor(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::Divide); + } + + static void Not(DataParser& parser) + { + parser.Match('!'); + Factor(parser); + parser.Emit(Instruction::Not); + } + static void Or(DataParser& parser) + { + // We already skipped the first '|' during expression + parser.Match('|'); + parser.Push(); + Relational(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::Or); + } + static void And(DataParser& parser) + { + parser.Match('&', false); + parser.Match('&'); + parser.Push(); + Relational(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::And); + } + static void Less(DataParser& parser) + { + Instruction instruction = Instruction::Less; + parser.Match('<', false); + if (parser.Look() == '=') { + parser.Match('='); + instruction = Instruction::LessEq; + } + else { + parser.SkipWhitespace(); + } + parser.Push(); + Additive(parser); + parser.Pop(Register::L); + parser.Emit(instruction); + } + static void Greater(DataParser& parser) + { + Instruction instruction = Instruction::Greater; + parser.Match('>', false); + if (parser.Look() == '=') { + parser.Match('='); + instruction = Instruction::GreaterEq; + } + else { + parser.SkipWhitespace(); + } + parser.Push(); + Additive(parser); + parser.Pop(Register::L); + parser.Emit(instruction); + } + static void Equal(DataParser& parser) + { + parser.Match('=', false); + parser.Match('='); + parser.Push(); + Additive(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::Equal); + } + static void NotEqual(DataParser& parser) + { + parser.Match('!', false); + parser.Match('='); + parser.Push(); + Additive(parser); + parser.Pop(Register::L); + parser.Emit(Instruction::NotEqual); + } + + static void Ternary(DataParser& parser) + { + parser.Match('?'); + parser.Push(); + Expression(parser); + parser.Push(); + parser.Match(':'); + Expression(parser); + parser.Pop(Register::C); + parser.Pop(Register::L); + parser.Emit(Instruction::Ternary); + } + static void Function(DataParser& parser, Instruction function_type, const String& func_name) + { + RMLUI_ASSERT(function_type == Instruction::TransformFnc || function_type == Instruction::EventFnc); + + // We already matched the variable name (and '|' for transform functions) + if (parser.Look() == '(') + { + int num_arguments = 0; + bool looping = true; + + parser.Match('('); + if (parser.Look() == ')') { + parser.Match(')'); + looping = false; + } + else + parser.Push(); + + while (looping) + { + num_arguments += 1; + Expression(parser); + parser.Push(); + + switch (parser.Look()) { + case ')': parser.Match(')'); looping = false; break; + case ',': parser.Match(','); break; + default: + parser.Expected("one of ')' or ','"); + looping = false; + } + } + + if (num_arguments > 0) { + parser.Arguments(num_arguments); + parser.Pop(Register::R); + } + } + else { + parser.SkipWhitespace(); + } + + parser.Emit(function_type, Variant(func_name)); + } + + +} // + + + +class DataInterpreter { +public: + DataInterpreter(const Program& program, const AddressList& addresses, DataExpressionInterface expression_interface) + : program(program), addresses(addresses), expression_interface(expression_interface) {} + + bool Error(String message) const + { + message = "Error during execution. " + message; + Log::Message(Log::LT_WARNING, message.c_str()); + RMLUI_ERROR; + return false; + } + + bool Run() + { + bool success = true; + for (size_t i = 0; i < program.size(); i++) + { + if (!Execute(program[i].instruction, program[i].data)) + { + success = false; + break; + } + } + + if(success && !stack.empty()) + Log::Message(Log::LT_WARNING, "Possible data interpreter stack corruption. Stack size is %d at end of execution (should be zero).", stack.size()); + + if(!success) + { + String program_str = DumpProgram(); + Log::Message(Log::LT_WARNING, "Failed to execute program with %d instructions:", program.size()); + Log::Message(Log::LT_WARNING, program_str.c_str()); + } + + return success; + } + + String DumpProgram() const + { + String str; + for (size_t i = 0; i < program.size(); i++) + { + String instruction_str = program[i].data.Get(); + str += CreateString(50 + instruction_str.size(), " %4d '%c' %s\n", i, char(program[i].instruction), instruction_str.c_str()); + } + return str; + } + + Variant Result() const { + return R; + } + + +private: + Variant R, L, C; + Stack stack; + Vector arguments; + + const Program& program; + const AddressList& addresses; + DataExpressionInterface expression_interface; + + bool Execute(const Instruction instruction, const Variant& data) + { + auto AnyString = [](const Variant& v1, const Variant& v2) { + return v1.GetType() == Variant::STRING || v2.GetType() == Variant::STRING; + }; + + switch (instruction) + { + case Instruction::Push: + { + stack.push(std::move(R)); + R.Clear(); + } + break; + case Instruction::Pop: + { + if (stack.empty()) + return Error("Cannot pop stack, it is empty."); + + Register reg = Register(data.Get(-1)); + switch (reg) { + case Register::R: R = stack.top(); stack.pop(); break; + case Register::L: L = stack.top(); stack.pop(); break; + case Register::C: C = stack.top(); stack.pop(); break; + default: + return Error(CreateString(50, "Invalid register %d.", int(reg))); + } + } + break; + case Instruction::Literal: + { + R = data; + } + break; + case Instruction::Variable: + { + size_t variable_index = size_t(data.Get(-1)); + if (variable_index < addresses.size()) + R = expression_interface.GetValue(addresses[variable_index]); + else + return Error("Variable address not found."); + } + break; + case Instruction::Add: + { + if (AnyString(L, R)) + R = Variant(L.Get() + R.Get()); + else + R = Variant(L.Get() + R.Get()); + } + break; + case Instruction::Subtract: R = Variant(L.Get() - R.Get()); break; + case Instruction::Multiply: R = Variant(L.Get() * R.Get()); break; + case Instruction::Divide: R = Variant(L.Get() / R.Get()); break; + case Instruction::Not: R = Variant(!R.Get()); break; + case Instruction::And: R = Variant(L.Get() && R.Get()); break; + case Instruction::Or: R = Variant(L.Get() || R.Get()); break; + case Instruction::Less: R = Variant(L.Get() < R.Get()); break; + case Instruction::LessEq: R = Variant(L.Get() <= R.Get()); break; + case Instruction::Greater: R = Variant(L.Get() > R.Get()); break; + case Instruction::GreaterEq: R = Variant(L.Get() >= R.Get()); break; + case Instruction::Equal: + { + if (AnyString(L, R)) + R = Variant(L.Get() == R.Get()); + else + R = Variant(L.Get() == R.Get()); + } + break; + case Instruction::NotEqual: + { + if (AnyString(L, R)) + R = Variant(L.Get() != R.Get()); + else + R = Variant(L.Get() != R.Get()); + } + break; + case Instruction::Ternary: + { + if (L.Get()) + R = C; + } + break; + case Instruction::Arguments: + { + if (!arguments.empty()) + return Error("Argument stack is not empty."); + + int num_arguments = data.Get(-1); + if (num_arguments < 0) + return Error("Invalid number of arguments."); + if (stack.size() < size_t(num_arguments)) + return Error(CreateString(100, "Cannot pop %d arguments, stack contains only %d elements.", num_arguments, stack.size())); + + arguments.resize(num_arguments); + for (int i = num_arguments - 1; i >= 0; i--) + { + arguments[i] = std::move(stack.top()); + stack.pop(); + } + } + break; + case Instruction::TransformFnc: + { + const String function_name = data.Get(); + + if (!expression_interface.CallTransform(function_name, R, arguments)) + { + String arguments_str; + for (size_t i = 0; i < arguments.size(); i++) + { + arguments_str += arguments[i].Get(); + if (i < arguments.size() - 1) + arguments_str += ", "; + } + Error(CreateString(50 + function_name.size() + arguments_str.size(), "Failed to execute data function: %s(%s)", function_name.c_str(), arguments_str.c_str())); + } + + arguments.clear(); + } + break; + case Instruction::EventFnc: + { + const String function_name = data.Get(); + + if (!expression_interface.EventCallback(function_name, arguments)) + { + String arguments_str; + for (size_t i = 0; i < arguments.size(); i++) + { + arguments_str += arguments[i].Get(); + if (i < arguments.size() - 1) + arguments_str += ", "; + } + Error(CreateString(50 + function_name.size() + arguments_str.size(), "Failed to execute event callback: %s(%s)", function_name.c_str(), arguments_str.c_str())); + } + + arguments.clear(); + } + break; + case Instruction::Assign: + { + size_t variable_index = size_t(data.Get(-1)); + if (variable_index < addresses.size()) + { + if (!expression_interface.SetValue(addresses[variable_index], R)) + return Error("Could not assign to variable."); + } + else + return Error("Variable address not found."); + } + break; + default: + RMLUI_ERRORMSG("Instruction not implemented."); break; + } + return true; + } +}; + + + +#ifdef RMLUI_TESTS_ENABLED + +struct TestParser { + TestParser() : model(type_register.GetTransformFuncRegister()) + { + DataModelConstructor handle(&model, &type_register); + handle.Bind("radius", &radius); + handle.Bind("color_name", &color_name); + handle.BindFunc("color_value", [this](Variant& variant) { + variant = ToString(color_value); + }); + + String result; + result = TestExpression("!!10 - 1 ? 'hello' : 'world' | to_upper", "WORLD"); + result = TestExpression("(color_name) + (': rgba(' + color_value + ')')", "color: rgba(180, 100, 255, 255)"); + result = TestExpression("'hello world' | to_upper(5 + 12 == 17 ? 'yes' : 'no', 9*2)", "HELLO WORLD"); + result = TestExpression("true == false", "0"); + result = TestExpression("true != false", "1"); + result = TestExpression("true", "1"); + + result = TestExpression("true || false ? true && 3==1+2 ? 'Absolutely!' : 'well..' : 'no'", "Absolutely!"); + result = TestExpression(R"('It\'s a fit')", R"(It's a fit)"); + result = TestExpression("2 * 2", "4"); + result = TestExpression("50000 / 1500", "33.333"); + result = TestExpression("5*1+2", "7"); + result = TestExpression("5*(1+2)", "15"); + result = TestExpression("2*(-2)/4", "-1"); + result = TestExpression("5.2 + 19 + 'px'", "24.2px"); + + result = TestExpression("(radius | format(2)) + 'm'", "8.70m"); + result = TestExpression("radius < 10.5 ? 'smaller' : 'larger'", "smaller"); + TestAssignment("radius = 15"); + result = TestExpression("radius < 10.5 ? 'smaller' : 'larger'", "larger"); + TestAssignment("radius = 4; color_name = 'image-color'"); + result = TestExpression("radius == 4 && color_name == 'image-color'", "1"); + + result = TestExpression("5 == 1 + 2*2 || 8 == 1 + 4 ? 'yes' : 'no'", "yes"); + result = TestExpression("!!('fa' + 'lse')", "0"); + result = TestExpression("!!('tr' + 'ue')", "1"); + result = TestExpression("'fox' + 'dog' ? 'FoxyDog' : 'hot' + 'dog' | to_upper", "HOTDOG"); + + result = TestExpression("3.62345 | round", "4"); + result = TestExpression("3.62345 | format(0)", "4"); + result = TestExpression("3.62345 | format(2)", "3.62"); + result = TestExpression("3.62345 | format(10)", "3.6234500000"); + result = TestExpression("3.62345 | format(10, true)", "3.62345"); + result = TestExpression("3.62345 | round | format(2)", "4.00"); + result = TestExpression("3.0001 | format(2, false)", "3.00"); + result = TestExpression("3.0001 | format(2, true)", "3"); + + result = TestExpression("0.2 + 3.42345 | round", "4"); + result = TestExpression("(3.42345 | round) + 0.2", "3.2"); + result = TestExpression("(3.42345 | format(0)) + 0.2", "30.2"); // Here, format(0) returns a string, so the + means string concatenation. + } + + String TestExpression(String expression, String expected = String()) + { + String result; + DataExpressionInterface interface(&model, nullptr); + DataParser parser(expression, interface); + if (parser.Parse(false)) + { + Program program = parser.ReleaseProgram(); + AddressList addresses = parser.ReleaseAddresses(); + + DataInterpreter interpreter(program, addresses, interface); + if (interpreter.Run()) + result = interpreter.Result().Get(); + + if (!expected.empty() && result != expected) + { + String program_str = interpreter.DumpProgram(); + Log::Message(Log::LT_WARNING, "%s", program_str.c_str()); + RMLUI_ERRORMSG("Got unexpected data parser result."); + } + } + else + { + RMLUI_ERRORMSG("Could not parse expression."); + } + + return result; + }; + + bool TestAssignment(String expression) + { + bool result = false; + DataExpressionInterface interface(&model, nullptr); + DataParser parser(expression, interface); + if (parser.Parse(true)) + { + Program program = parser.ReleaseProgram(); + AddressList addresses = parser.ReleaseAddresses(); + + DataInterpreter interpreter(program, addresses, interface); + result = interpreter.Run(); + } + RMLUI_ASSERT(result); + return result; + }; + + DataTypeRegister type_register; + DataModel model; + + float radius = 8.7f; + String color_name = "color"; + Colourb color_value = Colourb(180, 100, 255); +}; + +static TestParser test_parser; + +#endif + + +DataExpression::DataExpression(String expression) : expression(expression) {} + +DataExpression::~DataExpression() +{ +} + +bool DataExpression::Parse(const DataExpressionInterface& expression_interface, bool is_assignment_expression) +{ + DataParser parser(expression, expression_interface); + if (!parser.Parse(is_assignment_expression)) + return false; + + program = parser.ReleaseProgram(); + addresses = parser.ReleaseAddresses(); + + return true; +} + +bool DataExpression::Run(const DataExpressionInterface& expression_interface, Variant& out_value) +{ + DataInterpreter interpreter(program, addresses, expression_interface); + + if (!interpreter.Run()) + return false; + + out_value = interpreter.Result(); + return true; +} + +StringList DataExpression::GetVariableNameList() const +{ + StringList list; + list.reserve(addresses.size()); + for (const DataAddress& address : addresses) + { + if (!address.empty()) + list.push_back(address[0].name); + } + return list; +} + +DataExpressionInterface::DataExpressionInterface(DataModel* data_model, Element* element, Event* event) : data_model(data_model), element(element), event(event) +{} + +DataAddress DataExpressionInterface::ParseAddress(const String& address_str) const +{ + if (address_str.size() >= 4 && address_str[0] == 'e' && address_str[1] == 'v' && address_str[2] == '.') + return DataAddress{ DataAddressEntry("ev"), DataAddressEntry(address_str.substr(3)) }; + + return data_model ? data_model->ResolveAddress(address_str, element) : DataAddress(); +} +Variant DataExpressionInterface::GetValue(const DataAddress& address) const +{ + Variant result; + if(event && address.size() == 2 && address.front().name == "ev") + { + auto& parameters = event->GetParameters(); + auto it = parameters.find(address.back().name); + if (it != parameters.end()) + result = it->second; + } + else if (data_model) + { + data_model->GetVariableInto(address, result); + } + return result; +} + +bool DataExpressionInterface::SetValue(const DataAddress& address, const Variant& value) const +{ + bool result = false; + if (data_model && !address.empty()) + { + if (DataVariable variable = data_model->GetVariable(address)) + result = variable.Set(value); + + if (result) + data_model->DirtyVariable(address.front().name); + } + return result; +} + +bool DataExpressionInterface::CallTransform(const String& name, Variant& inout_variant, const VariantList& arguments) +{ + return data_model ? data_model->CallTransform(name, inout_variant, arguments) : false; +} + +bool DataExpressionInterface::EventCallback(const String& name, const VariantList& arguments) +{ + if (!data_model || !event) + return false; + + const DataEventFunc* func = data_model->GetEventCallback(name); + if (!func || !*func) + return false; + + DataModelHandle handle(data_model); + func->operator()(handle, *event, arguments); + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataExpression.h b/thirdparty/RmlUi/Source/Core/DataExpression.h new file mode 100644 index 000000000..e8a8940a5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataExpression.h @@ -0,0 +1,82 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATAEXPRESSION_H +#define RMLUI_CORE_DATAEXPRESSION_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/DataTypes.h" + +namespace Rml { + +class Element; +class DataModel; +struct InstructionData; +using Program = Vector; +using AddressList = Vector; + +class DataExpressionInterface { +public: + DataExpressionInterface() = default; + DataExpressionInterface(DataModel* data_model, Element* element, Event* event = nullptr); + + DataAddress ParseAddress(const String& address_str) const; + Variant GetValue(const DataAddress& address) const; + bool SetValue(const DataAddress& address, const Variant& value) const; + bool CallTransform(const String& name, Variant& inout_result, const VariantList& arguments); + bool EventCallback(const String& name, const VariantList& arguments); + +private: + DataModel* data_model = nullptr; + Element* element = nullptr; + Event* event = nullptr; +}; + + +class DataExpression { +public: + DataExpression(String expression); + ~DataExpression(); + + bool Parse(const DataExpressionInterface& expression_interface, bool is_assignment_expression); + + bool Run(const DataExpressionInterface& expression_interface, Variant& out_value); + + // Available after Parse() + StringList GetVariableNameList() const; + +private: + String expression; + + Program program; + AddressList addresses; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DataModel.cpp b/thirdparty/RmlUi/Source/Core/DataModel.cpp new file mode 100644 index 000000000..d44f286ab --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataModel.cpp @@ -0,0 +1,467 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/DataController.h" +#include "../../Include/RmlUi/Core/DataView.h" +#include "../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +static DataAddress ParseAddress(const String& address_str) +{ + StringList list; + StringUtilities::ExpandString(list, address_str, '.'); + + DataAddress address; + address.reserve(list.size() * 2); + + for (const auto& item : list) + { + if (item.empty()) + return DataAddress(); + + size_t i_open = item.find('[', 0); + if (i_open == 0) + return DataAddress(); + + address.emplace_back(item.substr(0, i_open)); + + while (i_open != String::npos) + { + size_t i_close = item.find(']', i_open + 1); + if (i_close == String::npos) + return DataAddress(); + + int index = FromString(item.substr(i_open + 1, i_close - i_open), -1); + if (index < 0) + return DataAddress(); + + address.emplace_back(index); + + i_open = item.find('[', i_close + 1); + } + // TODO: Abort on invalid characters among [ ] and after the last found bracket? + } + + RMLUI_ASSERT(!address.empty() && !address[0].name.empty()); + + return address; +} + +// Returns an error string on error, or nullptr on success. +static const char* LegalVariableName(const String& name) +{ + static SmallUnorderedSet reserved_names{ "it", "ev", "true", "false", "size", "literal" }; + + if (name.empty()) + return "Name cannot be empty."; + + const String name_lower = StringUtilities::ToLower(name); + + const char first = name_lower.front(); + if (!(first >= 'a' && first <= 'z')) + return "First character must be 'a-z' or 'A-Z'."; + + for (const char c : name_lower) + { + if (!(c == '_' || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))) + return "Name must strictly contain characters a-z, A-Z, 0-9 and under_score."; + } + + if (reserved_names.count(name_lower) == 1) + return "Name is reserved."; + + return nullptr; +} + +static String DataAddressToString(const DataAddress& address) +{ + String result; + bool is_first = true; + for (auto& entry : address) + { + if (entry.index >= 0) + result += '[' + ToString(entry.index) + ']'; + else + { + if (!is_first) + result += "."; + result += entry.name; + } + is_first = false; + } + return result; +} + +DataModel::DataModel(const TransformFuncRegister* transform_register) : transform_register(transform_register) +{ + views = MakeUnique(); + controllers = MakeUnique(); +} + +DataModel::~DataModel() +{ + RMLUI_ASSERT(attached_elements.empty()); +} + +void DataModel::AddView(DataViewPtr view) { + views->Add(std::move(view)); +} + +void DataModel::AddController(DataControllerPtr controller) { + controllers->Add(std::move(controller)); +} + +bool DataModel::BindVariable(const String& name, DataVariable variable) +{ + const char* name_error_str = LegalVariableName(name); + if (name_error_str) + { + Log::Message(Log::LT_WARNING, "Could not bind data variable '%s'. %s", name.c_str(), name_error_str); + return false; + } + + if (!variable) + { + Log::Message(Log::LT_WARNING, "Could not bind variable '%s' to data model, data type not registered.", name.c_str()); + return false; + } + + bool inserted = variables.emplace(name, variable).second; + if (!inserted) + { + Log::Message(Log::LT_WARNING, "Data model variable with name '%s' already exists.", name.c_str()); + return false; + } + + return true; +} + +bool DataModel::BindFunc(const String& name, DataGetFunc get_func, DataSetFunc set_func) +{ + auto result = function_variable_definitions.emplace(name, nullptr); + auto& it = result.first; + bool inserted = result.second; + if (!inserted) + { + Log::Message(Log::LT_ERROR, "Data get/set function with name %s already exists in model", name.c_str()); + return false; + } + auto& func_definition_ptr = it->second; + func_definition_ptr = MakeUnique(std::move(get_func), std::move(set_func)); + + return BindVariable(name, DataVariable(func_definition_ptr.get(), nullptr)); +} + +bool DataModel::BindEventCallback(const String& name, DataEventFunc event_func) +{ + const char* name_error_str = LegalVariableName(name); + if (name_error_str) + { + Log::Message(Log::LT_WARNING, "Could not bind data event callback '%s'. %s", name.c_str(), name_error_str); + return false; + } + + if (!event_func) + { + Log::Message(Log::LT_WARNING, "Could not bind data event callback '%s' to data model, empty function provided.", name.c_str()); + return false; + } + + bool inserted = event_callbacks.emplace(name, std::move(event_func)).second; + if (!inserted) + { + Log::Message(Log::LT_WARNING, "Data event callback with name '%s' already exists.", name.c_str()); + return false; + } + + return true; +} + +bool DataModel::InsertAlias(Element* element, const String& alias_name, DataAddress replace_with_address) +{ + if (replace_with_address.empty() || replace_with_address.front().name.empty()) + { + Log::Message(Log::LT_WARNING, "Could not add alias variable '%s' to data model, replacement address invalid.", alias_name.c_str()); + return false; + } + + if (variables.count(alias_name) == 1) + Log::Message(Log::LT_WARNING, "Alias variable '%s' is shadowed by a global variable.", alias_name.c_str()); + + auto& map = aliases.emplace(element, SmallUnorderedMap()).first->second; + + auto it = map.find(alias_name); + if (it != map.end()) + Log::Message(Log::LT_WARNING, "Alias name '%s' in data model already exists, replaced.", alias_name.c_str()); + + map[alias_name] = std::move(replace_with_address); + + return true; +} + +bool DataModel::EraseAliases(Element* element) +{ + return aliases.erase(element) == 1; +} + +DataAddress DataModel::ResolveAddress(const String& address_str, Element* element) const +{ + DataAddress address = ParseAddress(address_str); + + if (address.empty()) + return address; + + const String& first_name = address.front().name; + + auto it = variables.find(first_name); + if (it != variables.end()) + return address; + + // Look for a variable alias for the first name. + + Element* ancestor = element; + while (ancestor && ancestor->GetDataModel() == this) + { + auto it_element = aliases.find(ancestor); + if (it_element != aliases.end()) + { + const auto& alias_names = it_element->second; + auto it_alias_name = alias_names.find(first_name); + if (it_alias_name != alias_names.end()) + { + const DataAddress& replace_address = it_alias_name->second; + if (replace_address.empty() || replace_address.front().name.empty()) + { + // Variable alias is invalid + return DataAddress(); + } + + // Insert the full alias address, replacing the first element. + address[0] = replace_address[0]; + address.insert(address.begin() + 1, replace_address.begin() + 1, replace_address.end()); + return address; + } + } + + ancestor = ancestor->GetParentNode(); + } + + Log::Message(Log::LT_WARNING, "Could not find variable name '%s' in data model.", address_str.c_str()); + + return DataAddress(); +} + +DataVariable DataModel::GetVariable(const DataAddress& address) const +{ + if (address.empty()) + return DataVariable(); + + auto it = variables.find(address.front().name); + if (it != variables.end()) + { + DataVariable variable = it->second; + + for (int i = 1; i < (int)address.size() && variable; i++) + { + variable = variable.Child(address[i]); + if (!variable) + return DataVariable(); + } + + return variable; + } + + if (address[0].name == "literal") + { + if (address.size() > 2 && address[1].name == "int") + return MakeLiteralIntVariable(address[2].index); + } + + return DataVariable(); +} + +const DataEventFunc* DataModel::GetEventCallback(const String& name) +{ + auto it = event_callbacks.find(name); + if (it == event_callbacks.end()) + { + Log::Message(Log::LT_WARNING, "Could not find data event callback '%s' in data model.", name.c_str()); + return nullptr; + } + + return &it->second; +} + +bool DataModel::GetVariableInto(const DataAddress& address, Variant& out_value) const { + DataVariable variable = GetVariable(address); + bool result = (variable && variable.Get(out_value)); + if (!result) + Log::Message(Log::LT_WARNING, "Could not get value from data variable '%s'.", DataAddressToString(address).c_str()); + return result; +} + +void DataModel::DirtyVariable(const String& variable_name) +{ + RMLUI_ASSERTMSG(LegalVariableName(variable_name) == nullptr, "Illegal variable name provided. Only top-level variables can be dirtied."); + RMLUI_ASSERTMSG(variables.count(variable_name) == 1, "In DirtyVariable: Variable name not found among added variables."); + dirty_variables.emplace(variable_name); +} + +bool DataModel::IsVariableDirty(const String& variable_name) const +{ + RMLUI_ASSERTMSG(LegalVariableName(variable_name) == nullptr, "Illegal variable name provided. Only top-level variables can be dirtied."); + return dirty_variables.count(variable_name) == 1; +} + +bool DataModel::CallTransform(const String& name, Variant& inout_result, const VariantList& arguments) const +{ + if (transform_register) + return transform_register->Call(name, inout_result, arguments); + return false; +} + +void DataModel::AttachModelRootElement(Element* element) +{ + attached_elements.insert(element); +} + +ElementList DataModel::GetAttachedModelRootElements() const +{ + return ElementList(attached_elements.begin(), attached_elements.end()); +} + +void DataModel::OnElementRemove(Element* element) +{ + EraseAliases(element); + views->OnElementRemove(element); + controllers->OnElementRemove(element); + attached_elements.erase(element); +} + +bool DataModel::Update() +{ + bool result = views->Update(*this, dirty_variables); + dirty_variables.clear(); + return result; +} + + + +#ifdef RMLUI_DEBUG + +static struct TestDataVariables { + TestDataVariables() + { + using IntVector = Vector; + + struct FunData { + int i = 99; + String x = "hello"; + IntVector magic = { 3, 5, 7, 11, 13 }; + }; + + using FunArray = Array; + + struct SmartData { + bool valid = true; + FunData fun; + FunArray more_fun; + }; + + DataModel model; + DataTypeRegister types; + + DataModelConstructor handle(&model, &types); + + { + handle.RegisterArray(); + + if (auto fun_handle = handle.RegisterStruct()) + { + fun_handle.RegisterMember("i", &FunData::i); + fun_handle.RegisterMember("x", &FunData::x); + fun_handle.RegisterMember("magic", &FunData::magic); + } + + handle.RegisterArray(); + + if (auto smart_handle = handle.RegisterStruct()) + { + smart_handle.RegisterMember("valid", &SmartData::valid); + smart_handle.RegisterMember("fun", &SmartData::fun); + smart_handle.RegisterMember("more_fun", &SmartData::more_fun); + } + } + + SmartData data; + data.fun.x = "Hello, we're in SmartData!"; + + handle.Bind("data", &data); + + { + Vector test_addresses = { "data.more_fun[1].magic[3]", "data.more_fun[1].magic.size", "data.fun.x", "data.valid" }; + Vector expected_results = { ToString(data.more_fun[1].magic[3]), ToString(int(data.more_fun[1].magic.size())), ToString(data.fun.x), ToString(data.valid) }; + + Vector results; + + for (auto& str_address : test_addresses) + { + DataAddress address = ParseAddress(str_address); + + Variant result; + if(model.GetVariableInto(address, result)) + results.push_back(result.Get()); + } + + RMLUI_ASSERT(results == expected_results); + + bool success = true; + success &= model.GetVariable(ParseAddress("data.more_fun[1].magic[1]")).Set(Variant(String("199"))); + RMLUI_ASSERT(success && data.more_fun[1].magic[1] == 199); + + data.fun.magic = { 99, 190, 55, 2000, 50, 60, 70, 80, 90 }; + + Variant get_result; + + const int magic_size = int(data.fun.magic.size()); + success &= model.GetVariable(ParseAddress("data.fun.magic.size")).Get(get_result); + RMLUI_ASSERT(success && get_result.Get() == ToString(magic_size)); + RMLUI_ASSERT(model.GetVariable(ParseAddress("data.fun.magic")).Size() == magic_size); + + success &= model.GetVariable(ParseAddress("data.fun.magic[8]")).Get(get_result); + RMLUI_ASSERT(success && get_result.Get() == "90"); + } + } +} test_data_variables; + + +#endif + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataTypeRegister.cpp b/thirdparty/RmlUi/Source/Core/DataTypeRegister.cpp new file mode 100644 index 000000000..24e4a554d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataTypeRegister.cpp @@ -0,0 +1,123 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/DataTypeRegister.h" + +namespace Rml { + +DataTypeRegister::DataTypeRegister() +{ + // Add default transform functions. + + transform_register.Register("to_lower", [](Variant& variant, const VariantList& /*arguments*/) -> bool { + String value; + if (!variant.GetInto(value)) + return false; + variant = StringUtilities::ToLower(value); + return true; + }); + + transform_register.Register("to_upper", [](Variant& variant, const VariantList& /*arguments*/) -> bool { + String value; + if (!variant.GetInto(value)) + return false; + variant = StringUtilities::ToUpper(value); + return true; + }); + + transform_register.Register("format", [](Variant& variant, const VariantList& arguments) -> bool { + // Arguments in: + // 0 : int[0,32] Precision. Number of digits after the decimal point. + // [1]: bool True to remove trailing zeros (default = false). + if (arguments.size() < 1 || arguments.size() > 2) { + Log::Message(Log::LT_WARNING, "Transform function 'format' requires at least one argument, at most two arguments."); + return false; + } + int precision = 0; + if (!arguments[0].GetInto(precision) || precision < 0 || precision > 32) { + Log::Message(Log::LT_WARNING, "Transform function 'format': First argument must be an integer in [0, 32]."); + return false; + } + bool remove_trailing_zeros = false; + if (arguments.size() >= 2) { + if (!arguments[1].GetInto(remove_trailing_zeros)) + return false; + } + + double value = 0; + if (!variant.GetInto(value)) + return false; + + String format_specifier = String(remove_trailing_zeros ? "%#." : "%.") + ToString(precision) + 'f'; + String result; + if (FormatString(result, 64, format_specifier.c_str(), value) == 0) + return false; + + if (remove_trailing_zeros) + StringUtilities::TrimTrailingDotZeros(result); + + variant = result; + return true; + }); + + transform_register.Register("round", [](Variant& variant, const VariantList& /*arguments*/) -> bool { + double value = 0; + if (!variant.GetInto(value)) + return false; + variant = Math::RoundFloat(value); + return true; + }); +} + +DataTypeRegister::~DataTypeRegister() +{} + +void TransformFuncRegister::Register(const String& name, DataTransformFunc transform_func) +{ + RMLUI_ASSERT(transform_func); + bool inserted = transform_functions.emplace(name, std::move(transform_func)).second; + if (!inserted) + { + Log::Message(Log::LT_ERROR, "Transform function '%s' already exists.", name.c_str()); + RMLUI_ERROR; + } +} + +bool TransformFuncRegister::Call(const String& name, Variant& inout_result, const VariantList& arguments) const +{ + auto it = transform_functions.find(name); + if (it == transform_functions.end()) + return false; + + const DataTransformFunc& transform_func = it->second; + RMLUI_ASSERT(transform_func); + + return transform_func(inout_result, arguments); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataVariable.cpp b/thirdparty/RmlUi/Source/Core/DataVariable.cpp new file mode 100644 index 000000000..d5694483e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataVariable.cpp @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/DataVariable.h" + +namespace Rml { + +bool DataVariable::Get(Variant& variant) { + return definition->Get(ptr, variant); +} + +bool DataVariable::Set(const Variant& variant) { + return definition->Set(ptr, variant); +} + +int DataVariable::Size() { + return definition->Size(ptr); +} + +DataVariable DataVariable::Child(const DataAddressEntry& address) { + return definition->Child(ptr, address); +} + +DataVariableType DataVariable::Type() { + return definition->Type(); +} + + +bool VariableDefinition::Get(void* /*ptr*/, Variant& /*variant*/) { + Log::Message(Log::LT_WARNING, "Values can only be retrieved from scalar data types."); + return false; +} +bool VariableDefinition::Set(void* /*ptr*/, const Variant& /*variant*/) { + Log::Message(Log::LT_WARNING, "Values can only be assigned to scalar data types."); + return false; +} +int VariableDefinition::Size(void* /*ptr*/) { + Log::Message(Log::LT_WARNING, "Tried to get the size from a non-array data type."); + return 0; +} +DataVariable VariableDefinition::Child(void* /*ptr*/, const DataAddressEntry& /*address*/) { + Log::Message(Log::LT_WARNING, "Tried to get the child of a scalar type."); + return DataVariable(); +} + +class LiteralIntDefinition final : public VariableDefinition { +public: + LiteralIntDefinition() : VariableDefinition(DataVariableType::Scalar) {} + + bool Get(void* ptr, Variant& variant) override + { + variant = static_cast(reinterpret_cast(ptr)); + return true; + } +}; + +DataVariable MakeLiteralIntVariable(int value) +{ + static LiteralIntDefinition literal_int_definition; + return DataVariable(&literal_int_definition, reinterpret_cast(static_cast(value))); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataView.cpp b/thirdparty/RmlUi/Source/Core/DataView.cpp new file mode 100644 index 000000000..2e6d70fce --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataView.cpp @@ -0,0 +1,160 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/DataView.h" +#include "../../Include/RmlUi/Core/Element.h" +#include + +namespace Rml { + +DataView::~DataView() +{} + +Element* DataView::GetElement() const +{ + Element* result = attached_element.get(); + if (!result) + Log::Message(Log::LT_WARNING, "Could not retrieve element in view, was it destroyed?"); + return result; +} + +int DataView::GetElementDepth() const { + return element_depth; +} + +bool DataView::IsValid() const { + return static_cast(attached_element); +} + +DataView::DataView(Element* element) : attached_element(element->GetObserverPtr()), element_depth(0) { + if (element) + { + for (Element* parent = element->GetParentNode(); parent; parent = parent->GetParentNode()) + element_depth += 1; + } +} + + +DataViews::DataViews() +{} + +DataViews::~DataViews() +{} + +void DataViews::Add(DataViewPtr view) { + views_to_add.push_back(std::move(view)); +} + +void DataViews::OnElementRemove(Element* element) +{ + for (auto it = views.begin(); it != views.end();) + { + auto& view = *it; + if (view && view->GetElement() == element) + { + views_to_remove.push_back(std::move(view)); + it = views.erase(it); + } + else + ++it; + } +} + +bool DataViews::Update(DataModel& model, const DirtyVariables& dirty_variables) +{ + bool result = false; + + // View updates may result in newly added views, thus we do it recursively but with an upper limit. + // Without the loop, newly added views won't be updated until the next Update() call. + for(int i = 0; i == 0 || (!views_to_add.empty() && i < 10); i++) + { + Vector dirty_views; + + if (!views_to_add.empty()) + { + views.reserve(views.size() + views_to_add.size()); + for (auto&& view : views_to_add) + { + dirty_views.push_back(view.get()); + for (const String& variable_name : view->GetVariableNameList()) + name_view_map.emplace(variable_name, view.get()); + + views.push_back(std::move(view)); + } + views_to_add.clear(); + } + + for (const String& variable_name : dirty_variables) + { + auto pair = name_view_map.equal_range(variable_name); + for (auto it = pair.first; it != pair.second; ++it) + dirty_views.push_back(it->second); + } + + // Remove duplicate entries + std::sort(dirty_views.begin(), dirty_views.end()); + auto it_remove = std::unique(dirty_views.begin(), dirty_views.end()); + dirty_views.erase(it_remove, dirty_views.end()); + + // Sort by the element's depth in the document tree so that any structural changes due to a changed variable are reflected in the element's children. + // Eg. the 'data-for' view will remove children if any of its data variable array size is reduced. + std::sort(dirty_views.begin(), dirty_views.end(), [](auto&& left, auto&& right) { return left->GetElementDepth() < right->GetElementDepth(); }); + + for (DataView* view : dirty_views) + { + RMLUI_ASSERT(view); + if (!view) + continue; + + if (view->IsValid()) + result |= view->Update(model); + } + + // Destroy views marked for destruction + // @performance: Horrible... + if (!views_to_remove.empty()) + { + for (const auto& view : views_to_remove) + { + for (auto it = name_view_map.begin(); it != name_view_map.end(); ) + { + if (it->second == view.get()) + it = name_view_map.erase(it); + else + ++it; + } + } + + views_to_remove.clear(); + } + } + + return result; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataViewDefault.cpp b/thirdparty/RmlUi/Source/Core/DataViewDefault.cpp new file mode 100644 index 000000000..9a212b774 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataViewDefault.cpp @@ -0,0 +1,493 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DataViewDefault.h" +#include "DataExpression.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Variant.h" + +namespace Rml { + +DataViewCommon::DataViewCommon(Element* element, String override_modifier) : DataView(element), modifier(override_modifier) +{} + +bool DataViewCommon::Initialize(DataModel& model, Element* element, const String& expression_str, const String& in_modifier) +{ + // The modifier can be overriden in the constructor + if (modifier.empty()) + modifier = in_modifier; + + expression = MakeUnique(expression_str); + DataExpressionInterface interface(&model, element); + + bool result = expression->Parse(interface, false); + return result; +} + +StringList DataViewCommon::GetVariableNameList() const { + RMLUI_ASSERT(expression); + return expression->GetVariableNameList(); +} + +const String& DataViewCommon::GetModifier() const { + return modifier; +} + +DataExpression& DataViewCommon::GetExpression() { + RMLUI_ASSERT(expression); + return *expression; +} + +void DataViewCommon::Release() +{ + delete this; +} + + +DataViewAttribute::DataViewAttribute(Element* element) : DataViewCommon(element) +{} + +DataViewAttribute::DataViewAttribute(Element * element, String override_attribute) : DataViewCommon(element, std::move(override_attribute)) +{} + +bool DataViewAttribute::Update(DataModel& model) +{ + const String& attribute_name = GetModifier(); + bool result = false; + Variant variant; + Element* element = GetElement(); + DataExpressionInterface interface(&model, element); + + if (element && GetExpression().Run(interface, variant)) + { + const String value = variant.Get(); + const Variant* attribute = element->GetAttribute(attribute_name); + + if (!attribute || (attribute && attribute->Get() != value)) + { + element->SetAttribute(attribute_name, value); + result = true; + } + } + return result; +} + + +DataViewValue::DataViewValue(Element* element) : DataViewAttribute(element, "value") +{} + + +DataViewStyle::DataViewStyle(Element* element) : DataViewCommon(element) +{} + +bool DataViewStyle::Update(DataModel& model) +{ + const String& property_name = GetModifier(); + bool result = false; + Variant variant; + Element* element = GetElement(); + DataExpressionInterface interface(&model, element); + + if (element && GetExpression().Run(interface, variant)) + { + const String value = variant.Get(); + const Property* p = element->GetLocalProperty(property_name); + if (!p || p->Get() != value) + { + element->SetProperty(property_name, value); + result = true; + } + } + return result; +} + + +DataViewClass::DataViewClass(Element* element) : DataViewCommon(element) +{} + +bool DataViewClass::Update(DataModel& model) +{ + const String& class_name = GetModifier(); + bool result = false; + Variant variant; + Element* element = GetElement(); + DataExpressionInterface interface(&model, element); + + if (element && GetExpression().Run(interface, variant)) + { + const bool activate = variant.Get(); + const bool is_set = element->IsClassSet(class_name); + if (activate != is_set) + { + element->SetClass(class_name, activate); + result = true; + } + } + return result; +} + + +DataViewRml::DataViewRml(Element* element) : DataViewCommon(element) +{} + +bool DataViewRml::Update(DataModel & model) +{ + bool result = false; + Variant variant; + Element* element = GetElement(); + DataExpressionInterface interface(&model, element); + + if (element && GetExpression().Run(interface, variant)) + { + String new_rml = variant.Get(); + if (new_rml != previous_rml) + { + element->SetInnerRML(new_rml); + previous_rml = std::move(new_rml); + result = true; + } + } + return result; +} + + +DataViewIf::DataViewIf(Element* element) : DataViewCommon(element) +{} + +bool DataViewIf::Update(DataModel& model) +{ + bool result = false; + Variant variant; + Element* element = GetElement(); + DataExpressionInterface interface(&model, element); + + if (element && GetExpression().Run(interface, variant)) + { + const bool value = variant.Get(); + const bool is_visible = (element->GetLocalStyleProperties().count(PropertyId::Display) == 0); + if(is_visible != value) + { + if (value) + element->RemoveProperty(PropertyId::Display); + else + element->SetProperty(PropertyId::Display, Property(Style::Display::None)); + result = true; + } + } + return result; +} + + +DataViewVisible::DataViewVisible(Element* element) : DataViewCommon(element) +{} + +bool DataViewVisible::Update(DataModel& model) +{ + bool result = false; + Variant variant; + Element* element = GetElement(); + DataExpressionInterface interface(&model, element); + + if (element && GetExpression().Run(interface, variant)) + { + const bool value = variant.Get(); + const bool is_visible = (element->GetLocalStyleProperties().count(PropertyId::Visibility) == 0); + if (is_visible != value) + { + if (value) + element->RemoveProperty(PropertyId::Visibility); + else + element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + result = true; + } + } + return result; +} + + +DataViewText::DataViewText(Element* element) : DataView(element) +{} + +bool DataViewText::Initialize(DataModel& model, Element* element, const String& RMLUI_UNUSED_PARAMETER(expression), const String& RMLUI_UNUSED_PARAMETER(modifier)) +{ + RMLUI_UNUSED(expression); + RMLUI_UNUSED(modifier); + + ElementText* element_text = rmlui_dynamic_cast(element); + if (!element_text) + return false; + + const String& in_text = element_text->GetText(); + + text.reserve(in_text.size()); + + DataExpressionInterface expression_interface(&model, element); + + size_t previous_close_brackets = 0; + size_t begin_brackets = 0; + while ((begin_brackets = in_text.find("{{", begin_brackets)) != String::npos) + { + text.insert(text.end(), in_text.begin() + previous_close_brackets, in_text.begin() + begin_brackets); + + const size_t begin_name = begin_brackets + 2; + const size_t end_name = in_text.find("}}", begin_name); + + if (end_name == String::npos) + return false; + + DataEntry entry; + entry.index = text.size(); + entry.data_expression = MakeUnique(String(in_text.begin() + begin_name, in_text.begin() + end_name)); + + if (entry.data_expression->Parse(expression_interface, false)) + data_entries.push_back(std::move(entry)); + + previous_close_brackets = end_name + 2; + begin_brackets = previous_close_brackets; + } + + if (data_entries.empty()) + return false; + + if (previous_close_brackets < in_text.size()) + text.insert(text.end(), in_text.begin() + previous_close_brackets, in_text.end()); + + return true; +} + +bool DataViewText::Update(DataModel& model) +{ + bool entries_modified = false; + { + Element* element = GetElement(); + DataExpressionInterface expression_interface(&model, element); + + for (DataEntry& entry : data_entries) + { + RMLUI_ASSERT(entry.data_expression); + Variant variant; + bool result = entry.data_expression->Run(expression_interface, variant); + const String value = variant.Get(); + if (result && entry.value != value) + { + entry.value = value; + entries_modified = true; + } + } + } + + if (entries_modified) + { + if (Element* element = GetElement()) + { + RMLUI_ASSERTMSG(rmlui_dynamic_cast(element), "Somehow the element type was changed from ElementText since construction of the view. Should not be possible?"); + + if (ElementText* text_element = static_cast(element)) + { + String new_text = BuildText(); + text_element->SetText(new_text); + } + } + else + { + Log::Message(Log::LT_WARNING, "Could not update data view text, element no longer valid. Was it destroyed?"); + } + } + + return entries_modified; +} + +StringList DataViewText::GetVariableNameList() const +{ + StringList full_list; + full_list.reserve(data_entries.size()); + + for (const DataEntry& entry : data_entries) + { + RMLUI_ASSERT(entry.data_expression); + + StringList entry_list = entry.data_expression->GetVariableNameList(); + full_list.insert(full_list.end(), + MakeMoveIterator(entry_list.begin()), + MakeMoveIterator(entry_list.end()) + ); + } + + return full_list; +} + +void DataViewText::Release() +{ + delete this; +} + +String DataViewText::BuildText() const +{ + size_t reserve_size = text.size(); + + for (const DataEntry& entry : data_entries) + reserve_size += entry.value.size(); + + String result; + result.reserve(reserve_size); + + size_t previous_index = 0; + for (const DataEntry& entry : data_entries) + { + result += text.substr(previous_index, entry.index - previous_index); + result += entry.value; + previous_index = entry.index; + } + + if (previous_index < text.size()) + result += text.substr(previous_index); + + return result; +} + + + +DataViewFor::DataViewFor(Element* element) : DataView(element) +{} + +bool DataViewFor::Initialize(DataModel& model, Element* element, const String& in_expression, const String& in_rml_content) +{ + rml_contents = in_rml_content; + + StringList iterator_container_pair; + StringUtilities::ExpandString(iterator_container_pair, in_expression, ':'); + + if (iterator_container_pair.empty() || iterator_container_pair.size() > 2 || iterator_container_pair.front().empty() || iterator_container_pair.back().empty()) + { + Log::Message(Log::LT_WARNING, "Invalid syntax in data-for '%s'", in_expression.c_str()); + return false; + } + + if (iterator_container_pair.size() == 2) + { + StringList iterator_index_pair; + StringUtilities::ExpandString(iterator_index_pair, iterator_container_pair.front(), ','); + + if (iterator_index_pair.empty()) + { + Log::Message(Log::LT_WARNING, "Invalid syntax in data-for '%s'", in_expression.c_str()); + return false; + } + else if (iterator_index_pair.size() == 1) + { + iterator_name = iterator_index_pair.front(); + } + else if (iterator_index_pair.size() == 2) + { + iterator_name = iterator_index_pair.front(); + iterator_index_name = iterator_index_pair.back(); + } + } + + if (iterator_name.empty()) + iterator_name = "it"; + + if (iterator_index_name.empty()) + iterator_index_name = "it_index"; + + const String& container_name = iterator_container_pair.back(); + + container_address = model.ResolveAddress(container_name, element); + if (container_address.empty()) + return false; + + element->SetProperty(PropertyId::Display, Property(Style::Display::None)); + + return true; +} + + +bool DataViewFor::Update(DataModel& model) +{ + DataVariable variable = model.GetVariable(container_address); + if (!variable) + return false; + + bool result = false; + const int size = variable.Size(); + const int num_elements = (int)elements.size(); + Element* element = GetElement(); + + for (int i = 0; i < Math::Max(size, num_elements); i++) + { + if (i >= num_elements) + { + ElementPtr new_element_ptr = Factory::InstanceElement(nullptr, element->GetTagName(), element->GetTagName(), attributes); + + DataAddress iterator_address; + iterator_address.reserve(container_address.size() + 1); + iterator_address = container_address; + iterator_address.push_back(DataAddressEntry(i)); + + DataAddress iterator_index_address = { + {"literal"}, {"int"}, {i} + }; + + model.InsertAlias(new_element_ptr.get(), iterator_name, std::move(iterator_address)); + model.InsertAlias(new_element_ptr.get(), iterator_index_name, std::move(iterator_index_address)); + + Element* new_element = element->GetParentNode()->InsertBefore(std::move(new_element_ptr), element); + elements.push_back(new_element); + + elements[i]->SetInnerRML(rml_contents); + + RMLUI_ASSERT(i < (int)elements.size()); + } + if (i >= size) + { + model.EraseAliases(elements[i]); + elements[i]->GetParentNode()->RemoveChild(elements[i]).reset(); + elements[i] = nullptr; + } + } + + if (num_elements > size) + elements.resize(size); + + return result; +} + +StringList DataViewFor::GetVariableNameList() const { + RMLUI_ASSERT(!container_address.empty()); + return StringList{ container_address.front().name }; +} + +void DataViewFor::Release() +{ + delete this; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DataViewDefault.h b/thirdparty/RmlUi/Source/Core/DataViewDefault.h new file mode 100644 index 000000000..8dc4918e9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DataViewDefault.h @@ -0,0 +1,173 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DATAVIEWDEFAULT_H +#define RMLUI_CORE_DATAVIEWDEFAULT_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/DataView.h" +#include "../../Include/RmlUi/Core/Variant.h" + +namespace Rml { + +class Element; +class DataExpression; +using DataExpressionPtr = UniquePtr; + + +class DataViewCommon : public DataView { +public: + DataViewCommon(Element* element, String override_modifier = String()); + + bool Initialize(DataModel& model, Element* element, const String& expression, const String& modifier) override; + + StringList GetVariableNameList() const override; + +protected: + const String& GetModifier() const; + DataExpression& GetExpression(); + + // Delete this + void Release() override; + +private: + String modifier; + DataExpressionPtr expression; +}; + + +class DataViewAttribute : public DataViewCommon { +public: + DataViewAttribute(Element* element); + DataViewAttribute(Element* element, String override_attribute); + + bool Update(DataModel& model) override; +}; + + +class DataViewValue final : public DataViewAttribute { +public: + DataViewValue(Element* element); +}; + + +class DataViewStyle final : public DataViewCommon { +public: + DataViewStyle(Element* element); + + bool Update(DataModel& model) override; +}; + + +class DataViewClass final : public DataViewCommon { +public: + DataViewClass(Element* element); + + bool Update(DataModel& model) override; +}; + + +class DataViewRml final : public DataViewCommon { +public: + DataViewRml(Element* element); + + bool Update(DataModel& model) override; + +private: + String previous_rml; +}; + + +class DataViewIf final : public DataViewCommon { +public: + DataViewIf(Element* element); + + bool Update(DataModel& model) override; +}; + + +class DataViewVisible final : public DataViewCommon { +public: + DataViewVisible(Element* element); + + bool Update(DataModel& model) override; +}; + + +class DataViewText final : public DataView { +public: + DataViewText(Element* in_element); + + bool Initialize(DataModel& model, Element* element, const String& expression, const String& modifier) override; + + bool Update(DataModel& model) override; + StringList GetVariableNameList() const override; + +protected: + void Release() override; + +private: + String BuildText() const; + + struct DataEntry { + size_t index = 0; // Index into 'text' + DataExpressionPtr data_expression; + String value; + }; + + String text; + Vector data_entries; +}; + + +class DataViewFor final : public DataView { +public: + DataViewFor(Element* element); + + bool Initialize(DataModel& model, Element* element, const String& expression, const String& inner_rml) override; + + bool Update(DataModel& model) override; + + StringList GetVariableNameList() const override; + +protected: + void Release() override; + +private: + DataAddress container_address; + String iterator_name; + String iterator_index_name; + String rml_contents; + ElementAttributes attributes; + + ElementList elements; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Decorator.cpp b/thirdparty/RmlUi/Source/Core/Decorator.cpp new file mode 100644 index 000000000..dd67e6161 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Decorator.cpp @@ -0,0 +1,104 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Decorator.h" +#include "TextureDatabase.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/Texture.h" +#include + +namespace Rml { + +Decorator::Decorator() +{ +} + +Decorator::~Decorator() +{ +} + +// Attempts to load a texture into the list of textures in use by the decorator. +int Decorator::LoadTexture(const String& texture_name, const String& rcss_path) +{ + if (texture_name == first_texture.GetSource()) + return 0; + + for (size_t i = 0; i < additional_textures.size(); i++) + { + if (texture_name == additional_textures[i].GetSource()) + return (int)i + 1; + } + + Texture texture; + texture.Set(texture_name, rcss_path); + + additional_textures.push_back(texture); + return (int)additional_textures.size(); +} + +int Decorator::AddTexture(const Texture& texture) +{ + if (!texture) + return -1; + + if (!first_texture) + first_texture = texture; + + if (first_texture == texture) + return 0; + + auto it = std::find(additional_textures.begin(), additional_textures.end(), texture); + if (it != additional_textures.end()) + return (int)(it - additional_textures.begin()) + 1; + + additional_textures.push_back(texture); + return (int)additional_textures.size(); +} + +int Decorator::GetNumTextures() const +{ + int result = (first_texture ? 1 : 0); + result += (int)additional_textures.size(); + return result; +} + +// Returns one of the decorator's previously loaded textures. +const Texture* Decorator::GetTexture(int index) const +{ + if (index == 0) + return &first_texture; + + index -= 1; + if (index < 0 || index >= (int)additional_textures.size()) + return nullptr; + + return &(additional_textures[index]); +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorGradient.cpp b/thirdparty/RmlUi/Source/Core/DecoratorGradient.cpp new file mode 100644 index 000000000..1f0d97b55 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorGradient.cpp @@ -0,0 +1,141 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorGradient.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +/* +Gradient decorator usage in CSS: + +decorator: gradient( direction start-color stop-color ); + +direction: horizontal|vertical; +start-color: #ff00ff; +stop-color: #00ff00; +*/ + +namespace Rml { + +//======================================================= + +DecoratorGradient::DecoratorGradient() +{ +} + +DecoratorGradient::~DecoratorGradient() +{ +} + +bool DecoratorGradient::Initialise(const Direction &dir_, const Colourb &start_, const Colourb & stop_) +{ + dir = dir_; + start = start_; + stop = stop_; + return true; +} + +DecoratorDataHandle DecoratorGradient::GenerateElementData(Element* element) const +{ + auto *data = new Geometry(element); + Vector2f padded_size = element->GetBox().GetSize(Box::PADDING); + + const float opacity = element->GetComputedValues().opacity; + + // Apply opacity + Colourb colour_start = start; + colour_start.alpha = (byte)(opacity * (float)colour_start.alpha); + Colourb colour_stop = stop; + colour_stop.alpha = (byte)(opacity * (float)colour_stop.alpha); + + auto &vertices = data->GetVertices(); + vertices.resize(4); + + auto &indices = data->GetIndices(); + indices.resize(6); + + GeometryUtilities::GenerateQuad(&vertices[0], &indices[0], Vector2f(0, 0), padded_size, colour_start, 0); + + if (dir == Direction::Horizontal) { + vertices[1].colour = vertices[2].colour = colour_stop; + } else if (dir == Direction::Vertical) { + vertices[2].colour = vertices[3].colour = colour_stop; + } + + data->SetHostElement(element); + return reinterpret_cast(data); +} + +void DecoratorGradient::ReleaseElementData(DecoratorDataHandle element_data) const +{ + delete reinterpret_cast(element_data); +} + +void DecoratorGradient::RenderElement(Element* element, DecoratorDataHandle element_data) const +{ + auto* data = reinterpret_cast(element_data); + data->Render(element->GetAbsoluteOffset(Box::PADDING).Round()); +} + +//======================================================= + +DecoratorGradientInstancer::DecoratorGradientInstancer() +{ + // register properties for the decorator + ids.direction = RegisterProperty("direction", "horizontal").AddParser("keyword", "horizontal, vertical").GetId(); + ids.start = RegisterProperty("start-color", "#ffffff").AddParser("color").GetId(); + ids.stop = RegisterProperty("stop-color", "#ffffff").AddParser("color").GetId(); + RegisterShorthand("decorator", "direction, start-color, stop-color", ShorthandType::FallThrough); +} + +DecoratorGradientInstancer::~DecoratorGradientInstancer() +{ +} + +SharedPtr DecoratorGradientInstancer::InstanceDecorator(const String & RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties_, + const DecoratorInstancerInterface& RMLUI_UNUSED_PARAMETER(interface_)) +{ + RMLUI_UNUSED(name); + RMLUI_UNUSED(interface_); + + DecoratorGradient::Direction dir = (DecoratorGradient::Direction)properties_.GetProperty(ids.direction)->Get< int >(); + Colourb start = properties_.GetProperty(ids.start)->Get(); + Colourb stop = properties_.GetProperty(ids.stop)->Get(); + + auto decorator = MakeShared(); + if (decorator->Initialise(dir, start, stop)) { + return decorator; + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorGradient.h b/thirdparty/RmlUi/Source/Core/DecoratorGradient.h new file mode 100644 index 000000000..8b2c20da4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorGradient.h @@ -0,0 +1,77 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORGRADIENT_H +#define RMLUI_CORE_DECORATORGRADIENT_H + +#include "../../Include/RmlUi/Core/Decorator.h" +#include "../../Include/RmlUi/Core/DecoratorInstancer.h" +#include "../../Include/RmlUi/Core/Property.h" + +namespace Rml { + +class DecoratorGradient : public Decorator +{ +public: + enum class Direction { Horizontal = 0, Vertical = 1 }; + + DecoratorGradient(); + virtual ~DecoratorGradient(); + + bool Initialise(const Direction &dir_, const Colourb &start_, const Colourb & stop_); + + DecoratorDataHandle GenerateElementData(Element* element) const override; + void ReleaseElementData(DecoratorDataHandle element_data) const override; + + void RenderElement(Element* element, DecoratorDataHandle element_data) const override; + +private: + Direction dir; + Colourb start, stop; +}; + + + +class DecoratorGradientInstancer : public DecoratorInstancer +{ +public: + DecoratorGradientInstancer(); + ~DecoratorGradientInstancer(); + + SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) override; + +private: + struct GradientPropertyIds { + PropertyId direction, start, stop; + }; + GradientPropertyIds ids; + +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorInstancer.cpp b/thirdparty/RmlUi/Source/Core/DecoratorInstancer.cpp new file mode 100644 index 000000000..8016efcb5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorInstancer.cpp @@ -0,0 +1,65 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/DecoratorInstancer.h" + +namespace Rml { + +DecoratorInstancer::DecoratorInstancer() : properties(10, 10) +{ +} + +DecoratorInstancer::~DecoratorInstancer() +{ +} + +// Returns the property specification associated with the instancer. +const PropertySpecification& DecoratorInstancer::GetPropertySpecification() const +{ + return properties; +} + +// Registers a property for the decorator. +PropertyDefinition& DecoratorInstancer::RegisterProperty(const String& property_name, const String& default_value) +{ + return properties.RegisterProperty(property_name, default_value, false, false); +} + +// Registers a shorthand property definition. +ShorthandId DecoratorInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type) +{ + return properties.RegisterShorthand(shorthand_name, property_names, type); +} + + +const Sprite* DecoratorInstancerInterface::GetSprite(const String& name) const { + return style_sheet.GetSprite(name); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorNinePatch.cpp b/thirdparty/RmlUi/Source/Core/DecoratorNinePatch.cpp new file mode 100644 index 000000000..f50d589fb --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorNinePatch.cpp @@ -0,0 +1,250 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorNinePatch.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +DecoratorNinePatch::DecoratorNinePatch() +{ +} + +DecoratorNinePatch::~DecoratorNinePatch() +{ +} + +bool DecoratorNinePatch::Initialise(const Rectangle& _rect_outer, const Rectangle& _rect_inner, const Array* _edges, const Texture& _texture) +{ + rect_outer = _rect_outer; + rect_inner = _rect_inner; + + if (_edges) + edges = MakeUnique< Array >(*_edges); + + int texture_index = AddTexture(_texture); + return (texture_index >= 0); +} + +DecoratorDataHandle DecoratorNinePatch::GenerateElementData(Element* element) const +{ + RenderInterface* render_interface = element->GetRenderInterface(); + const auto& computed = element->GetComputedValues(); + + Geometry* data = new Geometry(element); + + const Texture* texture = GetTexture(); + data->SetTexture(texture); + const Vector2i texture_dimensions_i = texture->GetDimensions(render_interface); + const Vector2f texture_dimensions = { (float)texture_dimensions_i.x, (float)texture_dimensions_i.y }; + + const Vector2f surface_dimensions = element->GetBox().GetSize(Box::PADDING); + + const float opacity = computed.opacity; + Colourb quad_colour = computed.image_color; + + quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha); + + + /* In the following, we operate on the four diagonal vertices in the grid, as they define the whole grid. */ + + // Absolute texture coordinates 'px' + Vector2f tex_pos[4]; + tex_pos[0] = { rect_outer.x, rect_outer.y }; + tex_pos[1] = { rect_inner.x, rect_inner.y }; + tex_pos[2] = { rect_inner.x + rect_inner.width, rect_inner.y + rect_inner.height }; + tex_pos[3] = { rect_outer.x + rect_outer.width, rect_outer.y + rect_outer.height }; + + // Normalized texture coordinates [0, 1] + Vector2f tex_coords[4]; + for (int i = 0; i < 4; i++) + tex_coords[i] = tex_pos[i] / texture_dimensions; + + // Surface position [0, surface_dimensions] + // Need to keep the corner patches at their native pixel size, but stretch the inner patches. + Vector2f surface_pos[4]; + surface_pos[0] = { 0, 0 }; + surface_pos[1] = tex_pos[1] - tex_pos[0]; + surface_pos[2] = surface_dimensions - (tex_pos[3] - tex_pos[2]); + surface_pos[3] = surface_dimensions; + + // Change the size of the edges if specified. + if (edges) + { + const float dp_ratio = ElementUtilities::GetDensityIndependentPixelRatio(element); + float lengths[4]; // top, right, bottom, left + lengths[0] = element->ResolveNumericProperty(&(*edges)[0], dp_ratio * (surface_pos[1].y - surface_pos[0].y)); + lengths[1] = element->ResolveNumericProperty(&(*edges)[1], dp_ratio * (surface_pos[3].x - surface_pos[2].x)); + lengths[2] = element->ResolveNumericProperty(&(*edges)[2], dp_ratio * (surface_pos[3].y - surface_pos[2].y)); + lengths[3] = element->ResolveNumericProperty(&(*edges)[3], dp_ratio * (surface_pos[1].x - surface_pos[0].x)); + + surface_pos[1].y = lengths[0]; + surface_pos[2].x = surface_dimensions.x - lengths[1]; + surface_pos[2].y = surface_dimensions.y - lengths[2]; + surface_pos[1].x = lengths[3]; + } + + // In case the surface dimensions are less than the size of the corners, we need to scale down the corner rectangles, one dimension at a time. + const Vector2f surface_center_size = surface_pos[2] - surface_pos[1]; + for (int i = 0; i < 2; i++) + { + if (surface_center_size[i] < 0.0f) + { + float top_left_size = tex_pos[1][i] - tex_pos[0][i]; + float bottom_right_size = tex_pos[3][i] - tex_pos[2][i]; + surface_pos[1][i] = top_left_size / (top_left_size + bottom_right_size) * surface_dimensions[i]; + surface_pos[2][i] = surface_pos[1][i]; + } + } + + /* Now we have all the coordinates we need. Expand the diagonal vertices to the 16 individual vertices. */ + + Vector& vertices = data->GetVertices(); + Vector& indices = data->GetIndices(); + + vertices.resize(4 * 4); + + for (int y = 0; y < 4; y++) + { + for (int x = 0; x < 4; x++) + { + Vertex& vertex = vertices[y * 4 + x]; + vertex.colour = quad_colour; + vertex.position = { surface_pos[x].x, surface_pos[y].y }; + vertex.tex_coord = { tex_coords[x].x, tex_coords[y].y }; + } + } + + // Nine rectangles, two triangles per rectangle, three indices per triangle. + indices.resize(9 * 2 * 3); + + // Fill in the indices one rectangle at a time. + const int top_left_indices[9] = { 0, 1, 2, 4, 5, 6, 8, 9, 10 }; + for (int rectangle = 0; rectangle < 9; rectangle++) + { + int i = rectangle * 6; + int top_left_index = top_left_indices[rectangle]; + indices[i] = top_left_index; + indices[i + 1] = top_left_index + 4; + indices[i + 2] = top_left_index + 1; + indices[i + 3] = top_left_index + 1; + indices[i + 4] = top_left_index + 4; + indices[i + 5] = top_left_index + 5; + } + + return reinterpret_cast(data); +} + +void DecoratorNinePatch::ReleaseElementData(DecoratorDataHandle element_data) const +{ + delete reinterpret_cast< Geometry* >(element_data); +} + +void DecoratorNinePatch::RenderElement(Element* element, DecoratorDataHandle element_data) const +{ + Geometry* data = reinterpret_cast< Geometry* >(element_data); + data->Render(element->GetAbsoluteOffset(Box::PADDING).Round()); +} + + + +DecoratorNinePatchInstancer::DecoratorNinePatchInstancer() +{ + sprite_outer_id = RegisterProperty("outer", "").AddParser("string").GetId(); + sprite_inner_id = RegisterProperty("inner", "").AddParser("string").GetId(); + edge_ids[0] = RegisterProperty("edge-top", "0px").AddParser("number_length_percent").GetId(); + edge_ids[1] = RegisterProperty("edge-right", "0px").AddParser("number_length_percent").GetId(); + edge_ids[2] = RegisterProperty("edge-bottom", "0px").AddParser("number_length_percent").GetId(); + edge_ids[3] = RegisterProperty("edge-left", "0px").AddParser("number_length_percent").GetId(); + + RegisterShorthand("edge", "edge-top, edge-right, edge-bottom, edge-left", ShorthandType::Box); + + RMLUI_ASSERT(sprite_outer_id != PropertyId::Invalid && sprite_inner_id != PropertyId::Invalid); + + RegisterShorthand("decorator", "outer, inner, edge?", ShorthandType::RecursiveCommaSeparated); +} + +DecoratorNinePatchInstancer::~DecoratorNinePatchInstancer() +{ +} + +SharedPtr DecoratorNinePatchInstancer::InstanceDecorator(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) +{ + RMLUI_UNUSED(name); + + bool edges_set = false; + Array edges; + for (int i = 0; i < 4; i++) + { + edges[i] = *properties.GetProperty(edge_ids[i]); + if (edges[i].value.Get(0.0f) != 0.0f) + { + edges_set = true; + } + } + + const Sprite* sprite_outer = nullptr; + const Sprite* sprite_inner = nullptr; + + { + const String sprite_name = properties.GetProperty(sprite_outer_id)->Get< String >(); + sprite_outer = interface.GetSprite(sprite_name); + if (!sprite_outer) + { + Log::Message(Log::LT_WARNING, "Could not find sprite named '%s' in ninepatch decorator.", sprite_name.c_str()); + return nullptr; + } + } + { + const String sprite_name = properties.GetProperty(sprite_inner_id)->Get< String >(); + sprite_inner = interface.GetSprite(sprite_name); + if (!sprite_inner) + { + Log::Message(Log::LT_WARNING, "Could not find sprite named '%s' in ninepatch decorator.", sprite_name.c_str()); + return nullptr; + } + } + + if (sprite_outer->sprite_sheet != sprite_inner->sprite_sheet) + { + Log::Message(Log::LT_WARNING, "The outer and inner sprites in a ninepatch decorator must be from the same sprite sheet."); + return nullptr; + } + + auto decorator = MakeShared(); + + if (!decorator->Initialise(sprite_outer->rectangle, sprite_inner->rectangle, (edges_set ? &edges : nullptr), sprite_outer->sprite_sheet->texture)) + return nullptr; + + return decorator; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorNinePatch.h b/thirdparty/RmlUi/Source/Core/DecoratorNinePatch.h new file mode 100644 index 000000000..592d23cc6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorNinePatch.h @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORNINEPATCH_H +#define RMLUI_CORE_DECORATORNINEPATCH_H + +#include "../../Include/RmlUi/Core/Decorator.h" +#include "../../Include/RmlUi/Core/DecoratorInstancer.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Spritesheet.h" + +namespace Rml { + +class DecoratorNinePatch : public Decorator +{ +public: + DecoratorNinePatch(); + virtual ~DecoratorNinePatch(); + + bool Initialise(const Rectangle& rect_outer, const Rectangle& rect_inner, const Array* _edges, const Texture& texture); + + DecoratorDataHandle GenerateElementData(Element* element) const override; + void ReleaseElementData(DecoratorDataHandle element_data) const override; + + void RenderElement(Element* element, DecoratorDataHandle element_data) const override; + +private: + Rectangle rect_outer, rect_inner; + UniquePtr> edges; +}; + + + +class DecoratorNinePatchInstancer : public DecoratorInstancer +{ +public: + DecoratorNinePatchInstancer(); + ~DecoratorNinePatchInstancer(); + + SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) override; + +private: + PropertyId sprite_outer_id, sprite_inner_id; + PropertyId edge_ids[4]; + +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiled.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiled.cpp new file mode 100644 index 000000000..e4b7ae889 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiled.cpp @@ -0,0 +1,248 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiled.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Math.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include + +namespace Rml { + +DecoratorTiled::DecoratorTiled() +{ +} + +DecoratorTiled::~DecoratorTiled() +{ +} + +static const Vector2f oriented_texcoords[4][2] = { + {Vector2f(0, 0), Vector2f(1, 1)}, // ORIENTATION_NONE + {Vector2f(1, 0), Vector2f(0, 1)}, // FLIP_HORIZONTAL + {Vector2f(0, 1), Vector2f(1, 0)}, // FLIP_VERTICAL + {Vector2f(1, 1), Vector2f(0, 0)} // ROTATE_180 +}; + +DecoratorTiled::Tile::Tile() : position(0, 0), size(0, 0) +{ + texture_index = -1; + fit_mode = FILL; + orientation = ORIENTATION_NONE; +} + + +// Calculates the tile's dimensions from the texture and texture coordinates. +void DecoratorTiled::Tile::CalculateDimensions(Element* element, const Texture& texture) const +{ + RenderInterface* render_interface = element->GetRenderInterface(); + auto data_iterator = data.find(render_interface); + if (data_iterator == data.end()) + { + TileData new_data; + const Vector2i texture_dimensions_i = texture.GetDimensions(render_interface); + const Vector2f texture_dimensions((float)texture_dimensions_i.x, (float)texture_dimensions_i.y); + + if (texture_dimensions.x == 0 || texture_dimensions.y == 0) + { + new_data.size = Vector2f(0, 0); + new_data.texcoords[0] = Vector2f(0, 0); + new_data.texcoords[1] = Vector2f(0, 0); + } + else + { + // Need to scale the coordinates to normalized units and 'size' to absolute size (pixels) + if (size.x == 0 && size.y == 0 && position.x == 0 && position.y == 0) + new_data.size = texture_dimensions; + else + new_data.size = size; + + Vector2f size_relative = new_data.size / texture_dimensions; + + new_data.size = Vector2f(Math::AbsoluteValue(new_data.size.x), Math::AbsoluteValue(new_data.size.y)); + + new_data.texcoords[0] = position / texture_dimensions; + new_data.texcoords[1] = size_relative + new_data.texcoords[0]; + } + + data.emplace( render_interface, new_data ); + } +} + +// Get this tile's dimensions. +Vector2f DecoratorTiled::Tile::GetDimensions(Element* element) const +{ + RenderInterface* render_interface = element->GetRenderInterface(); + auto data_iterator = data.find(render_interface); + if (data_iterator == data.end()) + return Vector2f(0, 0); + + return data_iterator->second.size; +} + +// Generates geometry to render this tile across a surface. +void DecoratorTiled::Tile::GenerateGeometry(Vector< Vertex >& vertices, Vector< int >& indices, Element* element, const Vector2f& surface_origin, const Vector2f& surface_dimensions, const Vector2f& tile_dimensions) const +{ + if (surface_dimensions.x <= 0 || surface_dimensions.y <= 0) + return; + + RenderInterface* render_interface = element->GetRenderInterface(); + const auto& computed = element->GetComputedValues(); + + float opacity = computed.opacity; + Colourb quad_colour = computed.image_color; + + // Apply opacity + quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha); + + auto data_iterator = data.find(render_interface); + if (data_iterator == data.end()) + return; + + const TileData& data = data_iterator->second; + + // Generate the oriented texture coordinates for the tiles. + Vector2f scaled_texcoords[2]; + for (int i = 0; i < 2; i++) + { + scaled_texcoords[i] = data.texcoords[0] + oriented_texcoords[orientation][i] * (data.texcoords[1] - data.texcoords[0]); + } + + Vector2f final_tile_dimensions; + bool offset_and_clip_tile = false; + + switch (fit_mode) + { + case FILL: + { + final_tile_dimensions = surface_dimensions; + } + break; + case CONTAIN: + { + Vector2f scale_factor = surface_dimensions / tile_dimensions; + float min_factor = std::min(scale_factor.x, scale_factor.y); + final_tile_dimensions = tile_dimensions * min_factor; + + offset_and_clip_tile = true; + } + break; + case COVER: + { + Vector2f scale_factor = surface_dimensions / tile_dimensions; + float max_factor = std::max(scale_factor.x, scale_factor.y); + final_tile_dimensions = tile_dimensions * max_factor; + + offset_and_clip_tile = true; + } + break; + case SCALE_NONE: + { + final_tile_dimensions = tile_dimensions; + + offset_and_clip_tile = true; + } + break; + case SCALE_DOWN: + { + Vector2f scale_factor = surface_dimensions / tile_dimensions; + float min_factor = std::min(scale_factor.x, scale_factor.y); + if (min_factor < 1.0f) + final_tile_dimensions = tile_dimensions * min_factor; + else + final_tile_dimensions = tile_dimensions; + + offset_and_clip_tile = true; + } + break; + } + + + Vector2f tile_offset(0, 0); + + if (offset_and_clip_tile) + { + // Offset tile along each dimension. + for(int i = 0; i < 2; i++) + { + switch (align[i].type) { + case Style::LengthPercentage::Length: tile_offset[i] = align[i].value; break; + case Style::LengthPercentage::Percentage: tile_offset[i] = (surface_dimensions[i] - final_tile_dimensions[i]) * align[i].value * 0.01f; break; + } + } + tile_offset = tile_offset.Round(); + + // Clip tile. See if our tile extends outside the boundary at either side, along each dimension. + for(int i = 0; i < 2; i++) + { + // Left/right acts as top/bottom during the second iteration. + float overshoot_left = std::max(-tile_offset[i], 0.0f); + float overshoot_right = std::max(tile_offset[i] + final_tile_dimensions[i] - surface_dimensions[i], 0.0f); + + if(overshoot_left > 0.f || overshoot_right > 0.f) + { + float& left = scaled_texcoords[0][i]; + float& right = scaled_texcoords[1][i]; + float width = right - left; + + left += overshoot_left / final_tile_dimensions[i] * width; + right -= overshoot_right / final_tile_dimensions[i] * width; + + final_tile_dimensions[i] -= overshoot_left + overshoot_right; + tile_offset[i] += overshoot_left; + } + } + } + + + // Resize the vertex and index arrays to fit the new geometry. + int index_offset = (int) vertices.size(); + vertices.resize(vertices.size() + 4); + Vertex* new_vertices = &vertices[0] + index_offset; + + size_t num_indices = indices.size(); + indices.resize(indices.size() + 6); + int* new_indices = &indices[0] + num_indices; + + // Generate the vertices for the tiled surface. + Vector2f tile_position = (surface_origin + tile_offset).Round(); + + GeometryUtilities::GenerateQuad(new_vertices, new_indices, tile_position, final_tile_dimensions.Round(), quad_colour, scaled_texcoords[0], scaled_texcoords[1], index_offset); +} + +// Scales a tile dimensions by a fixed value along one axis. +void DecoratorTiled::ScaleTileDimensions(Vector2f& tile_dimensions, float axis_value, int axis) const +{ + if (tile_dimensions[axis] != axis_value) + { + tile_dimensions[1 - axis] = tile_dimensions[1 - axis] * (axis_value / tile_dimensions[axis]); + tile_dimensions[axis] = axis_value; + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiled.h b/thirdparty/RmlUi/Source/Core/DecoratorTiled.h new file mode 100644 index 000000000..31a659be8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiled.h @@ -0,0 +1,130 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILED_H +#define RMLUI_CORE_DECORATORTILED_H + +#include "../../Include/RmlUi/Core/ComputedValues.h" +#include "../../Include/RmlUi/Core/Decorator.h" +#include "../../Include/RmlUi/Core/Vertex.h" + +namespace Rml { + +struct Texture; + +/** + Base class for tiled decorators. + + @author Peter Curry + */ + +class DecoratorTiled : public Decorator +{ +public: + DecoratorTiled(); + virtual ~DecoratorTiled(); + + /** + Stores the orientation of a tile. + */ + enum TileOrientation + { + ORIENTATION_NONE, // No orientation. + FLIP_HORIZONTAL, // Flipped horizontally. + FLIP_VERTICAL, // Flipped vertically. + ROTATE_180, // Rotated 180 degrees clockwise. + }; + /** + Stores the fit mode of a tile. + */ + enum TileFitMode + { + FILL, // Tile is stretched to boundaries. + CONTAIN, // Tile is stretched to boundaries, keeping aspect ratio fixed, 'letter-boxed'. + COVER, // Tile is stretched to cover the boundaries, keeping aspect ratio fixed. + SCALE_NONE, // Tile is never scaled. + SCALE_DOWN, // Tile acts like 'scale-none' if smaller than boundaries, or like 'contain' otherwise. + }; + + /** + Structure for storing the different tiles the tiled decorator uses internally over its + surface. + + @author Peter Curry + */ + struct Tile + { + /// Constructs the tile with safe default values. + Tile(); + + /// Calculates the tile's dimensions from the texture and texture coordinates. + void CalculateDimensions(Element* element, const Texture& texture) const; + /// Get this tile's dimensions. + Vector2f GetDimensions(Element* element) const; + + /// Generates geometry to render this tile across a surface. + /// @param[out] vertices The array to store the generated vertex data. + /// @param[out] indices The array to store the generated index data. + /// @param[in] element The element hosting the decorator. + /// @param[in] surface_origin The starting point of the first tile to generate. + /// @param[in] surface_dimensions The dimensions of the surface to be tiled. + /// @param[in] tile_dimensions The dimensions to render this tile at. + void GenerateGeometry(Vector< Vertex >& vertices, Vector< int >& indices, Element* element, const Vector2f& surface_origin, const Vector2f& surface_dimensions, const Vector2f& tile_dimensions) const; + + struct TileData + { + Vector2f size; // 'px' units + Vector2f texcoords[2]; // relative units + }; + + using TileDataMap = SmallUnorderedMap< RenderInterface*, TileData >; + + int texture_index; + + // Position and size within the texture, absolute units (px) + Vector2f position, size; + + mutable TileDataMap data; + + TileOrientation orientation; + + TileFitMode fit_mode; + Style::LengthPercentage align[2]; + + }; + +protected: + /// Scales a tile dimensions by a fixed value along one axis. + /// @param tile_dimensions[in, out] The tile dimensions to scale. + /// @param axis_value[in] The fixed value to scale against. + /// @param axis[in] The axis to scale against; either 0 (for x) or 1 (for y). + void ScaleTileDimensions(Vector2f& tile_dimensions, float axis_value, int axis) const; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledBox.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledBox.cpp new file mode 100644 index 000000000..70d009212 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledBox.cpp @@ -0,0 +1,298 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledBox.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Geometry.h" + +namespace Rml { + +struct DecoratorTiledBoxData +{ + DecoratorTiledBoxData(Element* host_element, int num_textures) : num_textures(num_textures) + { + geometry = new Geometry[num_textures]; + for (int i = 0; i < num_textures; i++) + geometry[i].SetHostElement(host_element); + } + + ~DecoratorTiledBoxData() + { + delete[] geometry; + } + + const int num_textures; + Geometry* geometry; +}; + +DecoratorTiledBox::DecoratorTiledBox() +{ +} + +DecoratorTiledBox::~DecoratorTiledBox() +{ +} + +// Initialises the tiles for the decorator. +bool DecoratorTiledBox::Initialise(const Tile* _tiles, const Texture* _textures) +{ + // Load the textures. + for (int i = 0; i < 9; i++) + { + tiles[i] = _tiles[i]; + tiles[i].texture_index = AddTexture(_textures[i]); + } + + // All corners must have a valid texture. + for (int i = TOP_LEFT_CORNER; i <= BOTTOM_RIGHT_CORNER; i++) + { + if (tiles[i].texture_index == -1) + return false; + } + // Check that the centre tile has been specified. + if (tiles[CENTRE].texture_index < 0) + return false; + + // If only one side of the left / right edges have been configured, then mirror the tile for the other side. + if (tiles[LEFT_EDGE].texture_index == -1 && tiles[RIGHT_EDGE].texture_index > -1) + { + tiles[LEFT_EDGE] = tiles[RIGHT_EDGE]; + tiles[LEFT_EDGE].orientation = FLIP_HORIZONTAL; + } + else if (tiles[RIGHT_EDGE].texture_index == -1 && tiles[LEFT_EDGE].texture_index > -1) + { + tiles[RIGHT_EDGE] = tiles[LEFT_EDGE]; + tiles[RIGHT_EDGE].orientation = FLIP_HORIZONTAL; + } + else if (tiles[LEFT_EDGE].texture_index == -1 && tiles[RIGHT_EDGE].texture_index == -1) + return false; + + // If only one side of the top / bottom edges have been configured, then mirror the tile for the other side. + if (tiles[TOP_EDGE].texture_index == -1 && tiles[BOTTOM_EDGE].texture_index > -1) + { + tiles[TOP_EDGE] = tiles[BOTTOM_EDGE]; + tiles[TOP_EDGE].orientation = FLIP_VERTICAL; + } + else if (tiles[BOTTOM_EDGE].texture_index == -1 && tiles[TOP_EDGE].texture_index > -1) + { + tiles[BOTTOM_EDGE] = tiles[TOP_EDGE]; + tiles[BOTTOM_EDGE].orientation = FLIP_VERTICAL; + } + else if (tiles[TOP_EDGE].texture_index == -1 && tiles[BOTTOM_EDGE].texture_index == -1) + return false; + + return true; +} + +// Called on a decorator to generate any required per-element data for a newly decorated element. +DecoratorDataHandle DecoratorTiledBox::GenerateElementData(Element* element) const +{ + // Initialise the tiles for this element. + for (int i = 0; i < 9; i++) + { + RMLUI_ASSERT(tiles[i].texture_index >= 0); + tiles[i].CalculateDimensions(element, *GetTexture(tiles[i].texture_index)); + } + + Vector2f padded_size = element->GetBox().GetSize(Box::PADDING); + + // Calculate the size for the top row of tiles. + Vector2f top_left_dimensions = tiles[TOP_LEFT_CORNER].GetDimensions(element); + Vector2f top_dimensions = tiles[TOP_EDGE].GetDimensions(element); + Vector2f top_right_dimensions = tiles[TOP_RIGHT_CORNER].GetDimensions(element); + + // Calculate the size for the bottom row of tiles. + Vector2f bottom_left_dimensions = tiles[BOTTOM_LEFT_CORNER].GetDimensions(element); + Vector2f bottom_dimensions = tiles[BOTTOM_EDGE].GetDimensions(element); + Vector2f bottom_right_dimensions = tiles[BOTTOM_RIGHT_CORNER].GetDimensions(element); + + // The size of the left and right tiles. + Vector2f left_dimensions = tiles[LEFT_EDGE].GetDimensions(element); + Vector2f right_dimensions = tiles[RIGHT_EDGE].GetDimensions(element); + + // Scale the top corners down if appropriate. If they are scaled, then the left and right edges are also scaled + // if they shared a width with their corner. Best solution? Don't know. + if (padded_size.x < top_left_dimensions.x + top_right_dimensions.x) + { + float minimum_width = top_left_dimensions.x + top_right_dimensions.x; + + top_left_dimensions.x = padded_size.x * (top_left_dimensions.x / minimum_width); + if (tiles[TOP_LEFT_CORNER].GetDimensions(element).x == tiles[LEFT_EDGE].GetDimensions(element).x) + left_dimensions.x = top_left_dimensions.x; + + top_right_dimensions.x = padded_size.x * (top_right_dimensions.x / minimum_width); + if (tiles[TOP_RIGHT_CORNER].GetDimensions(element).x == tiles[RIGHT_EDGE].GetDimensions(element).x) + right_dimensions.x = top_right_dimensions.x; + } + + // Scale the bottom corners down if appropriate. If they are scaled, then the left and right edges are also scaled + // if they shared a width with their corner. Best solution? Don't know. + if (padded_size.x < bottom_left_dimensions.x + bottom_right_dimensions.x) + { + float minimum_width = bottom_left_dimensions.x + bottom_right_dimensions.x; + + bottom_left_dimensions.x = padded_size.x * (bottom_left_dimensions.x / minimum_width); + if (tiles[BOTTOM_LEFT_CORNER].GetDimensions(element).x == tiles[LEFT_EDGE].GetDimensions(element).x) + left_dimensions.x = bottom_left_dimensions.x; + + bottom_right_dimensions.x = padded_size.x * (bottom_right_dimensions.x / minimum_width); + if (tiles[BOTTOM_RIGHT_CORNER].GetDimensions(element).x == tiles[RIGHT_EDGE].GetDimensions(element).x) + right_dimensions.x = bottom_right_dimensions.x; + } + + // Scale the left corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled + // if they shared a width with their corner. Best solution? Don't know. + if (padded_size.y < top_left_dimensions.y + bottom_left_dimensions.y) + { + float minimum_height = top_left_dimensions.y + bottom_left_dimensions.y; + + top_left_dimensions.y = padded_size.y * (top_left_dimensions.y / minimum_height); + if (tiles[TOP_LEFT_CORNER].GetDimensions(element).y == tiles[TOP_EDGE].GetDimensions(element).y) + top_dimensions.y = top_left_dimensions.y; + + bottom_left_dimensions.y = padded_size.y * (bottom_left_dimensions.y / minimum_height); + if (tiles[BOTTOM_LEFT_CORNER].GetDimensions(element).y == tiles[BOTTOM_EDGE].GetDimensions(element).y) + bottom_dimensions.y = bottom_left_dimensions.y; + } + + // Scale the right corners down if appropriate. If they are scaled, then the top and bottom edges are also scaled + // if they shared a width with their corner. Best solution? Don't know. + if (padded_size.y < top_right_dimensions.y + bottom_right_dimensions.y) + { + float minimum_height = top_right_dimensions.y + bottom_right_dimensions.y; + + top_right_dimensions.y = padded_size.y * (top_right_dimensions.y / minimum_height); + if (tiles[TOP_RIGHT_CORNER].GetDimensions(element).y == tiles[TOP_EDGE].GetDimensions(element).y) + top_dimensions.y = top_right_dimensions.y; + + bottom_right_dimensions.y = padded_size.y * (bottom_right_dimensions.y / minimum_height); + if (tiles[BOTTOM_RIGHT_CORNER].GetDimensions(element).y == tiles[BOTTOM_EDGE].GetDimensions(element).y) + bottom_dimensions.y = bottom_right_dimensions.y; + } + + const int num_textures = GetNumTextures(); + DecoratorTiledBoxData* data = new DecoratorTiledBoxData(element, num_textures); + + // Generate the geometry for the top-left tile. + tiles[TOP_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_LEFT_CORNER].texture_index].GetVertices(), + data->geometry[tiles[TOP_LEFT_CORNER].texture_index].GetIndices(), + element, + Vector2f(0, 0), + top_left_dimensions, + top_left_dimensions); + // Generate the geometry for the top edge tiles. + tiles[TOP_EDGE].GenerateGeometry(data->geometry[tiles[TOP_EDGE].texture_index].GetVertices(), + data->geometry[tiles[TOP_EDGE].texture_index].GetIndices(), + element, + Vector2f(top_left_dimensions.x, 0), + Vector2f(padded_size.x - (top_left_dimensions.x + top_right_dimensions.x), top_dimensions.y), + top_dimensions); + // Generate the geometry for the top-right tile. + tiles[TOP_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[TOP_RIGHT_CORNER].texture_index].GetVertices(), + data->geometry[tiles[TOP_RIGHT_CORNER].texture_index].GetIndices(), + element, + Vector2f(padded_size.x - top_right_dimensions.x, 0), + top_right_dimensions, + top_right_dimensions); + + // Generate the geometry for the left side. + tiles[LEFT_EDGE].GenerateGeometry(data->geometry[tiles[LEFT_EDGE].texture_index].GetVertices(), + data->geometry[tiles[LEFT_EDGE].texture_index].GetIndices(), + element, + Vector2f(0, top_left_dimensions.y), + Vector2f(left_dimensions.x, padded_size.y - (top_left_dimensions.y + bottom_left_dimensions.y)), + left_dimensions); + + // Generate the geometry for the right side. + tiles[RIGHT_EDGE].GenerateGeometry(data->geometry[tiles[RIGHT_EDGE].texture_index].GetVertices(), + data->geometry[tiles[RIGHT_EDGE].texture_index].GetIndices(), + element, + Vector2f((padded_size.x - right_dimensions.x), top_right_dimensions.y), + Vector2f(right_dimensions.x, padded_size.y - (top_right_dimensions.y + bottom_right_dimensions.y)), + right_dimensions); + + // Generate the geometry for the bottom-left tile. + tiles[BOTTOM_LEFT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index].GetVertices(), + data->geometry[tiles[BOTTOM_LEFT_CORNER].texture_index].GetIndices(), + element, + Vector2f(0, padded_size.y - bottom_left_dimensions.y), + bottom_left_dimensions, + bottom_left_dimensions); + // Generate the geometry for the bottom edge tiles. + tiles[BOTTOM_EDGE].GenerateGeometry(data->geometry[tiles[BOTTOM_EDGE].texture_index].GetVertices(), + data->geometry[tiles[BOTTOM_EDGE].texture_index].GetIndices(), + element, + Vector2f(bottom_left_dimensions.x, padded_size.y - bottom_dimensions.y), + Vector2f(padded_size.x - (bottom_left_dimensions.x + bottom_right_dimensions.x), bottom_dimensions.y), + bottom_dimensions); + // Generate the geometry for the bottom-right tile. + tiles[BOTTOM_RIGHT_CORNER].GenerateGeometry(data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index].GetVertices(), + data->geometry[tiles[BOTTOM_RIGHT_CORNER].texture_index].GetIndices(), + element, + Vector2f(padded_size.x - bottom_right_dimensions.x, padded_size.y - bottom_right_dimensions.y), + bottom_right_dimensions, + bottom_right_dimensions); + + // Generate the centre geometry. + Vector2f centre_dimensions = tiles[CENTRE].GetDimensions(element); + Vector2f centre_surface_dimensions(padded_size.x - (left_dimensions.x + right_dimensions.x), + padded_size.y - (top_dimensions.y + bottom_dimensions.y)); + + tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(), + data->geometry[tiles[CENTRE].texture_index].GetIndices(), + element, + Vector2f(left_dimensions.x, top_dimensions.y), + centre_surface_dimensions, + centre_dimensions); + + // Set the textures on the geometry. + const Texture* texture = nullptr; + int texture_index = 0; + while ((texture = GetTexture(texture_index)) != nullptr) + data->geometry[texture_index++].SetTexture(texture); + + return reinterpret_cast(data); +} + +// Called to release element data generated by this decorator. +void DecoratorTiledBox::ReleaseElementData(DecoratorDataHandle element_data) const +{ + delete reinterpret_cast< DecoratorTiledBoxData* >(element_data); +} + +// Called to render the decorator on an element. +void DecoratorTiledBox::RenderElement(Element* element, DecoratorDataHandle element_data) const +{ + Vector2f translation = element->GetAbsoluteOffset(Box::PADDING).Round(); + DecoratorTiledBoxData* data = reinterpret_cast< DecoratorTiledBoxData* >(element_data); + + for (int i = 0; i < data->num_textures; i++) + data->geometry[i].Render(translation); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledBox.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledBox.h new file mode 100644 index 000000000..d4cfb95cb --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledBox.h @@ -0,0 +1,78 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDBOX_H +#define RMLUI_CORE_DECORATORTILEDBOX_H + +#include "DecoratorTiled.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledBox : public DecoratorTiled +{ +public: + DecoratorTiledBox(); + virtual ~DecoratorTiledBox(); + + /// Initialises the tiles for the decorator. + /// @param[in] tiles The declaration for all eight tiles. + /// @param[in] textures The textures for the eight tiles. + /// @return True if all the tiles and textures are properly specified. + bool Initialise(const Tile* tiles, const Texture* textures); + + /// Called on a decorator to generate any required per-element data for a newly decorated element. + DecoratorDataHandle GenerateElementData(Element* element) const override; + /// Called to release element data generated by this decorator. + void ReleaseElementData(DecoratorDataHandle element_data) const override; + + /// Called to render the decorator on an element. + void RenderElement(Element* element, DecoratorDataHandle element_data) const override; + +private: + enum + { + TOP_LEFT_CORNER = 0, + TOP_RIGHT_CORNER = 1, + BOTTOM_LEFT_CORNER = 2, + BOTTOM_RIGHT_CORNER = 3, + LEFT_EDGE = 4, + RIGHT_EDGE = 5, + TOP_EDGE = 6, + BOTTOM_EDGE = 7, + CENTRE = 8 + }; + + Tile tiles[9]; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledBoxInstancer.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledBoxInstancer.cpp new file mode 100644 index 000000000..1a2d2cc15 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledBoxInstancer.cpp @@ -0,0 +1,75 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledBoxInstancer.h" +#include "DecoratorTiledBox.h" + +namespace Rml { + +DecoratorTiledBoxInstancer::DecoratorTiledBoxInstancer() : DecoratorTiledInstancer(9) +{ + RegisterTileProperty("top-left-image"); + RegisterTileProperty("top-right-image"); + RegisterTileProperty("bottom-left-image"); + RegisterTileProperty("bottom-right-image"); + + RegisterTileProperty("left-image"); + RegisterTileProperty("right-image"); + RegisterTileProperty("top-image"); + RegisterTileProperty("bottom-image"); + + RegisterTileProperty("center-image"); + + RegisterShorthand("decorator", "top-left-image, top-image, top-right-image, left-image, center-image, right-image, bottom-left-image, bottom-image, bottom-right-image", ShorthandType::RecursiveCommaSeparated); +} + +DecoratorTiledBoxInstancer::~DecoratorTiledBoxInstancer() +{ +} + +// Instances a box decorator. +SharedPtrDecoratorTiledBoxInstancer::InstanceDecorator(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) +{ + RMLUI_UNUSED(name); + + constexpr size_t num_tiles = 9; + + DecoratorTiled::Tile tiles[num_tiles]; + Texture textures[num_tiles]; + + if (!GetTileProperties(tiles, textures, num_tiles, properties, interface)) + return nullptr; + + auto decorator = MakeShared(); + if (!decorator->Initialise(tiles, textures)) + return nullptr; + + return decorator; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledBoxInstancer.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledBoxInstancer.h new file mode 100644 index 000000000..842786b71 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledBoxInstancer.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDBOXINSTANCER_H +#define RMLUI_CORE_DECORATORTILEDBOXINSTANCER_H + +#include "DecoratorTiledInstancer.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledBoxInstancer : public DecoratorTiledInstancer +{ +public: + DecoratorTiledBoxInstancer(); + ~DecoratorTiledBoxInstancer(); + + /// Instances a box decorator. + SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontal.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontal.cpp new file mode 100644 index 000000000..ce0785baf --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontal.cpp @@ -0,0 +1,157 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledHorizontal.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/Texture.h" + +namespace Rml { + +struct DecoratorTiledHorizontalData +{ + DecoratorTiledHorizontalData(Element* host_element, int num_textures) : num_textures(num_textures) + { + geometry = new Geometry[num_textures]; + for (int i = 0; i < num_textures; i++) + geometry[i].SetHostElement(host_element); + } + + ~DecoratorTiledHorizontalData() + { + delete[] geometry; + } + + const int num_textures; + Geometry* geometry; +}; + +DecoratorTiledHorizontal::DecoratorTiledHorizontal() +{ +} + +DecoratorTiledHorizontal::~DecoratorTiledHorizontal() +{ +} + +// Initialises the tiles for the decorator. +bool DecoratorTiledHorizontal::Initialise(const Tile* _tiles, const Texture* _textures) +{ + // Load the textures. + for (int i = 0; i < 3; i++) + { + tiles[i] = _tiles[i]; + tiles[i].texture_index = AddTexture(_textures[i]); + } + + // If only one side of the decorator has been configured, then mirror the texture for the other side. + if (tiles[LEFT].texture_index == -1 && tiles[RIGHT].texture_index > -1) + { + tiles[LEFT] = tiles[RIGHT]; + tiles[LEFT].orientation = FLIP_HORIZONTAL; + } + else if (tiles[RIGHT].texture_index == -1 && tiles[LEFT].texture_index > -1) + { + tiles[RIGHT] = tiles[LEFT]; + tiles[RIGHT].orientation = FLIP_HORIZONTAL; + } + else if (tiles[LEFT].texture_index == -1 && tiles[RIGHT].texture_index == -1) + return false; + + if (tiles[CENTRE].texture_index == -1) + return false; + + return true; +} + +// Called on a decorator to generate any required per-element data for a newly decorated element. +DecoratorDataHandle DecoratorTiledHorizontal::GenerateElementData(Element* element) const +{ + // Initialise the tiles for this element. + for (int i = 0; i < 3; i++) + tiles[i].CalculateDimensions(element, *(GetTexture(tiles[i].texture_index))); + + const int num_textures = GetNumTextures(); + DecoratorTiledHorizontalData* data = new DecoratorTiledHorizontalData(element, num_textures); + + Vector2f padded_size = element->GetBox().GetSize(Box::PADDING); + + Vector2f left_dimensions = tiles[LEFT].GetDimensions(element); + Vector2f right_dimensions = tiles[RIGHT].GetDimensions(element); + Vector2f centre_dimensions = tiles[CENTRE].GetDimensions(element); + + // Scale the tile sizes by the height scale. + ScaleTileDimensions(left_dimensions, padded_size.y, 1); + ScaleTileDimensions(right_dimensions, padded_size.y, 1); + ScaleTileDimensions(centre_dimensions, padded_size.y, 1); + + // Round the outer tile widths now so that we don't get gaps when rounding again in GenerateGeometry. + left_dimensions.x = Math::RoundFloat(left_dimensions.x); + right_dimensions.x = Math::RoundFloat(right_dimensions.x); + + // Shrink the x-sizes on the left and right tiles if necessary. + if (padded_size.x < left_dimensions.x + right_dimensions.x) + { + float minimum_width = left_dimensions.x + right_dimensions.x; + left_dimensions.x = padded_size.x * (left_dimensions.x / minimum_width); + right_dimensions.x = padded_size.x * (right_dimensions.x / minimum_width); + } + + // Generate the geometry for the left tile. + tiles[LEFT].GenerateGeometry(data->geometry[tiles[LEFT].texture_index].GetVertices(), data->geometry[tiles[LEFT].texture_index].GetIndices(), element, Vector2f(0, 0), left_dimensions, left_dimensions); + // Generate the geometry for the centre tiles. + tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(), data->geometry[tiles[CENTRE].texture_index].GetIndices(), element, Vector2f(left_dimensions.x, 0), Vector2f(padded_size.x - (left_dimensions.x + right_dimensions.x), centre_dimensions.y), centre_dimensions); + // Generate the geometry for the right tile. + tiles[RIGHT].GenerateGeometry(data->geometry[tiles[RIGHT].texture_index].GetVertices(), data->geometry[tiles[RIGHT].texture_index].GetIndices(), element, Vector2f(padded_size.x - right_dimensions.x, 0), right_dimensions, right_dimensions); + + // Set the textures on the geometry. + const Texture* texture = nullptr; + int texture_index = 0; + while ((texture = GetTexture(texture_index)) != nullptr) + data->geometry[texture_index++].SetTexture(texture); + + return reinterpret_cast(data); +} + +// Called to release element data generated by this decorator. +void DecoratorTiledHorizontal::ReleaseElementData(DecoratorDataHandle element_data) const +{ + delete reinterpret_cast< DecoratorTiledHorizontalData* >(element_data); +} + +// Called to render the decorator on an element. +void DecoratorTiledHorizontal::RenderElement(Element* element, DecoratorDataHandle element_data) const +{ + Vector2f translation = element->GetAbsoluteOffset(Box::PADDING).Round(); + DecoratorTiledHorizontalData* data = reinterpret_cast< DecoratorTiledHorizontalData* >(element_data); + + for (int i = 0; i < data->num_textures; i++) + data->geometry[i].Render(translation); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontal.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontal.h new file mode 100644 index 000000000..b70f1dc69 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontal.h @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDHORIZONTAL_H +#define RMLUI_CORE_DECORATORTILEDHORIZONTAL_H + +#include "DecoratorTiled.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledHorizontal : public DecoratorTiled +{ +public: + DecoratorTiledHorizontal(); + virtual ~DecoratorTiledHorizontal(); + + /// Initialises the tiles for the decorator. + /// @param[in] tiles The declaration for all three tiles. + /// @param[in] textures The textures for the three tiles. + /// @return True if all the tiles and textures are properly specified. + bool Initialise(const Tile* tiles, const Texture* textures); + + /// Called on a decorator to generate any required per-element data for a newly decorated element. + DecoratorDataHandle GenerateElementData(Element* element) const override; + /// Called to release element data generated by this decorator. + void ReleaseElementData(DecoratorDataHandle element_data) const override; + + /// Called to render the decorator on an element. + void RenderElement(Element* element, DecoratorDataHandle element_data) const override; + +private: + enum + { + LEFT = 0, + RIGHT = 1, + CENTRE = 2 + }; + + Tile tiles[3]; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontalInstancer.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontalInstancer.cpp new file mode 100644 index 000000000..170b5954c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontalInstancer.cpp @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledHorizontalInstancer.h" +#include "DecoratorTiledHorizontal.h" + +namespace Rml { + +DecoratorTiledHorizontalInstancer::DecoratorTiledHorizontalInstancer() : DecoratorTiledInstancer(3) +{ + RegisterTileProperty("left-image"); + RegisterTileProperty("right-image"); + RegisterTileProperty("center-image"); + RegisterShorthand("decorator", "left-image, center-image, right-image", ShorthandType::RecursiveCommaSeparated); +} + +DecoratorTiledHorizontalInstancer::~DecoratorTiledHorizontalInstancer() +{ +} + +SharedPtr DecoratorTiledHorizontalInstancer::InstanceDecorator(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) +{ + RMLUI_UNUSED(name); + + constexpr size_t num_tiles = 3; + + DecoratorTiled::Tile tiles[num_tiles]; + Texture textures[num_tiles]; + + if (!GetTileProperties(tiles, textures, num_tiles, properties, interface)) + return nullptr; + + auto decorator = MakeShared(); + if (!decorator->Initialise(tiles, textures)) + return nullptr; + + return decorator; +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontalInstancer.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontalInstancer.h new file mode 100644 index 000000000..afe1aa957 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledHorizontalInstancer.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDHORIZONTALINSTANCER_H +#define RMLUI_CORE_DECORATORTILEDHORIZONTALINSTANCER_H + +#include "DecoratorTiledInstancer.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledHorizontalInstancer : public DecoratorTiledInstancer +{ +public: + DecoratorTiledHorizontalInstancer(); + ~DecoratorTiledHorizontalInstancer(); + + /// Instances a horizontal decorator. + SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledImage.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledImage.cpp new file mode 100644 index 000000000..d8d3c7fd8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledImage.cpp @@ -0,0 +1,79 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledImage.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" + +namespace Rml { + +DecoratorTiledImage::DecoratorTiledImage() +{ +} + +DecoratorTiledImage::~DecoratorTiledImage() +{ +} + +bool DecoratorTiledImage::Initialise(const Tile& _tile, const Texture& _texture) +{ + tile = _tile; + tile.texture_index = AddTexture(_texture); + return (tile.texture_index >= 0); +} + +// Called on a decorator to generate any required per-element data for a newly decorated element. +DecoratorDataHandle DecoratorTiledImage::GenerateElementData(Element* element) const +{ + // Calculate the tile's dimensions for this element. + tile.CalculateDimensions(element, *GetTexture(tile.texture_index)); + + Geometry* data = new Geometry(element); + data->SetTexture(GetTexture()); + + // Generate the geometry for the tile. + tile.GenerateGeometry(data->GetVertices(), data->GetIndices(), element, Vector2f(0, 0), element->GetBox().GetSize(Box::PADDING), tile.GetDimensions(element)); + + return reinterpret_cast(data); +} + +// Called to release element data generated by this decorator. +void DecoratorTiledImage::ReleaseElementData(DecoratorDataHandle element_data) const +{ + delete reinterpret_cast< Geometry* >(element_data); +} + +// Called to render the decorator on an element. +void DecoratorTiledImage::RenderElement(Element* element, DecoratorDataHandle element_data) const +{ + Geometry* data = reinterpret_cast< Geometry* >(element_data); + data->Render(element->GetAbsoluteOffset(Box::PADDING).Round()); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledImage.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledImage.h new file mode 100644 index 000000000..d369c58b7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledImage.h @@ -0,0 +1,65 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDIMAGE_H +#define RMLUI_CORE_DECORATORTILEDIMAGE_H + +#include "DecoratorTiled.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledImage : public DecoratorTiled +{ +public: + DecoratorTiledImage(); + virtual ~DecoratorTiledImage(); + + /// Initialises the tile for the decorator. + /// @param tile[in] The declaration for the tile. + /// @param texture[in] The texture to apply to the tile. + /// @return True if the image is valid, false otherwise. + bool Initialise(const Tile& tile, const Texture& texture); + + /// Called on a decorator to generate any required per-element data for a newly decorated element. + DecoratorDataHandle GenerateElementData(Element* element) const override; + /// Called to release element data generated by this decorator. + void ReleaseElementData(DecoratorDataHandle element_data) const override; + + /// Called to render the decorator on an element. + void RenderElement(Element* element, DecoratorDataHandle element_data) const override; + +private: + Tile tile; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledImageInstancer.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledImageInstancer.cpp new file mode 100644 index 000000000..4feefda9a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledImageInstancer.cpp @@ -0,0 +1,63 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledImageInstancer.h" +#include "DecoratorTiledImage.h" + +namespace Rml { + +DecoratorTiledImageInstancer::DecoratorTiledImageInstancer() : DecoratorTiledInstancer(1) +{ + RegisterTileProperty("image", true); + RegisterShorthand("decorator", "image", ShorthandType::RecursiveRepeat); +} + +DecoratorTiledImageInstancer::~DecoratorTiledImageInstancer() +{ +} + + +SharedPtr DecoratorTiledImageInstancer::InstanceDecorator(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) +{ + RMLUI_UNUSED(name); + + DecoratorTiled::Tile tile; + Texture texture; + + if (!GetTileProperties(&tile, &texture, 1, properties, interface)) + return nullptr; + + auto decorator = MakeShared(); + + if (!decorator->Initialise(tile, texture)) + return nullptr; + + return decorator; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledImageInstancer.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledImageInstancer.h new file mode 100644 index 000000000..daa0e1d77 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledImageInstancer.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDIMAGEINSTANCER_H +#define RMLUI_CORE_DECORATORTILEDIMAGEINSTANCER_H + +#include "DecoratorTiledInstancer.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledImageInstancer : public DecoratorTiledInstancer +{ +public: + DecoratorTiledImageInstancer(); + ~DecoratorTiledImageInstancer(); + + /// Instances an image decorator. + SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledInstancer.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledInstancer.cpp new file mode 100644 index 000000000..320878109 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledInstancer.cpp @@ -0,0 +1,196 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledInstancer.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/Spritesheet.h" + +namespace Rml { + +DecoratorTiledInstancer::DecoratorTiledInstancer(size_t num_tiles) +{ + tile_property_ids.reserve(num_tiles); +} + +// Adds the property declarations for a tile. +void DecoratorTiledInstancer::RegisterTileProperty(const String& name, bool register_fit_modes) +{ + TilePropertyIds ids = {}; + + ids.src = RegisterProperty(CreateString(32, "%s-src", name.c_str()), "").AddParser("string").GetId(); + + String additional_modes; + + if (register_fit_modes) + { + String fit_name = CreateString(32, "%s-fit", name.c_str()); + ids.fit = RegisterProperty(fit_name, "fill") + .AddParser("keyword", "fill, contain, cover, scale-none, scale-down") + .GetId(); + + String align_x_name = CreateString(32, "%s-align-x", name.c_str()); + ids.align_x = RegisterProperty(align_x_name, "center") + .AddParser("keyword", "left, center, right") + .AddParser("length_percent") + .GetId(); + + String align_y_name = CreateString(32, "%s-align-y", name.c_str()); + ids.align_y = RegisterProperty(align_y_name, "center") + .AddParser("keyword", "top, center, bottom") + .AddParser("length_percent") + .GetId(); + + additional_modes += ", " + fit_name + ", " + align_x_name + ", " + align_y_name; + } + + ids.orientation = RegisterProperty(CreateString(32, "%s-orientation", name.c_str()), "none") + .AddParser("keyword", "none, flip-horizontal, flip-vertical, rotate-180") + .GetId(); + + RegisterShorthand(name, CreateString(256, ("%s-src, %s-orientation" + additional_modes).c_str(), + name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str(), name.c_str()), + ShorthandType::FallThrough); + + tile_property_ids.push_back(ids); +} + + +// Retrieves all the properties for a tile from the property dictionary. +bool DecoratorTiledInstancer::GetTileProperties(DecoratorTiled::Tile* tiles, Texture* textures, size_t num_tiles_and_textures, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) const +{ + RMLUI_ASSERT(num_tiles_and_textures == tile_property_ids.size()); + + String previous_texture_name; + Texture previous_texture; + + for(size_t i = 0; i < num_tiles_and_textures; i++) + { + const TilePropertyIds& ids = tile_property_ids[i]; + + const Property* src_property = properties.GetProperty(ids.src); + const String texture_name = src_property->Get< String >(); + + // Skip the tile if it has no source name. + // Declaring the name 'auto' is the same as an empty string. This gives an easy way to skip certain + // tiles in a shorthand since we can't always declare an empty string. + static const String auto_str = "auto"; + if (texture_name.empty() || texture_name == auto_str) + continue; + + // We are required to set default values before instancing the tile, thus, all properties should always be dereferencable. + // If the debugger captures a zero-dereference, check that all properties for every tile is set and default values are set just before instancing. + + DecoratorTiled::Tile& tile = tiles[i]; + Texture& texture = textures[i]; + + // A tile is always either a sprite or an image. + if (const Sprite * sprite = interface.GetSprite(texture_name)) + { + tile.position.x = sprite->rectangle.x; + tile.position.y = sprite->rectangle.y; + tile.size.x = sprite->rectangle.width; + tile.size.y = sprite->rectangle.height; + + texture = sprite->sprite_sheet->texture; + } + else + { + // No sprite found, we assume then that the name is an image source. + // Since the common use case is to specify the same texture for all tiles, we + // check the previous texture first before fetching from the global database. + if (texture_name == previous_texture_name) + { + texture = previous_texture; + } + else if (src_property->source) + { + texture.Set(texture_name, src_property->source->path); + previous_texture_name = texture_name; + previous_texture = texture; + } + else + { + auto& source = src_property->source; + Log::Message(Log::LT_WARNING, "Texture name '%s' is neither a valid sprite name nor a texture file. Specified in decorator at %s:%d.", texture_name.c_str(), source ? source->path.c_str() : "", source ? source->line_number : -1); + return false; + } + } + + if (ids.fit != PropertyId::Invalid) + { + RMLUI_ASSERT(ids.align_x != PropertyId::Invalid && ids.align_y != PropertyId::Invalid); + const Property& fit_property = *properties.GetProperty(ids.fit); + tile.fit_mode = (DecoratorTiled::TileFitMode)fit_property.value.Get< int >(); + + const Property* align_properties[2] = { + properties.GetProperty(ids.align_x), + properties.GetProperty(ids.align_y) + }; + + for (int dimension = 0; dimension < 2; dimension++) + { + using Style::LengthPercentage; + + LengthPercentage& align = tile.align[dimension]; + const Property& property = *align_properties[dimension]; + if (property.unit == Property::KEYWORD) + { + enum { TOP_LEFT, CENTER, BOTTOM_RIGHT }; + switch (property.Get()) + { + case TOP_LEFT: align = LengthPercentage(LengthPercentage::Percentage, 0.0f); break; + case CENTER: align = LengthPercentage(LengthPercentage::Percentage, 50.0f); break; + case BOTTOM_RIGHT: align = LengthPercentage(LengthPercentage::Percentage, 100.0f); break; + } + } + else if (property.unit == Property::PERCENT) + { + align = LengthPercentage(LengthPercentage::Percentage, property.Get()); + } + else if(property.unit == Property::PX) + { + align = LengthPercentage(LengthPercentage::Length, property.Get()); + } + else + { + Log::Message(Log::LT_WARNING, "Decorator alignment value is '%s' which uses an unsupported unit (use px, %%, or keyword)", property.ToString().c_str()); + } + } + } + + if (ids.orientation != PropertyId::Invalid) + { + const Property& orientation_property = *properties.GetProperty(ids.orientation); + tile.orientation = (DecoratorTiled::TileOrientation)orientation_property.value.Get< int >(); + } + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledInstancer.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledInstancer.h new file mode 100644 index 000000000..2341f446d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledInstancer.h @@ -0,0 +1,71 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDINSTANCER_H +#define RMLUI_CORE_DECORATORTILEDINSTANCER_H + +#include "../../Include/RmlUi/Core/DecoratorInstancer.h" +#include "DecoratorTiled.h" + +namespace Rml { + +class StyleSheet; + +/** + @author Peter Curry + */ + + +class DecoratorTiledInstancer : public DecoratorInstancer +{ +public: + DecoratorTiledInstancer(size_t num_tiles); + +protected: + /// Adds the property declarations for a tile. + /// @param[in] name The name of the tile property. + /// @param[in] register_fit_modes If true, the tile will have the fit modes registered. + void RegisterTileProperty(const String& name, bool register_fit_modes = false); + + /// Retrieves all the properties for a tile from the property dictionary. + /// @param[out] tile The tile structure for storing the tile properties. + /// @param[out] textures Holds the textures declared for the tile. + /// @param[in] properties The user-defined list of parameters for the decorator. + /// @param[in] interface An interface for querying the active style sheet. + bool GetTileProperties(DecoratorTiled::Tile* tiles, Texture* textures, size_t num_tiles_and_textures, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) const; + +private: + struct TilePropertyIds { + PropertyId src, fit, align_x, align_y, orientation; + }; + + Vector tile_property_ids; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledVertical.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledVertical.cpp new file mode 100644 index 000000000..fdaeba686 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledVertical.cpp @@ -0,0 +1,158 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledVertical.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../Include/RmlUi/Core/Texture.h" + +namespace Rml { + +struct DecoratorTiledVerticalData +{ + DecoratorTiledVerticalData(Element* host_element, int num_textures) : num_textures(num_textures) + { + geometry = new Geometry[num_textures]; + for (int i = 0; i < num_textures; i++) + geometry[i].SetHostElement(host_element); + } + + ~DecoratorTiledVerticalData() + { + delete[] geometry; + } + + const int num_textures; + Geometry* geometry; +}; + +DecoratorTiledVertical::DecoratorTiledVertical() +{ +} + +DecoratorTiledVertical::~DecoratorTiledVertical() +{ +} + +// Initialises the tiles for the decorator. +bool DecoratorTiledVertical::Initialise(const Tile* _tiles, const Texture* _textures) +{ + // Load the textures. + for (int i = 0; i < 3; i++) + { + tiles[i] = _tiles[i]; + tiles[i].texture_index = AddTexture(_textures[i]); + } + + // If only one side of the decorator has been configured, then mirror the texture for the other side. + if (tiles[TOP].texture_index == -1 && tiles[BOTTOM].texture_index > -1) + { + tiles[TOP] = tiles[BOTTOM]; + tiles[TOP].orientation = FLIP_HORIZONTAL; + } + else if (tiles[BOTTOM].texture_index == -1 && tiles[TOP].texture_index > -1) + { + tiles[BOTTOM] = tiles[TOP]; + tiles[BOTTOM].orientation = FLIP_HORIZONTAL; + } + else if (tiles[TOP].texture_index == -1 && tiles[BOTTOM].texture_index == -1) + return false; + + if (tiles[CENTRE].texture_index == -1) + return false; + + return true; +} + +// Called on a decorator to generate any required per-element data for a newly decorated element. +DecoratorDataHandle DecoratorTiledVertical::GenerateElementData(Element* element) const +{ + // Initialise the tile for this element. + for (int i = 0; i < 3; i++) + tiles[i].CalculateDimensions(element, *GetTexture(tiles[i].texture_index)); + + const int num_textures = GetNumTextures(); + DecoratorTiledVerticalData* data = new DecoratorTiledVerticalData(element, num_textures); + + Vector2f padded_size = element->GetBox().GetSize(Box::PADDING); + + Vector2f top_dimensions = tiles[TOP].GetDimensions(element); + Vector2f bottom_dimensions = tiles[BOTTOM].GetDimensions(element); + Vector2f centre_dimensions = tiles[CENTRE].GetDimensions(element); + + // Scale the tile sizes by the width scale. + ScaleTileDimensions(top_dimensions, padded_size.x, 0); + ScaleTileDimensions(bottom_dimensions, padded_size.x, 0); + ScaleTileDimensions(centre_dimensions, padded_size.x, 0); + + // Round the outer tile heights now so that we don't get gaps when rounding again in GenerateGeometry. + top_dimensions.y = Math::RoundFloat(top_dimensions.y); + bottom_dimensions.y = Math::RoundFloat(bottom_dimensions.y); + + // Shrink the y-sizes on the left and right tiles if necessary. + if (padded_size.y < top_dimensions.y + bottom_dimensions.y) + { + float minimum_height = top_dimensions.y + bottom_dimensions.y; + top_dimensions.y = padded_size.y * (top_dimensions.y / minimum_height); + bottom_dimensions.y = padded_size.y * (bottom_dimensions.y / minimum_height); + } + + // Generate the geometry for the left tile. + tiles[TOP].GenerateGeometry(data->geometry[tiles[TOP].texture_index].GetVertices(), data->geometry[tiles[TOP].texture_index].GetIndices(), element, Vector2f(0, 0), top_dimensions, top_dimensions); + // Generate the geometry for the centre tiles. + tiles[CENTRE].GenerateGeometry(data->geometry[tiles[CENTRE].texture_index].GetVertices(), data->geometry[tiles[CENTRE].texture_index].GetIndices(), element, Vector2f(0, top_dimensions.y), Vector2f(centre_dimensions.x, padded_size.y - (top_dimensions.y + bottom_dimensions.y)), centre_dimensions); + // Generate the geometry for the right tile. + tiles[BOTTOM].GenerateGeometry(data->geometry[tiles[BOTTOM].texture_index].GetVertices(), data->geometry[tiles[BOTTOM].texture_index].GetIndices(), element, Vector2f(0, padded_size.y - bottom_dimensions.y), bottom_dimensions, bottom_dimensions); + + // Set the textures on the geometry. + const Texture* texture = nullptr; + int texture_index = 0; + while ((texture = GetTexture(texture_index)) != nullptr) + data->geometry[texture_index++].SetTexture(texture); + + return reinterpret_cast(data); +} + +// Called to release element data generated by this decorator. +void DecoratorTiledVertical::ReleaseElementData(DecoratorDataHandle element_data) const +{ + delete reinterpret_cast< DecoratorTiledVerticalData* >(element_data); +} + +// Called to render the decorator on an element. +void DecoratorTiledVertical::RenderElement(Element* element, DecoratorDataHandle element_data) const +{ + Vector2f translation = element->GetAbsoluteOffset(Box::PADDING).Round(); + DecoratorTiledVerticalData* data = reinterpret_cast< DecoratorTiledVerticalData* >(element_data); + + for (int i = 0; i < data->num_textures; i++) + data->geometry[i].Render(translation); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledVertical.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledVertical.h new file mode 100644 index 000000000..e74abe4b7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledVertical.h @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDVERTICAL_H +#define RMLUI_CORE_DECORATORTILEDVERTICAL_H + +#include "DecoratorTiled.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledVertical : public DecoratorTiled +{ +public: + DecoratorTiledVertical(); + virtual ~DecoratorTiledVertical(); + + /// Initialises the tiles for the decorator. + /// @param[in] tiles The declaration for all three tiles. + /// @param[in] textures The textures for the three tiles. + /// @return True if all the tiles and textures are properly specified. + bool Initialise(const Tile* tiles, const Texture* textures); + + /// Called on a decorator to generate any required per-element data for a newly decorated element. + DecoratorDataHandle GenerateElementData(Element* element) const override; + /// Called to release element data generated by this decorator. + void ReleaseElementData(DecoratorDataHandle element_data) const override; + + /// Called to render the decorator on an element. + void RenderElement(Element* element, DecoratorDataHandle element_data) const override; + +private: + enum + { + TOP = 0, + BOTTOM = 1, + CENTRE = 2 + }; + + Tile tiles[3]; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledVerticalInstancer.cpp b/thirdparty/RmlUi/Source/Core/DecoratorTiledVerticalInstancer.cpp new file mode 100644 index 000000000..02bc1862f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledVerticalInstancer.cpp @@ -0,0 +1,65 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DecoratorTiledVertical.h" +#include "DecoratorTiledVerticalInstancer.h" + +namespace Rml { + +DecoratorTiledVerticalInstancer::DecoratorTiledVerticalInstancer() : DecoratorTiledInstancer(3) +{ + RegisterTileProperty("top-image"); + RegisterTileProperty("bottom-image"); + RegisterTileProperty("center-image"); + RegisterShorthand("decorator", "top-image, center-image, bottom-image", ShorthandType::RecursiveCommaSeparated); +} + +DecoratorTiledVerticalInstancer::~DecoratorTiledVerticalInstancer() +{ +} + +SharedPtr DecoratorTiledVerticalInstancer::InstanceDecorator(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) +{ + RMLUI_UNUSED(name); + + constexpr size_t num_tiles = 3; + + DecoratorTiled::Tile tiles[num_tiles]; + Texture textures[num_tiles]; + + if (!GetTileProperties(tiles, textures, num_tiles, properties, interface)) + return nullptr; + + auto decorator = MakeShared(); + if (!decorator->Initialise(tiles, textures)) + return nullptr; + + return decorator; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DecoratorTiledVerticalInstancer.h b/thirdparty/RmlUi/Source/Core/DecoratorTiledVerticalInstancer.h new file mode 100644 index 000000000..3827ca928 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DecoratorTiledVerticalInstancer.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DECORATORTILEDVERTICALINSTANCER_H +#define RMLUI_CORE_DECORATORTILEDVERTICALINSTANCER_H + +#include "DecoratorTiledInstancer.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class DecoratorTiledVerticalInstancer : public DecoratorTiledInstancer +{ +public: + DecoratorTiledVerticalInstancer(); + ~DecoratorTiledVerticalInstancer(); + + /// Instances a vertical decorator. + SharedPtr InstanceDecorator(const String& name, const PropertyDictionary& properties, const DecoratorInstancerInterface& interface) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/DocumentHeader.cpp b/thirdparty/RmlUi/Source/Core/DocumentHeader.cpp new file mode 100644 index 000000000..8e7bab11c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DocumentHeader.cpp @@ -0,0 +1,68 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DocumentHeader.h" +#include "XMLParseTools.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" + +namespace Rml { + +void DocumentHeader::MergeHeader(const DocumentHeader& header) +{ + // Copy the title across if ours is empty + if (title.empty()) + title = header.title; + // Copy the url across if ours is empty + if (source.empty()) + source = header.source; + + // Combine internal data + rcss_inline.insert(rcss_inline.end(), header.rcss_inline.begin(), header.rcss_inline.end()); + rcss_inline_line_numbers.insert(rcss_inline_line_numbers.end(), header.rcss_inline_line_numbers.begin(), header.rcss_inline_line_numbers.end()); + scripts_inline.insert(scripts_inline.end(), header.scripts_inline.begin(), header.scripts_inline.end()); + + // Combine external data, keeping relative paths + MergePaths(template_resources, header.template_resources, header.source); + MergePaths(rcss_external, header.rcss_external, header.source); + MergePaths(scripts_external, header.scripts_external, header.source); +} + +void DocumentHeader::MergePaths(StringList& target, const StringList& source, const String& source_path) +{ + for (size_t i = 0; i < source.size(); i++) + { + String joined_path; + ::Rml::GetSystemInterface()->JoinPath(joined_path, StringUtilities::Replace(source_path, '|', ':'), StringUtilities::Replace(source[i], '|', ':')); + + target.push_back(StringUtilities::Replace(joined_path, ':', '|')); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/DocumentHeader.h b/thirdparty/RmlUi/Source/Core/DocumentHeader.h new file mode 100644 index 000000000..b20b424a0 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/DocumentHeader.h @@ -0,0 +1,75 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_DOCUMENTHEADER_H +#define RMLUI_CORE_DOCUMENTHEADER_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +using LineNumberList = Vector; + +/** + The document header struct contains the + header details gathered from an XML document parse. + + @author Lloyd Weehuizen + */ + +class DocumentHeader +{ +public: + /// Path and filename this document was loaded from + String source; + /// The title of the document + String title; + /// A list of template resources that can used while parsing the document + StringList template_resources; + + /// Inline RCSS definitions + StringList rcss_inline; + LineNumberList rcss_inline_line_numbers; + /// External RCSS definitions that should be loaded + StringList rcss_external; + + /// Inline script source + StringList scripts_inline; + /// External scripts that should be loaded + StringList scripts_external; + + /// Merges the specified header with this one + /// @param header Header to merge + void MergeHeader(const DocumentHeader& header); + + /// Merges paths from one string list to another, preserving the base_path + void MergePaths(StringList& target, const StringList& source, const String& base_path); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Element.cpp b/thirdparty/RmlUi/Source/Core/Element.cpp new file mode 100644 index 000000000..550e21624 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Element.cpp @@ -0,0 +1,2714 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/ElementInstancer.h" +#include "../../Include/RmlUi/Core/ElementScroll.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Dictionary.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../Include/RmlUi/Core/PropertiesIteratorView.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" +#include "Clock.h" +#include "ComputeProperty.h" +#include "ElementAnimation.h" +#include "ElementBackground.h" +#include "ElementBorder.h" +#include "ElementDefinition.h" +#include "ElementStyle.h" +#include "EventDispatcher.h" +#include "EventSpecification.h" +#include "ElementDecoration.h" +#include "LayoutEngine.h" +#include "PluginRegistry.h" +#include "PropertiesIterator.h" +#include "Pool.h" +#include "StyleSheetParser.h" +#include "StyleSheetNode.h" +#include "TransformState.h" +#include "TransformUtilities.h" +#include "XMLParseTools.h" +#include +#include + +namespace Rml { + +/** + STL function object for sorting elements by z-type (ie, float-types before general types, etc). + @author Peter Curry + */ +class ElementSortZOrder +{ +public: + bool operator()(const Pair< Element*, float >& lhs, const Pair< Element*, float >& rhs) const + { + return lhs.second < rhs.second; + } +}; + +/** + STL function object for sorting elements by z-index property. + @author Peter Curry + */ +class ElementSortZIndex +{ +public: + bool operator()(const Element* lhs, const Element* rhs) const + { + // Check the z-index. + return lhs->GetZIndex() < rhs->GetZIndex(); + } +}; + +// Determines how many levels up in the hierarchy the OnChildAdd and OnChildRemove are called (starting at the child itself) +static constexpr int ChildNotifyLevels = 2; + +// Meta objects for element collected in a single struct to reduce memory allocations +struct ElementMeta +{ + ElementMeta(Element* el) : event_dispatcher(el), style(el), background(el), border(el), decoration(el), scroll(el) {} + EventDispatcher event_dispatcher; + ElementStyle style; + ElementBackground background; + ElementBorder border; + ElementDecoration decoration; + ElementScroll scroll; + Style::ComputedValues computed_values; +}; + + +static Pool< ElementMeta > element_meta_chunk_pool(200, true); + + +/// Constructs a new RmlUi element. +Element::Element(const String& tag) : tag(tag), relative_offset_base(0, 0), relative_offset_position(0, 0), absolute_offset(0, 0), scroll_offset(0, 0), content_offset(0, 0), content_box(0, 0), +transform_state(), dirty_transform(false), dirty_perspective(false), dirty_animation(false), dirty_transition(false) +{ + RMLUI_ASSERT(tag == StringUtilities::ToLower(tag)); + parent = nullptr; + focus = nullptr; + instancer = nullptr; + owner_document = nullptr; + + offset_fixed = false; + offset_parent = nullptr; + offset_dirty = true; + + client_area = Box::PADDING; + + num_non_dom_children = 0; + + visible = true; + + z_index = 0; + + local_stacking_context = false; + local_stacking_context_forced = false; + stacking_context_dirty = false; + + structure_dirty = false; + + computed_values_are_default_initialized = true; + + clipping_ignore_depth = 0; + clipping_enabled = false; + clipping_state_dirty = true; + + meta = element_meta_chunk_pool.AllocateAndConstruct(this); + data_model = nullptr; +} + +Element::~Element() +{ + RMLUI_ASSERT(parent == nullptr); + + PluginRegistry::NotifyElementDestroy(this); + + // Remove scrollbar elements before we delete the children! + meta->scroll.ClearScrollbars(); + + // A simplified version of RemoveChild() for destruction. + for (ElementPtr& child : children) + { + Element* child_ancestor = child.get(); + for (int i = 0; i <= ChildNotifyLevels && child_ancestor; i++, child_ancestor = child_ancestor->GetParentNode()) + child_ancestor->OnChildRemove(child.get()); + + child->SetParent(nullptr); + } + + children.clear(); + num_non_dom_children = 0; + + element_meta_chunk_pool.DestroyAndDeallocate(meta); +} + +void Element::Update(float dp_ratio) +{ +#ifdef RMLUI_ENABLE_PROFILING + auto name = GetAddress(false, false); + RMLUI_ZoneScoped; + RMLUI_ZoneText(name.c_str(), name.size()); +#endif + + OnUpdate(); + + UpdateStructure(); + + HandleTransitionProperty(); + HandleAnimationProperty(); + AdvanceAnimations(); + + meta->scroll.Update(); + + UpdateProperties(); + + // Do en extra pass over the animations and properties if the 'animation' property was just changed. + if (dirty_animation) + { + HandleAnimationProperty(); + AdvanceAnimations(); + UpdateProperties(); + } + + for (size_t i = 0; i < children.size(); i++) + children[i]->Update(dp_ratio); +} + + +void Element::UpdateProperties() +{ + meta->style.UpdateDefinition(); + + if (meta->style.AnyPropertiesDirty()) + { + const ComputedValues* parent_values = nullptr; + if (parent) + parent_values = &parent->GetComputedValues(); + + const ComputedValues* document_values = nullptr; + float dp_ratio = 1.0f; + if (auto doc = GetOwnerDocument()) + { + document_values = &doc->GetComputedValues(); + if (Context * context = doc->GetContext()) + dp_ratio = context->GetDensityIndependentPixelRatio(); + } + + // Compute values and clear dirty properties + PropertyIdSet dirty_properties = meta->style.ComputeValues(meta->computed_values, parent_values, document_values, computed_values_are_default_initialized, dp_ratio); + + computed_values_are_default_initialized = false; + + // Computed values are just calculated and can safely be used in OnPropertyChange. + // However, new properties set during this call will not be available until the next update loop. + if (!dirty_properties.Empty()) + OnPropertyChange(dirty_properties); + } +} + +void Element::Render() +{ +#ifdef RMLUI_ENABLE_PROFILING + auto name = GetAddress(false, false); + RMLUI_ZoneScoped; + RMLUI_ZoneText(name.c_str(), name.size()); +#endif + + // Rebuild our stacking context if necessary. + if (stacking_context_dirty) + BuildLocalStackingContext(); + + UpdateTransformState(); + + // Render all elements in our local stacking context that have a z-index beneath our local index of 0. + size_t i = 0; + for (; i < stacking_context.size() && stacking_context[i]->z_index < 0; ++i) + stacking_context[i]->Render(); + + // Apply our transform + ElementUtilities::ApplyTransform(*this); + + // Set up the clipping region for this element. + if (ElementUtilities::SetClippingRegion(this)) + { + meta->background.RenderBackground(); + meta->border.RenderBorder(); + meta->decoration.RenderDecorators(); + + { + RMLUI_ZoneScopedNC("OnRender", 0x228B22); + + OnRender(); + } + } + + // Render the rest of the elements in the stacking context. + for (; i < stacking_context.size(); ++i) + stacking_context[i]->Render(); +} + +// Clones this element, returning a new, unparented element. +ElementPtr Element::Clone() const +{ + ElementPtr clone; + + if (instancer) + { + clone = instancer->InstanceElement(nullptr, GetTagName(), attributes); + if (clone) + clone->SetInstancer(instancer); + } + else + clone = Factory::InstanceElement(nullptr, GetTagName(), GetTagName(), attributes); + + if (clone != nullptr) + { + String inner_rml; + GetInnerRML(inner_rml); + + clone->SetInnerRML(inner_rml); + } + + return clone; +} + +// Sets or removes a class on the element. +void Element::SetClass(const String& class_name, bool activate) +{ + meta->style.SetClass(class_name, activate); +} + +// Checks if a class is set on the element. +bool Element::IsClassSet(const String& class_name) const +{ + return meta->style.IsClassSet(class_name); +} + +// Specifies the entire list of classes for this element. This will replace any others specified. +void Element::SetClassNames(const String& class_names) +{ + SetAttribute("class", class_names); +} + +/// Return the active class list +String Element::GetClassNames() const +{ + return meta->style.GetClassNames(); +} + +// Returns the active style sheet for this element. This may be nullptr. +const SharedPtr& Element::GetStyleSheet() const +{ + if (ElementDocument * document = GetOwnerDocument()) + return document->GetStyleSheet(); + static SharedPtr null_style_sheet; + return null_style_sheet; +} + +// Returns the element's definition. +const ElementDefinition* Element::GetDefinition() +{ + return meta->style.GetDefinition(); +} + +// Fills an String with the full address of this element. +String Element::GetAddress(bool include_pseudo_classes, bool include_parents) const +{ + // Add the tag name onto the address. + String address(tag); + + // Add the ID if we have one. + if (!id.empty()) + { + address += "#"; + address += id; + } + + String classes = meta->style.GetClassNames(); + if (!classes.empty()) + { + classes = StringUtilities::Replace(classes, ' ', '.'); + address += "."; + address += classes; + } + + if (include_pseudo_classes) + { + const PseudoClassList& pseudo_classes = meta->style.GetActivePseudoClasses(); + for (PseudoClassList::const_iterator i = pseudo_classes.begin(); i != pseudo_classes.end(); ++i) + { + address += ":"; + address += (*i); + } + } + + if (include_parents && parent) + { + address += " < "; + return address + parent->GetAddress(include_pseudo_classes, true); + } + else + return address; +} + +// Sets the position of this element, as a two-dimensional offset from another element. +void Element::SetOffset(const Vector2f& offset, Element* _offset_parent, bool _offset_fixed) +{ + _offset_fixed |= GetPosition() == Style::Position::Fixed; + + // If our offset has definitely changed, or any of our parenting has, then these are set and + // updated based on our left / right / top / bottom properties. + if (relative_offset_base != offset || + offset_parent != _offset_parent || + offset_fixed != _offset_fixed) + { + relative_offset_base = offset; + offset_fixed = _offset_fixed; + offset_parent = _offset_parent; + UpdateOffset(); + DirtyOffset(); + } + + // Otherwise, our offset is updated in case left / right / top / bottom will have an impact on + // our final position, and our children are dirtied if they do. + else + { + Vector2f& old_base = relative_offset_base; + Vector2f& old_position = relative_offset_position; + + UpdateOffset(); + + if (old_base != relative_offset_base || + old_position != relative_offset_position) + DirtyOffset(); + } +} + +// Returns the position of the top-left corner of one of the areas of this element's primary box. +Vector2f Element::GetRelativeOffset(Box::Area area) +{ + return relative_offset_base + relative_offset_position + GetBox().GetPosition(area); +} + +// Returns the position of the top-left corner of one of the areas of this element's primary box. +Vector2f Element::GetAbsoluteOffset(Box::Area area) +{ + if (offset_dirty) + { + offset_dirty = false; + + if (offset_parent != nullptr) + absolute_offset = offset_parent->GetAbsoluteOffset(Box::BORDER) + relative_offset_base + relative_offset_position; + else + absolute_offset = relative_offset_base + relative_offset_position; + + // Add any parent scrolling onto our position as well. Could cache this if required. + if (!offset_fixed) + { + Element* scroll_parent = parent; + while (scroll_parent != nullptr) + { + absolute_offset -= (scroll_parent->scroll_offset + scroll_parent->content_offset); + if (scroll_parent == offset_parent) + break; + else + scroll_parent = scroll_parent->parent; + } + } + } + + return absolute_offset + GetBox().GetPosition(area); +} + +// Sets an alternate area to use as the client area. +void Element::SetClientArea(Box::Area _client_area) +{ + client_area = _client_area; +} + +// Returns the area the element uses as its client area. +Box::Area Element::GetClientArea() const +{ + return client_area; +} + +// Sets the dimensions of the element's internal content. +void Element::SetContentBox(const Vector2f& _content_offset, const Vector2f& _content_box) +{ + if (content_offset != _content_offset || + content_box != _content_box) + { + // Seems to be jittering a wee bit; might need to be looked at. + scroll_offset.x += (content_offset.x - _content_offset.x); + scroll_offset.y += (content_offset.y - _content_offset.y); + + content_offset = _content_offset; + content_box = _content_box; + + scroll_offset.x = Math::Min(scroll_offset.x, GetScrollWidth() - GetClientWidth()); + scroll_offset.y = Math::Min(scroll_offset.y, GetScrollHeight() - GetClientHeight()); + DirtyOffset(); + } +} + +// Sets the box describing the size of the element. +void Element::SetBox(const Box& box) +{ + if (box != main_box || additional_boxes.size() > 0) + { + main_box = box; + additional_boxes.clear(); + + OnResize(); + + meta->background.DirtyBackground(); + meta->border.DirtyBorder(); + meta->decoration.DirtyDecorators(); + } +} + +// Adds a box to the end of the list describing this element's geometry. +void Element::AddBox(const Box& box) +{ + additional_boxes.push_back(box); + + OnResize(); + + meta->background.DirtyBackground(); + meta->border.DirtyBorder(); + meta->decoration.DirtyDecorators(); +} + +// Returns one of the boxes describing the size of the element. +const Box& Element::GetBox() +{ + return main_box; +} + +// Returns one of the boxes describing the size of the element. +const Box& Element::GetBox(int index) +{ + if (index < 1) + return main_box; + + int additional_box_index = index - 1; + if (additional_box_index >= (int)additional_boxes.size()) + return main_box; + + return additional_boxes[additional_box_index]; +} + +// Returns the number of boxes making up this element's geometry. +int Element::GetNumBoxes() +{ + return 1 + (int)additional_boxes.size(); +} + +// Returns the baseline of the element, in pixels offset from the bottom of the element's content area. +float Element::GetBaseline() const +{ + return 0; +} + +// Gets the intrinsic dimensions of this element, if it is of a type that has an inherent size. +bool Element::GetIntrinsicDimensions(Vector2f& RMLUI_UNUSED_PARAMETER(dimensions)) +{ + RMLUI_UNUSED(dimensions); + + return false; +} + +// Checks if a given point in screen coordinates lies within the bordered area of this element. +bool Element::IsPointWithinElement(const Vector2f& point) +{ + Vector2f position = GetAbsoluteOffset(Box::BORDER); + + for (int i = 0; i < GetNumBoxes(); ++i) + { + const Box& box = GetBox(i); + + Vector2f box_position = position + box.GetOffset(); + Vector2f box_dimensions = box.GetSize(Box::BORDER); + if (point.x >= box_position.x && + point.x <= (box_position.x + box_dimensions.x) && + point.y >= box_position.y && + point.y <= (box_position.y + box_dimensions.y)) + { + return true; + } + } + + return false; +} + +// Returns the visibility of the element. +bool Element::IsVisible() const +{ + return visible; +} + +// Returns the z-index of the element. +float Element::GetZIndex() const +{ + return z_index; +} + +// Returns the element's font face handle. +FontFaceHandle Element::GetFontFaceHandle() const +{ + return meta->computed_values.font_face_handle; +} + +// Sets a local property override on the element. +bool Element::SetProperty(const String& name, const String& value) +{ + // The name may be a shorthand giving us multiple underlying properties + PropertyDictionary properties; + if (!StyleSheetSpecification::ParsePropertyDeclaration(properties, name, value)) + { + Log::Message(Log::LT_WARNING, "Syntax error parsing inline property declaration '%s: %s;'.", name.c_str(), value.c_str()); + return false; + } + for (auto& property : properties.GetProperties()) + { + if (!meta->style.SetProperty(property.first, property.second)) + return false; + } + return true; +} + +// Sets a local property override on the element to a pre-parsed value. +bool Element::SetProperty(PropertyId id, const Property& property) +{ + return meta->style.SetProperty(id, property); +} + +// Removes a local property override on the element. +void Element::RemoveProperty(const String& name) +{ + meta->style.RemoveProperty(StyleSheetSpecification::GetPropertyId(name)); +} + +// Removes a local property override on the element. +void Element::RemoveProperty(PropertyId id) +{ + meta->style.RemoveProperty(id); +} + +// Returns one of this element's properties. +const Property* Element::GetProperty(const String& name) +{ + return meta->style.GetProperty(StyleSheetSpecification::GetPropertyId(name)); +} + +// Returns one of this element's properties. +const Property* Element::GetProperty(PropertyId id) +{ + return meta->style.GetProperty(id); +} + +// Returns one of this element's properties. +const Property* Element::GetLocalProperty(const String& name) +{ + return meta->style.GetLocalProperty(StyleSheetSpecification::GetPropertyId(name)); +} + +const Property* Element::GetLocalProperty(PropertyId id) +{ + return meta->style.GetLocalProperty(id); +} + +const PropertyMap& Element::GetLocalStyleProperties() +{ + return meta->style.GetLocalStyleProperties(); +} + +float Element::ResolveNumericProperty(const Property *property, float base_value) +{ + return meta->style.ResolveNumericProperty(property, base_value); +} + +float Element::ResolveNumericProperty(const String& property_name) +{ + auto property = meta->style.GetProperty(StyleSheetSpecification::GetPropertyId(property_name)); + if (!property) + return 0.0f; + + if (property->unit & Property::ANGLE) + return ComputeAngle(*property); + + RelativeTarget relative_target = RelativeTarget::None; + if (property->definition) + relative_target = property->definition->GetRelativeTarget(); + + float result = meta->style.ResolveLength(property, relative_target); + + return result; +} + +Vector2f Element::GetContainingBlock() +{ + Vector2f containing_block(0, 0); + + if (offset_parent != nullptr) + { + using namespace Style; + Position position_property = GetPosition(); + const Box& parent_box = offset_parent->GetBox(); + + if (position_property == Position::Static || position_property == Position::Relative) + { + containing_block = parent_box.GetSize(); + } + else if(position_property == Position::Absolute || position_property == Position::Fixed) + { + containing_block = parent_box.GetSize(Box::PADDING); + } + } + + return containing_block; +} + +Style::Position Element::GetPosition() +{ + return meta->computed_values.position; +} + +Style::Float Element::GetFloat() +{ + return meta->computed_values.float_; +} + +Style::Display Element::GetDisplay() +{ + return meta->computed_values.display; +} + +float Element::GetLineHeight() +{ + return meta->computed_values.line_height.value; +} + +// Returns this element's TransformState +const TransformState *Element::GetTransformState() const noexcept +{ + return transform_state.get(); +} + +// Project a 2D point in pixel coordinates onto the element's plane. +bool Element::Project(Vector2f& point) const noexcept +{ + if(!transform_state || !transform_state->GetTransform()) + return true; + + // The input point is in window coordinates. Need to find the projection of the point onto the current element plane, + // taking into account the full transform applied to the element. + + if (const Matrix4f* inv_transform = transform_state->GetInverseTransform()) + { + // Pick two points forming a line segment perpendicular to the window. + Vector4f window_points[2] = {{ point.x, point.y, -10, 1}, { point.x, point.y, 10, 1 }}; + + // Project them into the local element space. + window_points[0] = *inv_transform * window_points[0]; + window_points[1] = *inv_transform * window_points[1]; + + Vector3f local_points[2] = { + window_points[0].PerspectiveDivide(), + window_points[1].PerspectiveDivide() + }; + + // Construct a ray from the two projected points in the local space of the current element. + // Find the intersection with the z=0 plane to produce our destination point. + Vector3f ray = local_points[1] - local_points[0]; + + // Only continue if we are not close to parallel with the plane. + if(std::fabs(ray.z) > 1.0f) + { + // Solving the line equation p = p0 + t*ray for t, knowing that p.z = 0, produces the following. + float t = -local_points[0].z / ray.z; + Vector3f p = local_points[0] + ray * t; + + point = Vector2f(p.x, p.y); + return true; + } + } + + // The transformation matrix is either singular, or the ray is parallel to the element's plane. + return false; +} + +PropertiesIteratorView Element::IterateLocalProperties() const +{ + return PropertiesIteratorView(MakeUnique(meta->style.Iterate())); +} + + +// Sets or removes a pseudo-class on the element. +void Element::SetPseudoClass(const String& pseudo_class, bool activate) +{ + meta->style.SetPseudoClass(pseudo_class, activate); +} + +// Checks if a specific pseudo-class has been set on the element. +bool Element::IsPseudoClassSet(const String& pseudo_class) const +{ + return meta->style.IsPseudoClassSet(pseudo_class); +} + +// Checks if a complete set of pseudo-classes are set on the element. +bool Element::ArePseudoClassesSet(const PseudoClassList& pseudo_classes) const +{ + for (PseudoClassList::const_iterator i = pseudo_classes.begin(); i != pseudo_classes.end(); ++i) + { + if (!IsPseudoClassSet(*i)) + return false; + } + + return true; +} + +// Gets a list of the current active pseudo classes +const PseudoClassList& Element::GetActivePseudoClasses() const +{ + return meta->style.GetActivePseudoClasses(); +} + +/// Get the named attribute +Variant* Element::GetAttribute(const String& name) +{ + return GetIf(attributes, name); +} + +// Checks if the element has a certain attribute. +bool Element::HasAttribute(const String& name) const +{ + return attributes.find(name) != attributes.end(); +} + +// Removes an attribute from the element +void Element::RemoveAttribute(const String& name) +{ + auto it = attributes.find(name); + if (it != attributes.end()) + { + attributes.erase(it); + + ElementAttributes changed_attributes; + changed_attributes.emplace(name, Variant()); + OnAttributeChange(changed_attributes); + } +} + +// Gets the outer most focus element down the tree from this node +Element* Element::GetFocusLeafNode() +{ + // If there isn't a focus, then we are the leaf. + if (!focus) + { + return this; + } + + // Recurse down the tree until we found the leaf focus element + Element* focus_element = focus; + while (focus_element->focus) + focus_element = focus_element->focus; + + return focus_element; +} + +// Returns the element's context. +Context* Element::GetContext() const +{ + ElementDocument* document = GetOwnerDocument(); + if (document != nullptr) + return document->GetContext(); + + return nullptr; +} + +// Set a group of attributes +void Element::SetAttributes(const ElementAttributes& _attributes) +{ + attributes.reserve(attributes.size() + _attributes.size()); + for (auto& pair : _attributes) + attributes[pair.first] = pair.second; + + OnAttributeChange(_attributes); +} + +// Returns the number of attributes on the element. +int Element::GetNumAttributes() const +{ + return (int)attributes.size(); +} + +// Gets the name of the element. +const String& Element::GetTagName() const +{ + return tag; +} + +// Gets the ID of the element. +const String& Element::GetId() const +{ + return id; +} + +// Sets the ID of the element. +void Element::SetId(const String& _id) +{ + SetAttribute("id", _id); +} + +// Gets the horizontal offset from the context's left edge to element's left border edge. +float Element::GetAbsoluteLeft() +{ + return GetAbsoluteOffset(Box::BORDER).x; +} + +// Gets the vertical offset from the context's top edge to element's top border edge. +float Element::GetAbsoluteTop() +{ + return GetAbsoluteOffset(Box::BORDER).y; +} + +// Gets the width of the left border of an element. +float Element::GetClientLeft() +{ + return GetBox().GetPosition(client_area).x; +} + +// Gets the height of the top border of an element. +float Element::GetClientTop() +{ + return GetBox().GetPosition(client_area).y; +} + +// Gets the inner width of the element. +float Element::GetClientWidth() +{ + return GetBox().GetSize(client_area).x - meta->scroll.GetScrollbarSize(ElementScroll::VERTICAL); +} + +// Gets the inner height of the element. +float Element::GetClientHeight() +{ + return GetBox().GetSize(client_area).y - meta->scroll.GetScrollbarSize(ElementScroll::HORIZONTAL); +} + +// Returns the element from which all offset calculations are currently computed. +Element* Element::GetOffsetParent() +{ + return offset_parent; +} + +// Gets the distance from this element's left border to its offset parent's left border. +float Element::GetOffsetLeft() +{ + return relative_offset_base.x + relative_offset_position.x; +} + +// Gets the distance from this element's top border to its offset parent's top border. +float Element::GetOffsetTop() +{ + return relative_offset_base.y + relative_offset_position.y; +} + +// Gets the width of the element, including the client area, padding, borders and scrollbars, but not margins. +float Element::GetOffsetWidth() +{ + return GetBox().GetSize(Box::BORDER).x; +} + +// Gets the height of the element, including the client area, padding, borders and scrollbars, but not margins. +float Element::GetOffsetHeight() +{ + return GetBox().GetSize(Box::BORDER).y; +} + +// Gets the left scroll offset of the element. +float Element::GetScrollLeft() +{ + return scroll_offset.x; +} + +// Sets the left scroll offset of the element. +void Element::SetScrollLeft(float scroll_left) +{ + const float new_offset = Math::Clamp(Math::RoundFloat(scroll_left), 0.0f, GetScrollWidth() - GetClientWidth()); + if (new_offset != scroll_offset.x) + { + scroll_offset.x = new_offset; + meta->scroll.UpdateScrollbar(ElementScroll::HORIZONTAL); + DirtyOffset(); + + DispatchEvent(EventId::Scroll, Dictionary()); + } +} + +// Gets the top scroll offset of the element. +float Element::GetScrollTop() +{ + return scroll_offset.y; +} + +// Sets the top scroll offset of the element. +void Element::SetScrollTop(float scroll_top) +{ + const float new_offset = Math::Clamp(Math::RoundFloat(scroll_top), 0.0f, GetScrollHeight() - GetClientHeight()); + if(new_offset != scroll_offset.y) + { + scroll_offset.y = new_offset; + meta->scroll.UpdateScrollbar(ElementScroll::VERTICAL); + DirtyOffset(); + + DispatchEvent(EventId::Scroll, Dictionary()); + } +} + +// Gets the width of the scrollable content of the element; it includes the element padding but not its margin. +float Element::GetScrollWidth() +{ + return Math::Max(content_box.x, GetClientWidth()); +} + +// Gets the height of the scrollable content of the element; it includes the element padding but not its margin. +float Element::GetScrollHeight() +{ + return Math::Max(content_box.y, GetClientHeight()); +} + +// Gets the object representing the declarations of an element's style attributes. +ElementStyle* Element::GetStyle() const +{ + return &meta->style; +} + +// Gets the document this element belongs to. +ElementDocument* Element::GetOwnerDocument() const +{ +#ifdef RMLUI_DEBUG + if (parent && !owner_document) + { + // Since we have a parent but no owner_document, then we must be a 'loose' element -- that is, constructed + // outside of a document and not attached to a child of any element in the hierarchy of a document. + // This check ensures that we didn't just forget to set the owner document. + RMLUI_ASSERT(!parent->GetOwnerDocument()); + } +#endif + + return owner_document; +} + +// Gets this element's parent node. +Element* Element::GetParentNode() const +{ + return parent; +} + +// Gets the element immediately following this one in the tree. +Element* Element::GetNextSibling() const +{ + if (parent == nullptr) + return nullptr; + + for (size_t i = 0; i < parent->children.size() - (parent->num_non_dom_children + 1); i++) + { + if (parent->children[i].get() == this) + return parent->children[i + 1].get(); + } + + return nullptr; +} + +// Gets the element immediately preceding this one in the tree. +Element* Element::GetPreviousSibling() const +{ + if (parent == nullptr) + return nullptr; + + for (size_t i = 1; i < parent->children.size() - parent->num_non_dom_children; i++) + { + if (parent->children[i].get() == this) + return parent->children[i - 1].get(); + } + + return nullptr; +} + +// Returns the first child of this element. +Element* Element::GetFirstChild() const +{ + if (GetNumChildren() > 0) + return children[0].get(); + + return nullptr; +} + +// Gets the last child of this element. +Element* Element::GetLastChild() const +{ + if (GetNumChildren() > 0) + return (children.end() - (num_non_dom_children + 1))->get(); + + return nullptr; +} + +Element* Element::GetChild(int index) const +{ + if (index < 0 || index >= (int) children.size()) + return nullptr; + + return children[index].get(); +} + +int Element::GetNumChildren(bool include_non_dom_elements) const +{ + return (int) children.size() - (include_non_dom_elements ? 0 : num_non_dom_children); +} + +// Gets the markup and content of the element. +void Element::GetInnerRML(String& content) const +{ + for (int i = 0; i < GetNumChildren(); i++) + { + children[i]->GetRML(content); + } +} + +// Gets the markup and content of the element. +String Element::GetInnerRML() const { + String result; + GetInnerRML(result); + return result; +} + +// Sets the markup and content of the element. All existing children will be replaced. +void Element::SetInnerRML(const String& rml) +{ + RMLUI_ZoneScopedC(0x6495ED); + + // Remove all DOM children. + while ((int) children.size() > num_non_dom_children) + RemoveChild(children.front().get()); + + if(!rml.empty()) + Factory::InstanceElementText(this, rml); +} + +// Sets the current element as the focus object. +bool Element::Focus() +{ + // Are we allowed focus? + Style::Focus focus_property = meta->computed_values.focus; + if (focus_property == Style::Focus::None) + return false; + + // Ask our context if we can switch focus. + Context* context = GetContext(); + if (context == nullptr) + return false; + + if (!context->OnFocusChange(this)) + return false; + + // Set this as the end of the focus chain. + focus = nullptr; + + // Update the focus chain up the hierarchy. + Element* element = this; + while (Element* parent = element->GetParentNode()) + { + parent->focus = element; + element = parent; + } + + return true; +} + +// Removes focus from from this element. +void Element::Blur() +{ + if (parent) + { + Context* context = GetContext(); + if (context == nullptr) + return; + + if (context->GetFocusElement() == this) + { + parent->Focus(); + } + else if (parent->focus == this) + { + parent->focus = nullptr; + } + } +} + +// Fakes a mouse click on this element. +void Element::Click() +{ + Context* context = GetContext(); + if (context == nullptr) + return; + + context->GenerateClickEvent(this); +} + +// Adds an event listener +void Element::AddEventListener(const String& event, EventListener* listener, bool in_capture_phase) +{ + EventId id = EventSpecificationInterface::GetIdOrInsert(event); + meta->event_dispatcher.AttachEvent(id, listener, in_capture_phase); +} + +// Adds an event listener +void Element::AddEventListener(EventId id, EventListener* listener, bool in_capture_phase) +{ + meta->event_dispatcher.AttachEvent(id, listener, in_capture_phase); +} + +// Removes an event listener from this element. +void Element::RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase) +{ + EventId id = EventSpecificationInterface::GetIdOrInsert(event); + meta->event_dispatcher.DetachEvent(id, listener, in_capture_phase); +} + +// Removes an event listener from this element. +void Element::RemoveEventListener(EventId id, EventListener* listener, bool in_capture_phase) +{ + meta->event_dispatcher.DetachEvent(id, listener, in_capture_phase); +} + + +// Dispatches the specified event +bool Element::DispatchEvent(const String& type, const Dictionary& parameters) +{ + const EventSpecification& specification = EventSpecificationInterface::GetOrInsert(type); + return EventDispatcher::DispatchEvent(this, specification.id, type, parameters, specification.interruptible, specification.bubbles, specification.default_action_phase); +} + +// Dispatches the specified event +bool Element::DispatchEvent(const String& type, const Dictionary& parameters, bool interruptible, bool bubbles) +{ + const EventSpecification& specification = EventSpecificationInterface::GetOrInsert(type); + return EventDispatcher::DispatchEvent(this, specification.id, type, parameters, interruptible, bubbles, specification.default_action_phase); +} + +// Dispatches the specified event +bool Element::DispatchEvent(EventId id, const Dictionary& parameters) +{ + const EventSpecification& specification = EventSpecificationInterface::Get(id); + return EventDispatcher::DispatchEvent(this, specification.id, specification.type, parameters, specification.interruptible, specification.bubbles, specification.default_action_phase); +} + +// Scrolls the parent element's contents so that this element is visible. +void Element::ScrollIntoView(bool align_with_top) +{ + Vector2f size(0, 0); + if (!align_with_top) + { + size.y = main_box.GetOffset().y + + main_box.GetSize(Box::BORDER).y; + } + + Element* scroll_parent = parent; + while (scroll_parent != nullptr) + { + Style::Overflow overflow_x_property = scroll_parent->GetComputedValues().overflow_x; + Style::Overflow overflow_y_property = scroll_parent->GetComputedValues().overflow_y; + + if ((overflow_x_property != Style::Overflow::Visible && + scroll_parent->GetScrollWidth() > scroll_parent->GetClientWidth()) || + (overflow_y_property != Style::Overflow::Visible && + scroll_parent->GetScrollHeight() > scroll_parent->GetClientHeight())) + { + Vector2f offset = scroll_parent->GetAbsoluteOffset(Box::BORDER) - GetAbsoluteOffset(Box::BORDER); + Vector2f scroll_offset(scroll_parent->GetScrollLeft(), scroll_parent->GetScrollTop()); + scroll_offset -= offset; + scroll_offset.x += scroll_parent->GetClientLeft(); + scroll_offset.y += scroll_parent->GetClientTop(); + + if (!align_with_top) + scroll_offset.y -= (scroll_parent->GetClientHeight() - size.y); + + if (overflow_x_property != Style::Overflow::Visible) + scroll_parent->SetScrollLeft(scroll_offset.x); + if (overflow_y_property != Style::Overflow::Visible) + scroll_parent->SetScrollTop(scroll_offset.y); + } + + scroll_parent = scroll_parent->GetParentNode(); + } +} + +// Appends a child to this element +Element* Element::AppendChild(ElementPtr child, bool dom_element) +{ + RMLUI_ASSERT(child); + Element* child_ptr = child.get(); + if (dom_element) + children.insert(children.end() - num_non_dom_children, std::move(child)); + else + { + children.push_back(std::move(child)); + num_non_dom_children++; + } + // Set parent just after inserting into children. This allows us to eg. get our previous sibling in SetParent. + child_ptr->SetParent(this); + + Element* ancestor = child_ptr; + for (int i = 0; i <= ChildNotifyLevels && ancestor; i++, ancestor = ancestor->GetParentNode()) + ancestor->OnChildAdd(child_ptr); + + DirtyStackingContext(); + DirtyStructure(); + + if (dom_element) + DirtyLayout(); + + return child_ptr; +} + +// Adds a child to this element, directly after the adjacent element. Inherits +// the dom/non-dom status from the adjacent element. +Element* Element::InsertBefore(ElementPtr child, Element* adjacent_element) +{ + RMLUI_ASSERT(child); + // Find the position in the list of children of the adjacent element. If + // it's nullptr or we can't find it, then we insert it at the end of the dom + // children, as a dom element. + size_t child_index = 0; + bool found_child = false; + if (adjacent_element) + { + for (child_index = 0; child_index < children.size(); child_index++) + { + if (children[child_index].get() == adjacent_element) + { + found_child = true; + break; + } + } + } + + Element* child_ptr = nullptr; + + if (found_child) + { + child_ptr = child.get(); + + if ((int) child_index >= GetNumChildren()) + num_non_dom_children++; + else + DirtyLayout(); + + children.insert(children.begin() + child_index, std::move(child)); + child_ptr->SetParent(this); + + Element* ancestor = child_ptr; + for (int i = 0; i <= ChildNotifyLevels && ancestor; i++, ancestor = ancestor->GetParentNode()) + ancestor->OnChildAdd(child_ptr); + + DirtyStackingContext(); + DirtyStructure(); + } + else + { + child_ptr = AppendChild(std::move(child)); + } + + return child_ptr; +} + +// Replaces the second node with the first node. +ElementPtr Element::ReplaceChild(ElementPtr inserted_element, Element* replaced_element) +{ + RMLUI_ASSERT(inserted_element); + auto insertion_point = children.begin(); + while (insertion_point != children.end() && insertion_point->get() != replaced_element) + { + ++insertion_point; + } + + Element* inserted_element_ptr = inserted_element.get(); + + if (insertion_point == children.end()) + { + AppendChild(std::move(inserted_element)); + return nullptr; + } + + children.insert(insertion_point, std::move(inserted_element)); + inserted_element_ptr->SetParent(this); + + ElementPtr result = RemoveChild(replaced_element); + + Element* ancestor = inserted_element_ptr; + for (int i = 0; i <= ChildNotifyLevels && ancestor; i++, ancestor = ancestor->GetParentNode()) + ancestor->OnChildAdd(inserted_element_ptr); + + return result; +} + +// Removes the specified child +ElementPtr Element::RemoveChild(Element* child) +{ + size_t child_index = 0; + + for (auto itr = children.begin(); itr != children.end(); ++itr) + { + // Add the element to the delete list + if (itr->get() == child) + { + Element* ancestor = child; + for (int i = 0; i <= ChildNotifyLevels && ancestor; i++, ancestor = ancestor->GetParentNode()) + ancestor->OnChildRemove(child); + + if (child_index >= children.size() - num_non_dom_children) + num_non_dom_children--; + + ElementPtr detached_child = std::move(*itr); + children.erase(itr); + + // Remove the child element as the focused child of this element. + if (child == focus) + { + focus = nullptr; + + // If this child (or a descendant of this child) is the context's currently + // focused element, set the focus to us instead. + if (Context * context = GetContext()) + { + Element* focus_element = context->GetFocusElement(); + while (focus_element) + { + if (focus_element == child) + { + Focus(); + break; + } + + focus_element = focus_element->GetParentNode(); + } + } + } + + detached_child->SetParent(nullptr); + + DirtyLayout(); + DirtyStackingContext(); + DirtyStructure(); + + return detached_child; + } + + child_index++; + } + + return nullptr; +} + + +bool Element::HasChildNodes() const +{ + return (int) children.size() > num_non_dom_children; +} + +Element* Element::GetElementById(const String& id) +{ + // Check for special-case tokens. + if (id == "#self") + return this; + else if (id == "#document") + return GetOwnerDocument(); + else if (id == "#parent") + return this->parent; + else + { + Element* search_root = GetOwnerDocument(); + if (search_root == nullptr) + search_root = this; + return ElementUtilities::GetElementById(search_root, id); + } +} + +// Get all elements with the given tag. +void Element::GetElementsByTagName(ElementList& elements, const String& tag) +{ + return ElementUtilities::GetElementsByTagName(elements, this, tag); +} + +// Get all elements with the given class set on them. +void Element::GetElementsByClassName(ElementList& elements, const String& class_name) +{ + return ElementUtilities::GetElementsByClassName(elements, this, class_name); +} + +static Element* QuerySelectorMatchRecursive(const StyleSheetNodeListRaw& nodes, Element* element) +{ + for (int i = 0; i < element->GetNumChildren(); i++) + { + Element* child = element->GetChild(i); + + for (const StyleSheetNode* node : nodes) + { + if (node->IsApplicable(child, false)) + return child; + } + + Element* matching_element = QuerySelectorMatchRecursive(nodes, child); + if (matching_element) + return matching_element; + } + + return nullptr; +} + +static void QuerySelectorAllMatchRecursive(ElementList& matching_elements, const StyleSheetNodeListRaw& nodes, Element* element) +{ + for (int i = 0; i < element->GetNumChildren(); i++) + { + Element* child = element->GetChild(i); + + for (const StyleSheetNode* node : nodes) + { + if (node->IsApplicable(child, false)) + { + matching_elements.push_back(child); + break; + } + } + + QuerySelectorAllMatchRecursive(matching_elements, nodes, child); + } +} + +Element* Element::QuerySelector(const String& selectors) +{ + StyleSheetNode root_node; + StyleSheetNodeListRaw leaf_nodes = StyleSheetParser::ConstructNodes(root_node, selectors); + + if (leaf_nodes.empty()) + { + Log::Message(Log::LT_WARNING, "Query selector '%s' is empty. In element %s", selectors.c_str(), GetAddress().c_str()); + return nullptr; + } + + return QuerySelectorMatchRecursive(leaf_nodes, this); +} + +void Element::QuerySelectorAll(ElementList& elements, const String& selectors) +{ + StyleSheetNode root_node; + StyleSheetNodeListRaw leaf_nodes = StyleSheetParser::ConstructNodes(root_node, selectors); + + if (leaf_nodes.empty()) + { + Log::Message(Log::LT_WARNING, "Query selector '%s' is empty. In element %s", selectors.c_str(), GetAddress().c_str()); + return; + } + + QuerySelectorAllMatchRecursive(elements, leaf_nodes, this); +} + +// Access the event dispatcher +EventDispatcher* Element::GetEventDispatcher() const +{ + return &meta->event_dispatcher; +} + +String Element::GetEventDispatcherSummary() const +{ + return meta->event_dispatcher.ToString(); +} + +// Access the element background. +ElementBackground* Element::GetElementBackground() const +{ + return &meta->background; +} + +// Access the element border. +ElementBorder* Element::GetElementBorder() const +{ + return &meta->border; +} + +// Access the element decorators +ElementDecoration* Element::GetElementDecoration() const +{ + return &meta->decoration; +} + +// Returns the element's scrollbar functionality. +ElementScroll* Element::GetElementScroll() const +{ + return &meta->scroll; +} + +DataModel* Element::GetDataModel() const +{ + return data_model; +} + +int Element::GetClippingIgnoreDepth() +{ + if (clipping_state_dirty) + { + IsClippingEnabled(); + } + + return clipping_ignore_depth; +} + +bool Element::IsClippingEnabled() +{ + if (clipping_state_dirty) + { + const auto& computed = GetComputedValues(); + + // Is clipping enabled for this element, yes unless both overlow properties are set to visible + clipping_enabled = computed.overflow_x != Style::Overflow::Visible + || computed.overflow_y != Style::Overflow::Visible; + + // Get the clipping ignore depth from the clip property + clipping_ignore_depth = computed.clip.number; + + clipping_state_dirty = false; + } + + return clipping_enabled; +} + +// Gets the render interface owned by this element's context. +RenderInterface* Element::GetRenderInterface() +{ + if (Context* context = GetContext()) + return context->GetRenderInterface(); + + return ::Rml::GetRenderInterface(); +} + +void Element::SetInstancer(ElementInstancer* _instancer) +{ + // Only record the first instancer being set as some instancers call other instancers to do their dirty work, in + // which case we don't want to update the lowest level instancer. + if (!instancer) + { + instancer = _instancer; + } +} + +// Forces the element to generate a local stacking context, regardless of the value of its z-index property. +void Element::ForceLocalStackingContext() +{ + local_stacking_context_forced = true; + local_stacking_context = true; + + DirtyStackingContext(); +} + +// Called during the update loop after children are rendered. +void Element::OnUpdate() +{ +} + +// Called during render after backgrounds, borders, decorators, but before children, are rendered. +void Element::OnRender() +{ +} + +void Element::OnResize() +{ +} + +// Called during a layout operation, when the element is being positioned and sized. +void Element::OnLayout() +{ +} + +// Called when attributes on the element are changed. +void Element::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + auto it = changed_attributes.find("id"); + if (it != changed_attributes.end()) + { + id = it->second.Get(); + meta->style.DirtyDefinition(); + } + + it = changed_attributes.find("class"); + if (it != changed_attributes.end()) + { + meta->style.SetClassNames(it->second.Get()); + } + + it = changed_attributes.find("style"); + if (it != changed_attributes.end()) + { + if (it->second.GetType() == Variant::STRING) + { + PropertyDictionary properties; + StyleSheetParser parser; + parser.ParseProperties(properties, it->second.GetReference()); + + for (const auto& name_value : properties.GetProperties()) + { + meta->style.SetProperty(name_value.first, name_value.second); + } + } + else if (it->second.GetType() != Variant::NONE) + { + Log::Message(Log::LT_WARNING, "Invalid 'style' attribute, string type required. In element: %s", GetAddress().c_str()); + } + } +} + +// Called when properties on the element are changed. +void Element::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + RMLUI_ZoneScoped; + + if (!IsLayoutDirty()) + { + // Force a relayout if any of the changed properties require it. + const PropertyIdSet changed_properties_forcing_layout = (changed_properties & StyleSheetSpecification::GetRegisteredPropertiesForcingLayout()); + + if(!changed_properties_forcing_layout.Empty()) + DirtyLayout(); + } + + + // Update the visibility. + if (changed_properties.Contains(PropertyId::Visibility) || + changed_properties.Contains(PropertyId::Display)) + { + bool new_visibility = (meta->computed_values.display != Style::Display::None && meta->computed_values.visibility == Style::Visibility::Visible); + + if (visible != new_visibility) + { + visible = new_visibility; + + if (parent != nullptr) + parent->DirtyStackingContext(); + + if (!visible) + Blur(); + } + + if (changed_properties.Contains(PropertyId::Display)) + { + // Due to structural pseudo-classes, this may change the element definition in siblings and parent. + // However, the definitions will only be changed on the next update loop which may result in jarring behavior for one @frame. + // A possible workaround is to add the parent to a list of elements that need to be updated again. + if (parent != nullptr) + parent->DirtyStructure(); + } + } + + // Update the position. + if (changed_properties.Contains(PropertyId::Left) || + changed_properties.Contains(PropertyId::Right) || + changed_properties.Contains(PropertyId::Top) || + changed_properties.Contains(PropertyId::Bottom)) + { + // TODO: This should happen during/after layout, as the containing box is not properly defined yet. Off-by-one @frame issue. + UpdateOffset(); + DirtyOffset(); + } + + // Update the z-index. + if (changed_properties.Contains(PropertyId::ZIndex)) + { + Style::ZIndex z_index_property = meta->computed_values.z_index; + + if (z_index_property.type == Style::ZIndex::Auto) + { + if (local_stacking_context && + !local_stacking_context_forced) + { + // We're no longer acting as a stacking context. + local_stacking_context = false; + + stacking_context_dirty = false; + stacking_context.clear(); + } + + // If our old z-index was not zero, then we must dirty our stacking context so we'll be re-indexed. + if (z_index != 0) + { + z_index = 0; + DirtyStackingContext(); + } + } + else + { + float new_z_index = z_index_property.value; + + if (new_z_index != z_index) + { + z_index = new_z_index; + + if (parent != nullptr) + parent->DirtyStackingContext(); + } + + if (!local_stacking_context) + { + local_stacking_context = true; + stacking_context_dirty = true; + } + } + } + + // Dirty the background if it's changed. + if (changed_properties.Contains(PropertyId::BackgroundColor) || + changed_properties.Contains(PropertyId::Opacity) || + changed_properties.Contains(PropertyId::ImageColor)) { + meta->background.DirtyBackground(); + } + + // Dirty the decoration if it's changed. + if (changed_properties.Contains(PropertyId::Decorator) || + changed_properties.Contains(PropertyId::Opacity) || + changed_properties.Contains(PropertyId::ImageColor)) { + meta->decoration.DirtyDecorators(); + } + + // Dirty the border if it's changed. + if (changed_properties.Contains(PropertyId::BorderTopWidth) || + changed_properties.Contains(PropertyId::BorderRightWidth) || + changed_properties.Contains(PropertyId::BorderBottomWidth) || + changed_properties.Contains(PropertyId::BorderLeftWidth) || + changed_properties.Contains(PropertyId::BorderTopColor) || + changed_properties.Contains(PropertyId::BorderRightColor) || + changed_properties.Contains(PropertyId::BorderBottomColor) || + changed_properties.Contains(PropertyId::BorderLeftColor) || + changed_properties.Contains(PropertyId::Opacity)) + meta->border.DirtyBorder(); + + + // Check for clipping state changes + if (changed_properties.Contains(PropertyId::Clip) || + changed_properties.Contains(PropertyId::OverflowX) || + changed_properties.Contains(PropertyId::OverflowY)) + { + clipping_state_dirty = true; + } + + // Check for `perspective' and `perspective-origin' changes + if (changed_properties.Contains(PropertyId::Perspective) || + changed_properties.Contains(PropertyId::PerspectiveOriginX) || + changed_properties.Contains(PropertyId::PerspectiveOriginY)) + { + DirtyTransformState(true, false); + } + + // Check for `transform' and `transform-origin' changes + if (changed_properties.Contains(PropertyId::Transform) || + changed_properties.Contains(PropertyId::TransformOriginX) || + changed_properties.Contains(PropertyId::TransformOriginY) || + changed_properties.Contains(PropertyId::TransformOriginZ)) + { + DirtyTransformState(false, true); + } + + // Check for `animation' changes + if (changed_properties.Contains(PropertyId::Animation)) + { + dirty_animation = true; + } + // Check for `transition' changes + if (changed_properties.Contains(PropertyId::Transition)) + { + dirty_transition = true; + } +} + +// Called when a child node has been added somewhere in the hierarchy +void Element::OnChildAdd(Element* /*child*/) +{ +} + +// Called when a child node has been removed somewhere in the hierarchy +void Element::OnChildRemove(Element* /*child*/) +{ +} + +// Forces a re-layout of this element, and any other children required. +void Element::DirtyLayout() +{ + Element* document = GetOwnerDocument(); + if (document != nullptr) + document->DirtyLayout(); +} + +// Forces a re-layout of this element, and any other children required. +bool Element::IsLayoutDirty() +{ + Element* document = GetOwnerDocument(); + if (document != nullptr) + return document->IsLayoutDirty(); + return false; +} + +void Element::ProcessDefaultAction(Event& event) +{ + if (event == EventId::Mousedown && IsPointWithinElement(Vector2f(event.GetParameter< float >("mouse_x", 0), event.GetParameter< float >("mouse_y", 0))) && + event.GetParameter< int >("button", 0) == 0) + SetPseudoClass("active", true); + + if (event == EventId::Mousescroll) + { + if (GetScrollHeight() > GetClientHeight()) + { + Style::Overflow overflow_property = meta->computed_values.overflow_y; + if (overflow_property == Style::Overflow::Auto || + overflow_property == Style::Overflow::Scroll) + { + // Stop the propagation if the current element has scrollbars. + // This prevents scrolling in parent elements, which is often unintended. If instead desired behavior is + // to scroll in parent elements when reaching top/bottom, move StopPropagation inside the next if statement. + event.StopPropagation(); + + const float wheel_delta = event.GetParameter< float >("wheel_delta", 0.f); + + if ((wheel_delta < 0 && GetScrollTop() > 0) || + (wheel_delta > 0 && GetScrollHeight() > GetScrollTop() + GetClientHeight())) + { + // Defined as three times the default line-height, multiplied by the dp ratio. + float default_scroll_length = 3.f * DefaultComputedValues.line_height.value; + if (const Context* context = GetContext()) + default_scroll_length *= context->GetDensityIndependentPixelRatio(); + + SetScrollTop(GetScrollTop() + wheel_delta * default_scroll_length); + } + } + } + + return; + } + + if (event.GetPhase() == EventPhase::Target) + { + switch (event.GetId()) + { + case EventId::Mouseover: + SetPseudoClass("hover", true); + break; + case EventId::Mouseout: + SetPseudoClass("hover", false); + break; + case EventId::Focus: + SetPseudoClass("focus", true); + break; + case EventId::Blur: + SetPseudoClass("focus", false); + break; + default: + break; + } + } +} + +const Style::ComputedValues& Element::GetComputedValues() const +{ + return meta->computed_values; +} + +void Element::GetRML(String& content) +{ + // First we start the open tag, add the attributes then close the open tag. + // Then comes the children in order, then we add our close tag. + content += "<"; + content += tag; + + for (auto& pair : attributes) + { + auto& name = pair.first; + auto& variant = pair.second; + String value; + if (variant.GetInto(value)) + content += " " + name + "=\"" + value + "\""; + } + + if (HasChildNodes()) + { + content += ">"; + + GetInnerRML(content); + + content += ""; + } + else + { + content += " />"; + } +} + +void Element::SetOwnerDocument(ElementDocument* document) +{ + // If this element is a document, then never change owner_document. + if (owner_document != this) + { + if (owner_document && !document) + { + // We are detaching from the document and thereby also the context. + if (Context * context = owner_document->GetContext()) + context->OnElementDetach(this); + } + + if (owner_document != document) + { + owner_document = document; + for (ElementPtr& child : children) + child->SetOwnerDocument(document); + } + } +} + +void Element::SetDataModel(DataModel* new_data_model) +{ + RMLUI_ASSERTMSG(!data_model || !new_data_model, "We must either attach a new data model, or detach the old one."); + + if (data_model == new_data_model) + return; + + if (data_model) + data_model->OnElementRemove(this); + + data_model = new_data_model; + + if (data_model) + ElementUtilities::ApplyDataViewsControllers(this); + + for (ElementPtr& child : children) + child->SetDataModel(new_data_model); +} + +void Element::Release() +{ + if (instancer) + instancer->ReleaseElement(this); + else + Log::Message(Log::LT_WARNING, "Leak detected: element %s not instanced via RmlUi Factory. Unable to release.", GetAddress().c_str()); +} + +void Element::SetParent(Element* _parent) +{ + // Assumes we are already detached from the hierarchy or we are detaching now. + RMLUI_ASSERT(!parent || !_parent); + + parent = _parent; + + if (parent) + { + // We need to update our definition and make sure we inherit the properties of our new parent. + meta->style.DirtyDefinition(); + meta->style.DirtyInheritedProperties(); + } + + // The transform state may require recalculation. + if (transform_state || (parent && parent->transform_state)) + DirtyTransformState(true, true); + + SetOwnerDocument(parent ? parent->GetOwnerDocument() : nullptr); + + if (!parent) + { + if (data_model) + SetDataModel(nullptr); + } + else + { + auto it = attributes.find("data-model"); + if (it == attributes.end()) + { + SetDataModel(parent->data_model); + } + else if (parent->data_model) + { + String name = it->second.Get(); + Log::Message(Log::LT_ERROR, "Nested data models are not allowed. Data model '%s' given in element %s.", name.c_str(), GetAddress().c_str()); + } + else if (Context* context = GetContext()) + { + String name = it->second.Get(); + if (DataModel* model = context->GetDataModelPtr(name)) + { + model->AttachModelRootElement(this); + SetDataModel(model); + } + else + Log::Message(Log::LT_ERROR, "Could not locate data model '%s' in element %s.", name.c_str(), GetAddress().c_str()); + } + } +} + +void Element::DirtyOffset() +{ + if(!offset_dirty) + { + offset_dirty = true; + + if(transform_state) + DirtyTransformState(true, true); + + // Not strictly true ... ? + for (size_t i = 0; i < children.size(); i++) + children[i]->DirtyOffset(); + } +} + +void Element::UpdateOffset() +{ + using namespace Style; + const auto& computed = meta->computed_values; + Position position_property = computed.position; + + if (position_property == Position::Absolute || + position_property == Position::Fixed) + { + if (offset_parent != nullptr) + { + const Box& parent_box = offset_parent->GetBox(); + Vector2f containing_block = parent_box.GetSize(Box::PADDING); + + // If the element is anchored left, then the position is offset by that resolved value. + if (computed.left.type != Left::Auto) + relative_offset_base.x = parent_box.GetEdge(Box::BORDER, Box::LEFT) + (ResolveValue(computed.left, containing_block.x) + GetBox().GetEdge(Box::MARGIN, Box::LEFT)); + + // If the element is anchored right, then the position is set first so the element's right-most edge + // (including margins) will render up against the containing box's right-most content edge, and then + // offset by the resolved value. + else if (computed.right.type != Right::Auto) + relative_offset_base.x = containing_block.x + parent_box.GetEdge(Box::BORDER, Box::LEFT) - (ResolveValue(computed.right, containing_block.x) + GetBox().GetSize(Box::BORDER).x + GetBox().GetEdge(Box::MARGIN, Box::RIGHT)); + + // If the element is anchored top, then the position is offset by that resolved value. + if (computed.top.type != Top::Auto) + relative_offset_base.y = parent_box.GetEdge(Box::BORDER, Box::TOP) + (ResolveValue(computed.top, containing_block.y) + GetBox().GetEdge(Box::MARGIN, Box::TOP)); + + // If the element is anchored bottom, then the position is set first so the element's right-most edge + // (including margins) will render up against the containing box's right-most content edge, and then + // offset by the resolved value. + else if (computed.bottom.type != Bottom::Auto) + relative_offset_base.y = containing_block.y + parent_box.GetEdge(Box::BORDER, Box::TOP) - (ResolveValue(computed.bottom, containing_block.y) + GetBox().GetSize(Box::BORDER).y + GetBox().GetEdge(Box::MARGIN, Box::BOTTOM)); + } + } + else if (position_property == Position::Relative) + { + if (offset_parent != nullptr) + { + const Box& parent_box = offset_parent->GetBox(); + Vector2f containing_block = parent_box.GetSize(); + + if (computed.left.type != Left::Auto) + relative_offset_position.x = ResolveValue(computed.left, containing_block.x); + else if (computed.right.type != Right::Auto) + relative_offset_position.x = -1 * ResolveValue(computed.right, containing_block.x); + else + relative_offset_position.x = 0; + + if (computed.top.type != Top::Auto) + relative_offset_position.y = ResolveValue(computed.top, containing_block.y); + else if (computed.bottom.type != Bottom::Auto) + relative_offset_position.y = -1 * ResolveValue(computed.bottom, containing_block.y); + else + relative_offset_position.y = 0; + } + } + else + { + relative_offset_position.x = 0; + relative_offset_position.y = 0; + } +} + +void Element::BuildLocalStackingContext() +{ + stacking_context_dirty = false; + stacking_context.clear(); + + BuildStackingContext(&stacking_context); + std::stable_sort(stacking_context.begin(), stacking_context.end(), ElementSortZIndex()); +} + +void Element::BuildStackingContext(ElementList* new_stacking_context) +{ + RMLUI_ZoneScoped; + + // Build the list of ordered children. Our child list is sorted within the stacking context so stacked elements + // will render in the right order; ie, positioned elements will render on top of inline elements, which will render + // on top of floated elements, which will render on top of block elements. + Vector< Pair< Element*, float > > ordered_children; + for (size_t i = 0; i < children.size(); ++i) + { + Element* child = children[i].get(); + + if (!child->IsVisible()) + continue; + + Pair< Element*, float > ordered_child; + ordered_child.first = child; + + if (child->GetPosition() != Style::Position::Static) + ordered_child.second = 3; + else if (child->GetFloat() != Style::Float::None) + ordered_child.second = 1; + else if (child->GetDisplay() == Style::Display::Block) + ordered_child.second = 0; + else + ordered_child.second = 2; + + ordered_children.push_back(ordered_child); + } + + // Sort the list! + std::stable_sort(ordered_children.begin(), ordered_children.end(), ElementSortZOrder()); + + // Add the list of ordered children into the stacking context in order. + for (size_t i = 0; i < ordered_children.size(); ++i) + { + new_stacking_context->push_back(ordered_children[i].first); + + if (!ordered_children[i].first->local_stacking_context) + ordered_children[i].first->BuildStackingContext(new_stacking_context); + } +} + +void Element::DirtyStackingContext() +{ + // The first ancestor of ours that doesn't have an automatic z-index is the ancestor that is establishing our local + // stacking context. + Element* stacking_context_parent = this; + while (stacking_context_parent != nullptr && + !stacking_context_parent->local_stacking_context) + stacking_context_parent = stacking_context_parent->GetParentNode(); + + if (stacking_context_parent != nullptr) + stacking_context_parent->stacking_context_dirty = true; +} + +void Element::DirtyStructure() +{ + structure_dirty = true; +} + +void Element::UpdateStructure() +{ + if (structure_dirty) + { + structure_dirty = false; + + // If this element or its children depend on structured selectors, they may need to be updated. + GetStyle()->DirtyDefinition(); + } +} + + +bool Element::Animate(const String & property_name, const Property & target_value, float duration, Tween tween, int num_iterations, bool alternate_direction, float delay, const Property* start_value) +{ + bool result = false; + PropertyId property_id = StyleSheetSpecification::GetPropertyId(property_name); + + auto it_animation = StartAnimation(property_id, start_value, num_iterations, alternate_direction, delay, false); + if (it_animation != animations.end()) + { + result = it_animation->AddKey(duration, target_value, *this, tween, true); + if (!result) + animations.erase(it_animation); + } + + return result; +} + + +bool Element::AddAnimationKey(const String & property_name, const Property & target_value, float duration, Tween tween) +{ + ElementAnimation* animation = nullptr; + + PropertyId property_id = StyleSheetSpecification::GetPropertyId(property_name); + + for (auto& existing_animation : animations) { + if (existing_animation.GetPropertyId() == property_id) { + animation = &existing_animation; + break; + } + } + if (!animation) + return false; + + bool result = animation->AddKey(animation->GetDuration() + duration, target_value, *this, tween, true); + + return result; +} + + +ElementAnimationList::iterator Element::StartAnimation(PropertyId property_id, const Property* start_value, int num_iterations, bool alternate_direction, float delay, bool initiated_by_animation_property) +{ + auto it = std::find_if(animations.begin(), animations.end(), [&](const ElementAnimation& el) { return el.GetPropertyId() == property_id; }); + + if (it != animations.end()) + { + *it = ElementAnimation{}; + } + else + { + animations.emplace_back(); + it = animations.end() - 1; + } + + Property value; + + if (start_value) + { + value = *start_value; + if (!value.definition) + if(auto default_value = GetProperty(property_id)) + value.definition = default_value->definition; + } + else if (auto default_value = GetProperty(property_id)) + { + value = *default_value; + } + + if (value.definition) + { + ElementAnimationOrigin origin = (initiated_by_animation_property ? ElementAnimationOrigin::Animation : ElementAnimationOrigin::User); + double start_time = Clock::GetElapsedTime() + (double)delay; + *it = ElementAnimation{ property_id, origin, value, *this, start_time, 0.0f, num_iterations, alternate_direction }; + } + + if(!it->IsInitalized()) + { + animations.erase(it); + it = animations.end(); + } + + return it; +} + + +bool Element::AddAnimationKeyTime(PropertyId property_id, const Property* target_value, float time, Tween tween) +{ + if (!target_value) + target_value = meta->style.GetProperty(property_id); + if (!target_value) + return false; + + ElementAnimation* animation = nullptr; + + for (auto& existing_animation : animations) { + if (existing_animation.GetPropertyId() == property_id) { + animation = &existing_animation; + break; + } + } + if (!animation) + return false; + + bool result = animation->AddKey(time, *target_value, *this, tween, true); + + return result; +} + +bool Element::StartTransition(const Transition & transition, const Property& start_value, const Property & target_value) +{ + auto it = std::find_if(animations.begin(), animations.end(), [&](const ElementAnimation& el) { return el.GetPropertyId() == transition.id; }); + + if (it != animations.end() && !it->IsTransition()) + return false; + + float duration = transition.duration; + double start_time = Clock::GetElapsedTime() + (double)transition.delay; + + if (it == animations.end()) + { + // Add transition as new animation + animations.push_back( + ElementAnimation{ transition.id, ElementAnimationOrigin::Transition, start_value, *this, start_time, 0.0f, 1, false } + ); + it = (animations.end() - 1); + } + else + { + // Compress the duration based on the progress of the current animation + float f = it->GetInterpolationFactor(); + f = 1.0f - (1.0f - f)*transition.reverse_adjustment_factor; + duration = duration * f; + // Replace old transition + *it = ElementAnimation{ transition.id, ElementAnimationOrigin::Transition, start_value, *this, start_time, 0.0f, 1, false }; + } + + bool result = it->AddKey(duration, target_value, *this, transition.tween, true); + + if (result) + SetProperty(transition.id, start_value); + else + animations.erase(it); + + return result; +} + +void Element::HandleTransitionProperty() +{ + if(dirty_transition) + { + dirty_transition = false; + + // Remove all transitions that are no longer in our local list + const TransitionList& keep_transitions = GetComputedValues().transition; + + if (keep_transitions.all) + return; + + auto it_remove = animations.end(); + + if (keep_transitions.none) + { + // All transitions should be removed, but only touch the animations that originate from the 'transition' property. + // Move all animations to be erased in a valid state at the end of the list, and erase later. + it_remove = std::partition(animations.begin(), animations.end(), + [](const ElementAnimation& animation) -> bool { return !animation.IsTransition(); } + ); + } + else + { + // Only remove the transitions that are not in our keep list. + const auto& keep_transitions_list = keep_transitions.transitions; + + it_remove = std::partition(animations.begin(), animations.end(), + [&keep_transitions_list](const ElementAnimation& animation) -> bool { + if (!animation.IsTransition()) + return true; + auto it = std::find_if(keep_transitions_list.begin(), keep_transitions_list.end(), + [&animation](const Transition& transition) { return animation.GetPropertyId() == transition.id; } + ); + bool keep_animation = (it != keep_transitions_list.end()); + return keep_animation; + } + ); + } + + // We can decide what to do with cancelled transitions here. + for (auto it = it_remove; it != animations.end(); ++it) + RemoveProperty(it->GetPropertyId()); + + animations.erase(it_remove, animations.end()); + } +} + +void Element::HandleAnimationProperty() +{ + // Note: We are effectively restarting all animations whenever 'dirty_animation' is set. Use the dirty flag with care, + // or find another approach which only updates actual "dirty" animations. + if (dirty_animation) + { + dirty_animation = false; + + const AnimationList& animation_list = meta->computed_values.animation; + bool element_has_animations = (!animation_list.empty() || !animations.empty()); + StyleSheet* stylesheet = nullptr; + + if (element_has_animations) + stylesheet = GetStyleSheet().get(); + + if (stylesheet) + { + // Remove existing animations + { + // We only touch the animations that originate from the 'animation' property. + auto it_remove = std::partition(animations.begin(), animations.end(), + [](const ElementAnimation & animation) { return animation.GetOrigin() != ElementAnimationOrigin::Animation; } + ); + + // We can decide what to do with cancelled animations here. + for (auto it = it_remove; it != animations.end(); ++it) + RemoveProperty(it->GetPropertyId()); + + animations.erase(it_remove, animations.end()); + } + + // Start animations + for (const auto& animation : animation_list) + { + const Keyframes* keyframes_ptr = stylesheet->GetKeyframes(animation.name); + if (keyframes_ptr && keyframes_ptr->blocks.size() >= 1 && !animation.paused) + { + auto& property_ids = keyframes_ptr->property_ids; + auto& blocks = keyframes_ptr->blocks; + + bool has_from_key = (blocks[0].normalized_time == 0); + bool has_to_key = (blocks.back().normalized_time == 1); + + // If the first key defines initial conditions for a given property, use those values, else, use this element's current values. + for (PropertyId id : property_ids) + StartAnimation(id, (has_from_key ? blocks[0].properties.GetProperty(id) : nullptr), animation.num_iterations, animation.alternate, animation.delay, true); + + // Add middle keys: Need to skip the first and last keys if they set the initial and end conditions, respectively. + for (int i = (has_from_key ? 1 : 0); i < (int)blocks.size() + (has_to_key ? -1 : 0); i++) + { + // Add properties of current key to animation + float time = blocks[i].normalized_time * animation.duration; + for (auto& property : blocks[i].properties.GetProperties()) + AddAnimationKeyTime(property.first, &property.second, time, animation.tween); + } + + // If the last key defines end conditions for a given property, use those values, else, use this element's current values. + float time = animation.duration; + for (PropertyId id : property_ids) + AddAnimationKeyTime(id, (has_to_key ? blocks.back().properties.GetProperty(id) : nullptr), time, animation.tween); + } + } + } + } +} + +void Element::AdvanceAnimations() +{ + if (!animations.empty()) + { + double time = Clock::GetElapsedTime(); + + for (auto& animation : animations) + { + Property property = animation.UpdateAndGetProperty(time, *this); + if (property.unit != Property::UNKNOWN) + SetProperty(animation.GetPropertyId(), property); + } + + // Move all completed animations to the end of the list + auto it_completed = std::partition(animations.begin(), animations.end(), [](const ElementAnimation& animation) { return !animation.IsComplete(); }); + + Vector dictionary_list; + Vector is_transition; + dictionary_list.reserve(animations.end() - it_completed); + is_transition.reserve(animations.end() - it_completed); + + for (auto it = it_completed; it != animations.end(); ++it) + { + const String& property_name = StyleSheetSpecification::GetPropertyName(it->GetPropertyId()); + + dictionary_list.emplace_back(); + dictionary_list.back().emplace("property", Variant(property_name)); + is_transition.push_back(it->IsTransition()); + + // Remove completed transition- and animation-initiated properties. + // Should behave like in HandleTransitionProperty() and HandleAnimationProperty() respectively. + if (it->GetOrigin() != ElementAnimationOrigin::User) + RemoveProperty(it->GetPropertyId()); + } + + // Need to erase elements before submitting event, as iterators might be invalidated when calling external code. + animations.erase(it_completed, animations.end()); + + for (size_t i = 0; i < dictionary_list.size(); i++) + DispatchEvent(is_transition[i] ? EventId::Transitionend : EventId::Animationend, dictionary_list[i]); + } +} + + + +void Element::DirtyTransformState(bool perspective_dirty, bool transform_dirty) +{ + dirty_perspective |= perspective_dirty; + dirty_transform |= transform_dirty; +} + + +void Element::UpdateTransformState() +{ + if (!dirty_perspective && !dirty_transform) + return; + + const ComputedValues& computed = meta->computed_values; + + const Vector2f pos = GetAbsoluteOffset(Box::BORDER); + const Vector2f size = GetBox().GetSize(Box::BORDER); + + bool perspective_or_transform_changed = false; + + if (dirty_perspective) + { + // If perspective is set on this element, then it applies to our children. We just calculate it here, + // and let the children's transform update merge it with their transform. + bool had_perspective = (transform_state && transform_state->GetLocalPerspective()); + + float distance = computed.perspective; + Vector2f vanish = Vector2f(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f); + bool have_perspective = false; + + if (distance > 0.0f) + { + have_perspective = true; + + // Compute the vanishing point from the perspective origin + if (computed.perspective_origin_x.type == Style::PerspectiveOrigin::Percentage) + vanish.x = pos.x + computed.perspective_origin_x.value * 0.01f * size.x; + else + vanish.x = pos.x + computed.perspective_origin_x.value; + + if (computed.perspective_origin_y.type == Style::PerspectiveOrigin::Percentage) + vanish.y = pos.y + computed.perspective_origin_y.value * 0.01f * size.y; + else + vanish.y = pos.y + computed.perspective_origin_y.value; + } + + if (have_perspective) + { + // Equivalent to: Translate(x,y,0) * Perspective(distance) * Translate(-x,-y,0) + Matrix4f perspective = Matrix4f::FromRows( + { 1, 0, -vanish.x / distance, 0 }, + { 0, 1, -vanish.y / distance, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, -1 / distance, 1 } + ); + + if (!transform_state) + transform_state = MakeUnique(); + + perspective_or_transform_changed |= transform_state->SetLocalPerspective(&perspective); + } + else if (transform_state) + transform_state->SetLocalPerspective(nullptr); + + perspective_or_transform_changed |= (have_perspective != had_perspective); + + dirty_perspective = false; + } + + + if (dirty_transform) + { + // We want to find the accumulated transform given all our ancestors. It is assumed here that the parent transform is already updated, + // so that we only need to consider our local transform and combine it with our parent's transform and perspective matrices. + bool had_transform = (transform_state && transform_state->GetTransform()); + + bool have_transform = false; + Matrix4f transform = Matrix4f::Identity(); + + if (computed.transform) + { + // First find the current element's transform + const int n = computed.transform->GetNumPrimitives(); + for (int i = 0; i < n; ++i) + { + const TransformPrimitive& primitive = computed.transform->GetPrimitive(i); + Matrix4f matrix = TransformUtilities::ResolveTransform(primitive, *this); + transform *= matrix; + have_transform = true; + } + + if(have_transform) + { + // Compute the transform origin + Vector3f transform_origin(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f, 0); + + if (computed.transform_origin_x.type == Style::TransformOrigin::Percentage) + transform_origin.x = pos.x + computed.transform_origin_x.value * size.x * 0.01f; + else + transform_origin.x = pos.x + computed.transform_origin_x.value; + + if (computed.transform_origin_y.type == Style::TransformOrigin::Percentage) + transform_origin.y = pos.y + computed.transform_origin_y.value * size.y * 0.01f; + else + transform_origin.y = pos.y + computed.transform_origin_y.value; + + transform_origin.z = computed.transform_origin_z; + + // Make the transformation apply relative to the transform origin + transform = Matrix4f::Translate(transform_origin) * transform * Matrix4f::Translate(-transform_origin); + } + + // We may want to include the local offsets here, as suggested by the CSS specs, so that the local transform is applied after the offset I believe + // the motivation is. Then we would need to subtract the absolute zero-offsets during geometry submit whenever we have transforms. + } + + if (parent && parent->transform_state) + { + // Apply the parent's local perspective and transform. + // @performance: If we have no local transform and no parent perspective, we can effectively just point to the parent transform instead of copying it. + const TransformState& parent_state = *parent->transform_state; + + if (auto parent_perspective = parent_state.GetLocalPerspective()) + { + transform = *parent_perspective * transform; + have_transform = true; + } + + if (auto parent_transform = parent_state.GetTransform()) + { + transform = *parent_transform * transform; + have_transform = true; + } + } + + if (have_transform) + { + if (!transform_state) + transform_state = MakeUnique(); + + perspective_or_transform_changed |= transform_state->SetTransform(&transform); + } + else if (transform_state) + transform_state->SetTransform(nullptr); + + perspective_or_transform_changed |= (had_transform != have_transform); + } + + // A change in perspective or transform will require an update to children transforms as well. + if (perspective_or_transform_changed) + { + for (size_t i = 0; i < children.size(); i++) + children[i]->DirtyTransformState(false, true); + } + + // No reason to keep the transform state around if transform and perspective have been removed. + if (transform_state && !transform_state->GetTransform() && !transform_state->GetLocalPerspective()) + { + transform_state.reset(); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementAnimation.cpp b/thirdparty/RmlUi/Source/Core/ElementAnimation.cpp new file mode 100644 index 000000000..7ecfdc6f8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementAnimation.cpp @@ -0,0 +1,542 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2018 Michael R. P. Ragazzon + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementAnimation.h" +#include "ElementStyle.h" +#include "TransformUtilities.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/Transform.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" + +namespace Rml { + +static Colourf ColourToLinearSpace(Colourb c) +{ + Colourf result; + // Approximate inverse sRGB function + result.red = Math::SquareRoot((float)c.red / 255.f); + result.green = Math::SquareRoot((float)c.green / 255.f); + result.blue = Math::SquareRoot((float)c.blue / 255.f); + result.alpha = (float)c.alpha / 255.f; + return result; +} + +static Colourb ColourFromLinearSpace(Colourf c) +{ + Colourb result; + result.red = (byte)Math::Clamp(c.red*c.red*255.f, 0.0f, 255.f); + result.green = (byte)Math::Clamp(c.green*c.green*255.f, 0.0f, 255.f); + result.blue = (byte)Math::Clamp(c.blue*c.blue*255.f, 0.0f, 255.f); + result.alpha = (byte)Math::Clamp(c.alpha*255.f, 0.0f, 255.f); + return result; +} + +// Merges all the primitives to a single DecomposedMatrix4 primitive +static bool CombineAndDecompose(Transform& t, Element& e) +{ + Matrix4f m = Matrix4f::Identity(); + + for (TransformPrimitive& primitive : t.GetPrimitives()) + { + Matrix4f m_primitive = TransformUtilities::ResolveTransform(primitive, e); + m *= m_primitive; + } + + Transforms::DecomposedMatrix4 decomposed; + + if (!TransformUtilities::Decompose(decomposed, m)) + return false; + + t.ClearPrimitives(); + t.AddPrimitive(decomposed); + + return true; +} + + +static Property InterpolateProperties(const Property & p0, const Property& p1, float alpha, Element& element, const PropertyDefinition* definition) +{ + if ((p0.unit & Property::NUMBER_LENGTH_PERCENT) && (p1.unit & Property::NUMBER_LENGTH_PERCENT)) + { + if (p0.unit == p1.unit || !definition) + { + // If we have the same units, we can just interpolate regardless of what the value represents. + // Or if we have distinct units but no definition, all bets are off. This shouldn't occur, just interpolate values. + float f0 = p0.value.Get(); + float f1 = p1.value.Get(); + float f = (1.0f - alpha) * f0 + alpha * f1; + return Property{ f, p0.unit }; + } + else + { + // Otherwise, convert units to pixels. + float f0 = element.GetStyle()->ResolveLength(&p0, definition->GetRelativeTarget()); + float f1 = element.GetStyle()->ResolveLength(&p1, definition->GetRelativeTarget()); + float f = (1.0f - alpha) * f0 + alpha * f1; + return Property{ f, Property::PX }; + } + } + + if (p0.unit == Property::KEYWORD && p1.unit == Property::KEYWORD) + { + // Discrete interpolation, swap at alpha = 0.5. + // Special case for the 'visibility' property as in the CSS specs: + // Apply the visible property if present during the entire transition period, ie. alpha (0,1). + if (definition && definition->GetId() == PropertyId::Visibility) + { + if (p0.Get() == (int)Style::Visibility::Visible) + return alpha < 1.f ? p0 : p1; + else if (p1.Get() == (int)Style::Visibility::Visible) + return alpha <= 0.f ? p0 : p1; + } + + return alpha < 0.5f ? p0 : p1; + } + + if (p0.unit == Property::COLOUR && p1.unit == Property::COLOUR) + { + Colourf c0 = ColourToLinearSpace(p0.value.Get()); + Colourf c1 = ColourToLinearSpace(p1.value.Get()); + + Colourf c = c0 * (1.0f - alpha) + c1 * alpha; + + return Property{ ColourFromLinearSpace(c), Property::COLOUR }; + } + + if (p0.unit == Property::TRANSFORM && p1.unit == Property::TRANSFORM) + { + auto& t0 = p0.value.GetReference(); + auto& t1 = p1.value.GetReference(); + + const auto& prim0 = t0->GetPrimitives(); + const auto& prim1 = t1->GetPrimitives(); + + if (prim0.size() != prim1.size()) + { + RMLUI_ERRORMSG("Transform primitives not of same size during interpolation. Were the transforms properly prepared for interpolation?"); + return Property{ t0, Property::TRANSFORM }; + } + + // Build the new, interpolating transform + UniquePtr t(new Transform); + t->GetPrimitives().reserve(t0->GetPrimitives().size()); + + for (size_t i = 0; i < prim0.size(); i++) + { + TransformPrimitive p = prim0[i]; + if (!TransformUtilities::InterpolateWith(p, prim1[i], alpha)) + { + RMLUI_ERRORMSG("Transform primitives can not be interpolated. Were the transforms properly prepared for interpolation?"); + return Property{ t0, Property::TRANSFORM }; + } + t->AddPrimitive(p); + } + + return Property{ TransformPtr(std::move(t)), Property::TRANSFORM }; + } + + // Fall back to discrete interpolation for incompatible units. + return alpha < 0.5f ? p0 : p1; +} + + + + +enum class PrepareTransformResult { Unchanged = 0, ChangedT0 = 1, ChangedT1 = 2, ChangedT0andT1 = 3, Invalid = 4 }; + +static PrepareTransformResult PrepareTransformPair(Transform& t0, Transform& t1, Element& element) +{ + using namespace Transforms; + + // Insert or modify primitives such that the two transforms match exactly in both number of and types of primitives. + // Based largely on https://drafts.csswg.org/css-transforms-1/#interpolation-of-transforms + + auto& prims0 = t0.GetPrimitives(); + auto& prims1 = t1.GetPrimitives(); + + // Check for trivial case where they contain the same primitives + if (prims0.size() == prims1.size()) + { + PrepareTransformResult result = PrepareTransformResult::Unchanged; + bool same_primitives = true; + + for (size_t i = 0; i < prims0.size(); i++) + { + auto p0_type = prims0[i].type; + auto p1_type = prims1[i].type; + + // See if they are the same or can be converted to a matching generic type. + if (TransformUtilities::TryConvertToMatchingGenericType(prims0[i], prims1[i])) + { + if (prims0[i].type != p0_type) + result = PrepareTransformResult((int)result | (int)PrepareTransformResult::ChangedT0); + if (prims1[i].type != p1_type) + result = PrepareTransformResult((int)result | (int)PrepareTransformResult::ChangedT1); + } + else + { + same_primitives = false; + break; + } + } + if (same_primitives) + return result; + } + + if (prims0.size() != prims1.size()) + { + // Try to match the smallest set of primitives to the larger set, set missing keys in the small set to identity. + // Requirement: The small set must match types in the same order they appear in the big set. + // Example: (letter indicates type, number represents values) + // big: a0 b0 c0 b1 + // ^ ^ + // small: b2 b3 + // ^ ^ + // new small: a1 b2 c1 b3 + bool prims0_smallest = (prims0.size() < prims1.size()); + + auto& small = (prims0_smallest ? prims0 : prims1); + auto& big = (prims0_smallest ? prims1 : prims0); + + Vector matching_indices; // Indices into 'big' for matching types + matching_indices.reserve(small.size() + 1); + + size_t i_big = 0; + bool match_success = true; + bool changed_big = false; + + // Iterate through the small set to see if its types fit into the big set + for (size_t i_small = 0; i_small < small.size(); i_small++) + { + match_success = false; + + for (; i_big < big.size(); i_big++) + { + auto big_type = big[i_big].type; + + if (TransformUtilities::TryConvertToMatchingGenericType(small[i_small], big[i_big])) + { + // They matched exactly or in their more generic form. One or both primitives may have been converted. + match_success = true; + if (big[i_big].type != big_type) + changed_big = true; + } + + if (match_success) + { + matching_indices.push_back(i_big); + match_success = true; + i_big += 1; + break; + } + } + + if (!match_success) + break; + } + + + if (match_success) + { + // Success, insert the missing primitives into the small set + matching_indices.push_back(big.size()); // Needed to copy elements behind the last matching primitive + small.reserve(big.size()); + size_t i0 = 0; + for (size_t match_index : matching_indices) + { + for (size_t i = i0; i < match_index; i++) + { + TransformPrimitive p = big[i]; + TransformUtilities::SetIdentity(p); + small.insert(small.begin() + i, p); + } + + // Next value to copy is one-past the matching primitive + i0 = match_index + 1; + } + + // The small set has always been changed if we get here, but the big set is only changed + // if one or more of its primitives were converted to a general form. + if (changed_big) + return PrepareTransformResult::ChangedT0andT1; + + return (prims0_smallest ? PrepareTransformResult::ChangedT0 : PrepareTransformResult::ChangedT1); + } + } + + + // If we get here, things get tricky. Need to do full matrix interpolation. + // In short, we decompose the Transforms into translation, rotation, scale, skew and perspective components. + // Then, during update, interpolate these components and combine into a new transform matrix. + if (!CombineAndDecompose(t0, element)) + return PrepareTransformResult::Invalid; + if (!CombineAndDecompose(t1, element)) + return PrepareTransformResult::Invalid; + + return PrepareTransformResult::ChangedT0andT1; +} + + +static bool PrepareTransforms(Vector& keys, Element& element, int start_index) +{ + bool result = true; + + // Prepare each transform individually. + for (int i = start_index; i < (int)keys.size(); i++) + { + Property& property = keys[i].property; + RMLUI_ASSERT(property.value.GetType() == Variant::TRANSFORMPTR); + + if (!property.value.GetReference()) + property.value = MakeShared(); + + bool must_decompose = false; + Transform& transform = *property.value.GetReference(); + + for (TransformPrimitive& primitive : transform.GetPrimitives()) + { + if (!TransformUtilities::PrepareForInterpolation(primitive, element)) + { + must_decompose = true; + break; + } + } + + if (must_decompose) + result &= CombineAndDecompose(transform, element); + } + + if (!result) + return false; + + // We don't need to prepare the transforms pairwise if we only have a single key added so far. + if (keys.size() < 2 || start_index < 1) + return true; + + // Now, prepare the transforms pair-wise so they can be interpolated. + const int N = (int)keys.size(); + + int count_iterations = -1; + const int max_iterations = 3 * N; + + Vector dirty_list(N + 1, false); + dirty_list[start_index] = true; + + // For each pair of keys, match the transform primitives such that they can be interpolated during animation update + for (int i = start_index; i < N && count_iterations < max_iterations; count_iterations++) + { + if (!dirty_list[i]) + { + ++i; + continue; + } + + auto& prop0 = keys[i - 1].property; + auto& prop1 = keys[i].property; + + if(prop0.unit != Property::TRANSFORM || prop1.unit != Property::TRANSFORM) + return false; + + auto& t0 = prop0.value.GetReference(); + auto& t1 = prop1.value.GetReference(); + + auto prepare_result = PrepareTransformPair(*t0, *t1, element); + + if (prepare_result == PrepareTransformResult::Invalid) + return false; + + bool changed_t0 = ((int)prepare_result & (int)PrepareTransformResult::ChangedT0); + bool changed_t1 = ((int)prepare_result & (int)PrepareTransformResult::ChangedT1); + + dirty_list[i] = false; + dirty_list[i - 1] = dirty_list[i - 1] || changed_t0; + dirty_list[i + 1] = dirty_list[i + 1] || changed_t1; + + if (changed_t0 && i > 1) + --i; + else + ++i; + } + + // Something has probably gone wrong if we exceeded max_iterations, possibly a bug in PrepareTransformPair() + return (count_iterations < max_iterations); +} + + +ElementAnimation::ElementAnimation(PropertyId property_id, ElementAnimationOrigin origin, const Property& current_value, Element& element, double start_world_time, float duration, int num_iterations, bool alternate_direction) + : property_id(property_id), duration(duration), num_iterations(num_iterations), alternate_direction(alternate_direction), last_update_world_time(start_world_time), + time_since_iteration_start(0.0f), current_iteration(0), reverse_direction(false), animation_complete(false), origin(origin) +{ + if (!current_value.definition) + { + Log::Message(Log::LT_WARNING, "Property in animation key did not have a definition (while adding key '%s').", current_value.ToString().c_str()); + } + InternalAddKey(0.0f, current_value, element, Tween{}); +} + + +bool ElementAnimation::InternalAddKey(float time, const Property& in_property, Element& element, Tween tween) +{ + int valid_properties = (Property::NUMBER_LENGTH_PERCENT | Property::ANGLE | Property::COLOUR | Property::TRANSFORM | Property::KEYWORD); + + if (!(in_property.unit & valid_properties)) + { + Log::Message(Log::LT_WARNING, "Property '%s' is not a valid target for interpolation.", in_property.ToString().c_str()); + return false; + } + + keys.emplace_back(time, in_property, tween); + bool result = true; + + if (keys.back().property.unit == Property::TRANSFORM) + { + result = PrepareTransforms(keys, element, (int)keys.size() - 1); + } + + if (!result) + { + Log::Message(Log::LT_WARNING, "Could not add animation key with property '%s'.", in_property.ToString().c_str()); + keys.pop_back(); + } + + return result; +} + + +bool ElementAnimation::AddKey(float target_time, const Property & in_property, Element& element, Tween tween, bool extend_duration) +{ + if (!IsInitalized()) + { + Log::Message(Log::LT_WARNING, "Element animation was not initialized properly, can't add key."); + return false; + } + if (!InternalAddKey(target_time, in_property, element, tween)) + { + return false; + } + + if (extend_duration) + duration = target_time; + + return true; +} + +float ElementAnimation::GetInterpolationFactorAndKeys(int* out_key0, int* out_key1) const +{ + float t = time_since_iteration_start; + + if (reverse_direction) + t = duration - t; + + int key0 = -1; + int key1 = -1; + + { + for (int i = 0; i < (int)keys.size(); i++) + { + if (keys[i].time >= t) + { + key1 = i; + break; + } + } + + if (key1 < 0) key1 = (int)keys.size() - 1; + key0 = (key1 == 0 ? 0 : key1 - 1); + } + + RMLUI_ASSERT(key0 >= 0 && key0 < (int)keys.size() && key1 >= 0 && key1 < (int)keys.size()); + + float alpha = 0.0f; + + { + const float t0 = keys[key0].time; + const float t1 = keys[key1].time; + + const float eps = 1e-3f; + + if (t1 - t0 > eps) + alpha = (t - t0) / (t1 - t0); + + alpha = Math::Clamp(alpha, 0.0f, 1.0f); + } + + alpha = keys[key1].tween(alpha); + + if (out_key0) *out_key0 = key0; + if (out_key1) *out_key1 = key1; + + return alpha; +} + + + +Property ElementAnimation::UpdateAndGetProperty(double world_time, Element& element) +{ + float dt = float(world_time - last_update_world_time); + if (keys.size() < 2 || animation_complete || dt <= 0.0f) + return Property{}; + + dt = Math::Min(dt, 0.1f); + + last_update_world_time = world_time; + time_since_iteration_start += dt; + + if (time_since_iteration_start >= duration) + { + // Next iteration + current_iteration += 1; + + if (num_iterations == -1 || (current_iteration >= 0 && current_iteration < num_iterations)) + { + time_since_iteration_start -= duration; + + if (alternate_direction) + reverse_direction = !reverse_direction; + } + else + { + animation_complete = true; + time_since_iteration_start = duration; + } + } + + int key0 = -1; + int key1 = -1; + + float alpha = GetInterpolationFactorAndKeys(&key0, &key1); + + Property result = InterpolateProperties(keys[key0].property, keys[key1].property, alpha, element, keys[0].property.definition); + + return result; +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementAnimation.h b/thirdparty/RmlUi/Source/Core/ElementAnimation.h new file mode 100644 index 000000000..c868ca288 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementAnimation.h @@ -0,0 +1,94 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2018 Michael R. P. Ragazzon + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTANIMATION_H +#define RMLUI_CORE_ELEMENTANIMATION_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Tween.h" + +namespace Rml { + +struct AnimationKey { + AnimationKey(float time, const Property& property, Tween tween) : time(time), property(property), tween(tween) {} + float time; // Local animation time (Zero means the time when the animation iteration starts) + Property property; + Tween tween; // Tweening between the previous and this key. Ignored for the first animation key. +}; + +// The origin is tracked for determining its behavior when adding and removing animations. +// User: Animation started by the Element API +// Animation: Animation started by the 'animation' property +// Transition: Animation started by the 'transition' property +enum class ElementAnimationOrigin : uint8_t { User, Animation, Transition }; + +class ElementAnimation +{ +private: + PropertyId property_id = PropertyId::Invalid; + + float duration = 0; // for a single iteration + int num_iterations = 0; // -1 for infinity + bool alternate_direction = 0; // between iterations + + Vector keys; + + double last_update_world_time = 0; + float time_since_iteration_start = 0; + int current_iteration = 0; + bool reverse_direction = false; + + bool animation_complete = true; + ElementAnimationOrigin origin = ElementAnimationOrigin::User; + + bool InternalAddKey(float time, const Property& property, Element& element, Tween tween); + + float GetInterpolationFactorAndKeys(int* out_key0, int* out_key1) const; + +public: + ElementAnimation() {} + ElementAnimation(PropertyId property_id, ElementAnimationOrigin origin, const Property& current_value, Element& element, + double start_world_time, float duration, int num_iterations, bool alternate_direction); + + bool AddKey(float target_time, const Property & property, Element & element, Tween tween, bool extend_duration); + + Property UpdateAndGetProperty(double time, Element& element); + + PropertyId GetPropertyId() const { return property_id; } + float GetDuration() const { return duration; } + bool IsComplete() const { return animation_complete; } + bool IsTransition() const { return origin == ElementAnimationOrigin::Transition; } + bool IsInitalized() const { return !keys.empty(); } + float GetInterpolationFactor() const { return GetInterpolationFactorAndKeys(nullptr, nullptr); } + ElementAnimationOrigin GetOrigin() const { return origin; } +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementBackground.cpp b/thirdparty/RmlUi/Source/Core/ElementBackground.cpp new file mode 100644 index 000000000..c9186da44 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementBackground.cpp @@ -0,0 +1,134 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "ElementBackground.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Profiling.h" + + +namespace Rml { + +ElementBackground::ElementBackground(Element* _element) : geometry(_element) +{ + element = _element; + background_dirty = true; +} + +ElementBackground::~ElementBackground() +{ +} + +// Renders the element's background, if it has one. +void ElementBackground::RenderBackground() +{ + if (background_dirty) + { + background_dirty = false; + GenerateBackground(); + } + + geometry.Render(element->GetAbsoluteOffset(Box::PADDING)); +} + +// Marks the background geometry as dirty. +void ElementBackground::DirtyBackground() +{ + background_dirty = true; +} + +// Generates the background geometry for the element. +void ElementBackground::GenerateBackground() +{ + RMLUI_ZoneScoped; + + // Fetch the new colour for the background. If the colour is transparent, then we don't render any background. + auto& computed = element->GetComputedValues(); + Colourb colour = computed.background_color; + float opacity = computed.opacity; + + // Apply opacity + colour.alpha = (byte)(opacity * (float)colour.alpha); + + if (colour.alpha <= 0) + { + geometry.GetVertices().clear(); + geometry.GetIndices().clear(); + geometry.Release(); + + return; + } + + // Work out how many boxes we need to generate geometry for. + int num_boxes = 0; + + for (int i = 0; i < element->GetNumBoxes(); ++i) + { + const Box& box = element->GetBox(i); + Vector2f size = box.GetSize(Box::PADDING); + if (size.x > 0 && size.y > 0) + num_boxes++; + } + + Vector< Vertex >& vertices = geometry.GetVertices(); + Vector< int >& indices = geometry.GetIndices(); + + int index_offset = 0; + vertices.resize(4 * num_boxes); + indices.resize(6 * num_boxes); + + if (num_boxes > 0) + { + Vertex* raw_vertices = &vertices[0]; + int* raw_indices = &indices[0]; + + for (int i = 0; i < element->GetNumBoxes(); ++i) + GenerateBackground(raw_vertices, raw_indices, index_offset, element->GetBox(i), colour); + } + + geometry.Release(); +} + +// Generates the background geometry for a single box. +void ElementBackground::GenerateBackground(Vertex*& vertices, int*& indices, int& index_offset, const Box& box, const Colourb& colour) +{ + Vector2f padded_size = box.GetSize(Box::PADDING); + if (padded_size.x <= 0 || + padded_size.y <= 0) + return; + + GeometryUtilities::GenerateQuad(vertices, indices, box.GetOffset(), padded_size, colour, index_offset); + + vertices += 4; + indices += 6; + index_offset += 4; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementBackground.h b/thirdparty/RmlUi/Source/Core/ElementBackground.h new file mode 100644 index 000000000..a55eedb9e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementBackground.h @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTBACKGROUND_H +#define RMLUI_CORE_ELEMENTBACKGROUND_H + +#include "../../Include/RmlUi/Core/Geometry.h" + +namespace Rml { + +class Box; +class Element; + +/** + @author Peter Curry + */ + +class ElementBackground +{ +public: + ElementBackground(Element* element); + ~ElementBackground(); + + /// Renders the element's border, if it has one. + void RenderBackground(); + + /// Marks the border geometry as dirty. + void DirtyBackground(); + +private: + // Generates the border geometry for the element. + void GenerateBackground(); + // Generates the border geometry for a single box. + void GenerateBackground(Vertex*& vertices, int*& indices, int& index_offset, const Box& box, const Colourb& colour); + + Element* element; + + // The background geometry. + Geometry geometry; + + bool background_dirty; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementBorder.cpp b/thirdparty/RmlUi/Source/Core/ElementBorder.cpp new file mode 100644 index 000000000..8789f8591 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementBorder.cpp @@ -0,0 +1,161 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "ElementBorder.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Profiling.h" + +namespace Rml { + +ElementBorder::ElementBorder(Element* _element) : geometry(_element) +{ + element = _element; + border_dirty = true; +} + +ElementBorder::~ElementBorder() +{ +} + +// Renders the element's border, if it has one. +void ElementBorder::RenderBorder() +{ + RMLUI_ZoneScoped; + if (border_dirty) + { + border_dirty = false; + GenerateBorder(); + } + + geometry.Render(element->GetAbsoluteOffset(Box::BORDER)); +} + +// Marks the border geometry as dirty. +void ElementBorder::DirtyBorder() +{ + border_dirty = true; +} + +// Generates the border geometry for the element. +void ElementBorder::GenerateBorder() +{ + int num_edges = 0; + + for (int i = 0; i < element->GetNumBoxes(); ++i) + { + const Box& box = element->GetBox(i); + for (int j = 0; j < 4; j++) + { + if (box.GetEdge(Box::BORDER, (Box::Edge) j) > 0) + num_edges++; + } + } + + Vector< Vertex >& vertices = geometry.GetVertices(); + Vector< int >& indices = geometry.GetIndices(); + + int index_offset = 0; + vertices.resize(4 * num_edges); + indices.resize(6 * num_edges); + + if (num_edges > 0) + { + Vertex* raw_vertices = &vertices[0]; + int* raw_indices = &indices[0]; + const ComputedValues& computed = element->GetComputedValues(); + + Colourb border_colours[4]; + border_colours[0] = computed.border_top_color; + border_colours[1] = computed.border_right_color; + border_colours[2] = computed.border_bottom_color; + border_colours[3] = computed.border_left_color; + + // Apply opacity to the border + float opacity = computed.opacity; + for(int i = 0; i < 4; ++i) { + border_colours[i].alpha = (byte)(opacity * (float)border_colours[i].alpha); + } + + for (int i = 0; i < element->GetNumBoxes(); ++i) + GenerateBorder(raw_vertices, raw_indices, index_offset, element->GetBox(i), border_colours); + } + + geometry.Release(); +} + +// Generates the border geometry for a single box. +void ElementBorder::GenerateBorder(Vertex*& vertices, int*& indices, int& index_offset, const Box& box, const Colourb* colours) +{ + // The axis of extrusion for each of the edges. + Vector2f box_extrusions[4] = + { + Vector2f(0, -1 * box.GetEdge(Box::BORDER, Box::TOP)), + Vector2f(box.GetEdge(Box::BORDER, Box::RIGHT), 0), + Vector2f(0, box.GetEdge(Box::BORDER, Box::BOTTOM)), + Vector2f(-1 * box.GetEdge(Box::BORDER, Box::LEFT), 0) + }; + + // The position of each of the corners of the inner border. + Vector2f box_corners[4]; + box_corners[0] = box.GetPosition(Box::PADDING); + box_corners[2] = box_corners[0] + box.GetSize(Box::PADDING); + box_corners[1] = Vector2f(box_corners[2].x, box_corners[0].y); + box_corners[3] = Vector2f(box_corners[0].x, box_corners[2].y); + + for (int i = 0; i < 4; i++) + { + float border_width = box.GetEdge(Box::BORDER, (Box::Edge) i); + if (border_width <= 0) + continue; + + vertices[0].position = box_corners[i]; + vertices[1].position = box_corners[i] + box_extrusions[i] + box_extrusions[i == 0 ? 3 : i - 1]; + vertices[2].position = box_corners[i == 3 ? 0 : i + 1]; + vertices[3].position = vertices[2].position + box_extrusions[i] + box_extrusions[i == 3 ? 0 : i + 1]; + + vertices[0].colour = colours[i]; + vertices[1].colour = colours[i]; + vertices[2].colour = colours[i]; + vertices[3].colour = colours[i]; + + indices[0] = index_offset; + indices[1] = index_offset + 3; + indices[2] = index_offset + 1; + indices[3] = index_offset; + indices[4] = index_offset + 2; + indices[5] = index_offset + 3; + + vertices += 4; + indices += 6; + index_offset += 4; + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementBorder.h b/thirdparty/RmlUi/Source/Core/ElementBorder.h new file mode 100644 index 000000000..b7a63a866 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementBorder.h @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTBORDER_H +#define RMLUI_CORE_ELEMENTBORDER_H + +#include "../../Include/RmlUi/Core/Geometry.h" + +namespace Rml { + +class Box; +class Element; + +/** + @author Peter Curry + */ + +class ElementBorder +{ +public: + ElementBorder(Element* element); + ~ElementBorder(); + + /// Renders the element's border, if it has one. + void RenderBorder(); + + /// Marks the border geometry as dirty. + void DirtyBorder(); + +private: + // Generates the border geometry for the element. + void GenerateBorder(); + // Generates the border geometry for a single box. + void GenerateBorder(Vertex*& vertices, int*& indices, int& index_offset, const Box& box, const Colourb* colours); + + Element* element; + + // The border geometry. + Geometry geometry; + + bool border_dirty; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementDecoration.cpp b/thirdparty/RmlUi/Source/Core/ElementDecoration.cpp new file mode 100644 index 000000000..478126cb9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementDecoration.cpp @@ -0,0 +1,116 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementDecoration.h" +#include "ElementDefinition.h" +#include "../../Include/RmlUi/Core/Decorator.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Profiling.h" + +namespace Rml { + +ElementDecoration::ElementDecoration(Element* _element) +{ + element = _element; + decorators_dirty = false; +} + +ElementDecoration::~ElementDecoration() +{ + ReleaseDecorators(); +} + +// Releases existing decorators and loads all decorators required by the element's definition. +bool ElementDecoration::ReloadDecorators() +{ + RMLUI_ZoneScopedC(0xB22222); + ReleaseDecorators(); + + auto& decorators_ptr = element->GetComputedValues().decorator; + if (!decorators_ptr) + return true; + + for (const auto& decorator : decorators_ptr->list) + { + if (decorator) + { + LoadDecorator(decorator); + } + } + + return true; +} + +// Loads a single decorator and adds it to the list of loaded decorators for this element. +int ElementDecoration::LoadDecorator(SharedPtr decorator) +{ + DecoratorHandle element_decorator; + element_decorator.decorator_data = decorator->GenerateElementData(element); + element_decorator.decorator = std::move(decorator); + + decorators.push_back(element_decorator); + return (int) (decorators.size() - 1); +} + +// Releases all existing decorators and frees their data. +void ElementDecoration::ReleaseDecorators() +{ + for (size_t i = 0; i < decorators.size(); i++) + { + if (decorators[i].decorator_data) + decorators[i].decorator->ReleaseElementData(decorators[i].decorator_data); + } + + decorators.clear(); +} + + +void ElementDecoration::RenderDecorators() +{ + // @performance: Ignore dirty flag if e.g. pseudo classes do not affect the decorators + if (decorators_dirty) + { + decorators_dirty = false; + ReloadDecorators(); + } + + // Render the decorators attached to this element in its current state. + // Render from back to front for correct render order. + for (int i = (int)decorators.size() - 1; i >= 0; i--) + { + DecoratorHandle& decorator = decorators[i]; + decorator.decorator->RenderElement(element, decorator.decorator_data); + } +} + +void ElementDecoration::DirtyDecorators() +{ + decorators_dirty = true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementDecoration.h b/thirdparty/RmlUi/Source/Core/ElementDecoration.h new file mode 100644 index 000000000..83aea0de2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementDecoration.h @@ -0,0 +1,86 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTDECORATION_H +#define RMLUI_CORE_ELEMENTDECORATION_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class Decorator; +class Element; + +/** + Manages an elements decorator state + + @author Lloyd Weehuizen + */ + +class ElementDecoration +{ +public: + /// Constructor + /// @param element The element this decorator with acting on + ElementDecoration(Element* element); + ~ElementDecoration(); + + /// Renders all appropriate decorators. + void RenderDecorators(); + + /// Mark decorators as dirty and force them to reset themselves. + void DirtyDecorators(); + +private: + // Loads a single decorator and adds it to the list of loaded decorators for this element. + int LoadDecorator(SharedPtr decorator); + // Releases existing decorators and loads all decorators required by the element's definition. + bool ReloadDecorators(); + // Releases all existing decorators and frees their data. + void ReleaseDecorators(); + + struct DecoratorHandle + { + SharedPtr decorator; + DecoratorDataHandle decorator_data; + }; + + using DecoratorHandleList = Vector< DecoratorHandle >; + + // The element this decorator belongs to + Element* element; + + // The list of every decorator used by this element in every class. + DecoratorHandleList decorators; + + // If set, a full reload is necessary + bool decorators_dirty; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementDefinition.cpp b/thirdparty/RmlUi/Source/Core/ElementDefinition.cpp new file mode 100644 index 000000000..accfc4a8d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementDefinition.cpp @@ -0,0 +1,55 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementDefinition.h" +#include "StyleSheetNode.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" + +namespace Rml { + +ElementDefinition::ElementDefinition(const Vector< const StyleSheetNode* >& style_sheet_nodes) +{ + // Initialises the element definition from the list of style sheet nodes. + for (size_t i = 0; i < style_sheet_nodes.size(); ++i) + properties.Merge(style_sheet_nodes[i]->GetProperties()); + + for (auto& property : properties.GetProperties()) + property_ids.Insert(property.first); +} + +const Property* ElementDefinition::GetProperty(PropertyId id) const +{ + return properties.GetProperty(id); +} + +const PropertyIdSet& ElementDefinition::GetPropertyIds() const +{ + return property_ids; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementDefinition.h b/thirdparty/RmlUi/Source/Core/ElementDefinition.h new file mode 100644 index 000000000..990ea6f44 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementDefinition.h @@ -0,0 +1,68 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTDEFINITION_H +#define RMLUI_CORE_ELEMENTDEFINITION_H + +#include "../../Include/RmlUi/Core/PropertyDictionary.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../Include/RmlUi/Core/Traits.h" + +namespace Rml { + +class StyleSheetNode; +class ElementDefinitionIterator; + +/** + ElementDefinition provides an element's applicable properties from its stylesheet. + + @author Peter Curry + */ + +class ElementDefinition : public NonCopyMoveable +{ +public: + ElementDefinition(const Vector< const StyleSheetNode* >& style_sheet_nodes); + + /// Returns a specific property from the element definition. + /// @param[in] id The id of the property to return. + /// @return The property defined against the give name, or nullptr if no such property was found. + const Property* GetProperty(PropertyId id) const; + + /// Returns the list of property ids this element definition defines. + const PropertyIdSet& GetPropertyIds() const; + + const PropertyDictionary& GetProperties() const { return properties; } + +private: + PropertyDictionary properties; + PropertyIdSet property_ids; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementDocument.cpp b/thirdparty/RmlUi/Source/Core/ElementDocument.cpp new file mode 100644 index 000000000..6cd94608a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementDocument.cpp @@ -0,0 +1,586 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "DocumentHeader.h" +#include "ElementStyle.h" +#include "EventDispatcher.h" +#include "LayoutEngine.h" +#include "StreamFile.h" +#include "StyleSheetFactory.h" +#include "Template.h" +#include "TemplateCache.h" +#include "XMLParseTools.h" + +namespace Rml { + +ElementDocument::ElementDocument(const String& tag) : Element(tag) +{ + style_sheet = nullptr; + context = nullptr; + + modal = false; + layout_dirty = true; + + position_dirty = false; + + ForceLocalStackingContext(); + SetOwnerDocument(this); + + SetProperty(PropertyId::Position, Property(Style::Position::Absolute)); +} + +ElementDocument::~ElementDocument() +{ +} + +void ElementDocument::ProcessHeader(const DocumentHeader* document_header) +{ + RMLUI_ZoneScoped; + + // Store the source address that we came from + source_url = document_header->source; + + // Construct a new header and copy the template details across + DocumentHeader header; + header.MergePaths(header.template_resources, document_header->template_resources, document_header->source); + + // Merge in any templates, note a merge may cause more templates to merge + for (size_t i = 0; i < header.template_resources.size(); i++) + { + Template* merge_template = TemplateCache::LoadTemplate(URL(header.template_resources[i]).GetURL()); + + if (merge_template) + header.MergeHeader(*merge_template->GetHeader()); + else + Log::Message(Log::LT_WARNING, "Template %s not found", header.template_resources[i].c_str()); + } + + // Merge the document's header last, as it is the most overriding. + header.MergeHeader(*document_header); + + // Set the title to the document title. + title = document_header->title; + + // If a style-sheet (or sheets) has been specified for this element, then we load them and set the combined sheet + // on the element; all of its children will inherit it by default. + SharedPtr new_style_sheet; + if (header.rcss_external.size() > 0) + new_style_sheet = StyleSheetFactory::GetStyleSheet(header.rcss_external); + + // Combine any inline sheets. + if (header.rcss_inline.size() > 0) + { + for (size_t i = 0;i < header.rcss_inline.size(); i++) + { + UniquePtr inline_sheet = MakeUnique(); + auto stream = MakeUnique((const byte*) header.rcss_inline[i].c_str(), header.rcss_inline[i].size()); + stream->SetSourceURL(document_header->source); + + if (inline_sheet->LoadStyleSheet(stream.get(), header.rcss_inline_line_numbers[i])) + { + if (new_style_sheet) + { + SharedPtr combined_sheet = new_style_sheet->CombineStyleSheet(*inline_sheet); + new_style_sheet = combined_sheet; + } + else + new_style_sheet = std::move(inline_sheet); + } + + stream.reset(); + } + } + + // If a style sheet is available, set it on the document and release it. + if (new_style_sheet) + { + SetStyleSheet(std::move(new_style_sheet)); + } + + // Load external scripts. + for (size_t i = 0; i < header.scripts_external.size(); i++) + { + auto stream = MakeUnique(); + if (stream->Open(header.scripts_external[i])) + LoadScript(stream.get(), header.scripts_external[i]); + } + + // Load internal scripts. + for (size_t i = 0; i < header.scripts_inline.size(); i++) + { + auto stream = MakeUnique((const byte*) header.scripts_inline[i].c_str(), header.scripts_inline[i].size()); + LoadScript(stream.get(), ""); + } + + // Hide this document. + SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + + // Update properties so that e.g. visibility status can be queried properly immediately. + UpdateProperties(); +} + +// Returns the document's context. +Context* ElementDocument::GetContext() +{ + return context; +} + +// Sets the document's title. +void ElementDocument::SetTitle(const String& _title) +{ + title = _title; +} + +const String& ElementDocument::GetTitle() const +{ + return title; +} + +const String& ElementDocument::GetSourceURL() const +{ + return source_url; +} + +// Sets the style sheet this document, and all of its children, uses. +void ElementDocument::SetStyleSheet(SharedPtr _style_sheet) +{ + RMLUI_ZoneScoped; + + if (style_sheet == _style_sheet) + return; + + style_sheet = _style_sheet; + + if (style_sheet) + style_sheet->BuildNodeIndexAndOptimizeProperties(); + + GetStyle()->DirtyDefinition(); +} + +// Returns the document's style sheet. +const SharedPtr& ElementDocument::GetStyleSheet() const +{ + return style_sheet; +} + +// Brings the document to the front of the document stack. +void ElementDocument::PullToFront() +{ + if (context != nullptr) + context->PullDocumentToFront(this); +} + +// Sends the document to the back of the document stack. +void ElementDocument::PushToBack() +{ + if (context != nullptr) + context->PushDocumentToBack(this); +} + +void ElementDocument::Show(ModalFlag modal_flag, FocusFlag focus_flag) +{ + switch (modal_flag) + { + case ModalFlag::None: modal = false; break; + case ModalFlag::Modal: modal = true; break; + case ModalFlag::Keep: break; + } + + bool focus = false; + bool autofocus = false; + bool focus_previous = false; + + switch (focus_flag) + { + case FocusFlag::None: + break; + case FocusFlag::Document: + focus = true; + break; + case FocusFlag::Keep: + focus = true; + focus_previous = true; + break; + case FocusFlag::Auto: + focus = true; + autofocus = true; + break; + } + + // Set to visible and switch focus if necessary + SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + + // We should update the document now, otherwise the focusing methods below do not think we are visible + // If this turns out to be slow, the more performant approach is just to compute the new visibility property + UpdateDocument(); + + if (focus) + { + Element* focus_element = this; + + if (autofocus) + { + Element* first_element = nullptr; + Element* element = FindNextTabElement(this, true); + + while (element && element != first_element) + { + if (!first_element) + first_element = element; + + if (element->HasAttribute("autofocus")) + { + focus_element = element; + break; + } + + element = FindNextTabElement(element, true); + } + } + else if (focus_previous) + { + focus_element = GetFocusLeafNode(); + } + + // Focus the window or element + bool focused = focus_element->Focus(); + if (focused && focus_element != this) + focus_element->ScrollIntoView(false); + } + + DispatchEvent(EventId::Show, Dictionary()); +} + +void ElementDocument::Hide() +{ + SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + + // We should update the document now, so that the (un)focusing will get the correct visibility + UpdateDocument(); + + DispatchEvent(EventId::Hide, Dictionary()); + + if (context) + { + context->UnfocusDocument(this); + } +} + +// Close this document +void ElementDocument::Close() +{ + if (context != nullptr) + context->UnloadDocument(this); +} + +ElementPtr ElementDocument::CreateElement(const String& name) +{ + return Factory::InstanceElement(nullptr, name, name, XMLAttributes()); +} + +// Create a text element. +ElementPtr ElementDocument::CreateTextNode(const String& text) +{ + // Create the element. + ElementPtr element = CreateElement("#text"); + if (!element) + { + Log::Message(Log::LT_ERROR, "Failed to create text element, instancer returned nullptr."); + return nullptr; + } + + // Cast up + ElementText* element_text = rmlui_dynamic_cast< ElementText* >(element.get()); + if (!element_text) + { + Log::Message(Log::LT_ERROR, "Failed to create text element, instancer didn't return a derivative of ElementText."); + return nullptr; + } + + // Set the text + element_text->SetText(text); + + return element; +} + +// Is the current document modal +bool ElementDocument::IsModal() const +{ + return modal && IsVisible(); +} + +// Default load script implementation +void ElementDocument::LoadScript(Stream* RMLUI_UNUSED_PARAMETER(stream), const String& RMLUI_UNUSED_PARAMETER(source_name)) +{ + RMLUI_UNUSED(stream); + RMLUI_UNUSED(source_name); +} + +// Updates the document, including its layout +void ElementDocument::UpdateDocument() +{ + const float dp_ratio = (context ? context->GetDensityIndependentPixelRatio() : 1.0f); + Update(dp_ratio); + UpdateLayout(); + UpdatePosition(); +} + +// Updates the layout if necessary. +void ElementDocument::UpdateLayout() +{ + // Note: Carefully consider when to call this function for performance reasons. + // Ideally, only called once per update loop. + if(layout_dirty) + { + RMLUI_ZoneScoped; + RMLUI_ZoneText(source_url.c_str(), source_url.size()); + + layout_dirty = false; + + Vector2f containing_block(0, 0); + if (GetParentNode() != nullptr) + containing_block = GetParentNode()->GetBox().GetSize(); + + LayoutEngine layout_engine; + layout_engine.FormatElement(this, containing_block); + } +} + +// Updates the position of the document based on the style properties. +void ElementDocument::UpdatePosition() +{ + if(position_dirty) + { + RMLUI_ZoneScoped; + + position_dirty = false; + + Element* root = GetParentNode(); + + // We only position ourselves if we are a child of our context's root element. That is, we don't want to proceed if we are unparented or an iframe document. + if (!root || !context || (root != context->GetRootElement())) + return; + + Vector2f position; + // Work out our containing block; relative offsets are calculated against it. + Vector2f containing_block = root->GetBox().GetSize(Box::CONTENT); + + auto& computed = GetComputedValues(); + + if (computed.left.type != Style::Left::Auto) + position.x = ResolveValue(computed.left, containing_block.x); + else if (computed.right.type != Style::Right::Auto) + position.x = (containing_block.x - GetBox().GetSize(Box::MARGIN).x) - ResolveValue(computed.right, containing_block.x); + else + position.x = GetBox().GetEdge(Box::MARGIN, Box::LEFT); + + if (computed.top.type != Style::Top::Auto) + position.y = ResolveValue(computed.top, containing_block.y); + else if (computed.bottom.type != Style::Bottom::Auto) + position.y = (containing_block.y - GetBox().GetSize(Box::MARGIN).y) - ResolveValue(computed.bottom, containing_block.y); + else + position.y = GetBox().GetEdge(Box::MARGIN, Box::TOP); + + SetOffset(position, nullptr); + } +} + +void ElementDocument::DirtyPosition() +{ + position_dirty = true; +} + +void ElementDocument::DirtyLayout() +{ + layout_dirty = true; +} + +bool ElementDocument::IsLayoutDirty() +{ + return layout_dirty; +} + +void ElementDocument::DirtyDpProperties() +{ + GetStyle()->DirtyPropertiesWithUnitRecursive(Property::DP); +} + +// Repositions the document if necessary. +void ElementDocument::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + Element::OnPropertyChange(changed_properties); + + // If the document's font-size has been changed, we need to dirty all rem properties. + if (changed_properties.Contains(PropertyId::FontSize)) + GetStyle()->DirtyPropertiesWithUnitRecursive(Property::REM); + + if (changed_properties.Contains(PropertyId::Top) || + changed_properties.Contains(PropertyId::Right) || + changed_properties.Contains(PropertyId::Bottom) || + changed_properties.Contains(PropertyId::Left)) + DirtyPosition(); +} + +// Processes the 'onpropertychange' event, checking for a change in position or size. +void ElementDocument::ProcessDefaultAction(Event& event) +{ + Element::ProcessDefaultAction(event); + + // Process generic keyboard events for this window in bubble phase + if (event == EventId::Keydown) + { + int key_identifier = event.GetParameter("key_identifier", Input::KI_UNKNOWN); + + // Process TAB + if (key_identifier == Input::KI_TAB) + { + if (Element* element = FindNextTabElement(event.GetTargetElement(), !event.GetParameter("shift_key", false))) + { + if(element->Focus()) + element->ScrollIntoView(false); + } + } + // Process ENTER being pressed on a focusable object (emulate click) + else if (key_identifier == Input::KI_RETURN || + key_identifier == Input::KI_NUMPADENTER) + { + Element* focus_node = GetFocusLeafNode(); + + if (focus_node && focus_node->GetComputedValues().tab_index == Style::TabIndex::Auto) + { + focus_node->Click(); + } + } + } +} + +void ElementDocument::OnResize() +{ + DirtyPosition(); +} + + +// Find the next element to focus, starting at the current element +// +// This algorithm is quite sneaky, I originally thought a depth first search would +// work, but it appears not. What is required is to cut the tree in half along the nodes +// from current_element up the root and then either traverse the tree in a clockwise or +// anticlock wise direction depending if you're searching forward or backward respectively +Element* ElementDocument::FindNextTabElement(Element* current_element, bool forward) +{ + // If we're searching forward, check the immediate children of this node first off + if (forward) + { + for (int i = 0; i < current_element->GetNumChildren(); i++) + if (Element* result = SearchFocusSubtree(current_element->GetChild(i), forward)) + return result; + } + + // Now walk up the tree, testing either the bottom or top + // of the tree, depending on whether we're going forwards + // or backwards respectively + // + // If we make it all the way up to the document, then + // we search the entire tree (to loop back round) + bool search_enabled = false; + Element* document = current_element->GetOwnerDocument(); + Element* child = current_element; + Element* parent = current_element->GetParentNode(); + while (child != document) + { + for (int i = 0; i < parent->GetNumChildren(); i++) + { + // Calculate index into children + int child_index = i; + if (!forward) + child_index = parent->GetNumChildren() - i - 1; + Element* search_child = parent->GetChild(child_index); + + // Do a search if its enabled + if (search_enabled) + if(Element* result = SearchFocusSubtree(search_child, forward)) + return result; + + // If we find the child, enable searching + if (search_child == child) + search_enabled = true; + } + + // Advance up the tree + child = parent; + parent = parent->GetParentNode(); + + // If we hit the top, enable searching the entire tree + if (parent == document) + search_enabled = true; + else // otherwise enable searching if we're going backward and disable if we're going forward + search_enabled = false; + } + + return nullptr; +} + +Element* ElementDocument::SearchFocusSubtree(Element* element, bool forward) +{ + // Skip disabled elements + if (element->IsPseudoClassSet("disabled")) + { + return nullptr; + } + if (!element->IsVisible()) + { + return nullptr; + } + + // Check if this is the node we're looking for + if (element->GetComputedValues().tab_index == Style::TabIndex::Auto) + { + return element; + } + + // Check all children + for (int i = 0; i < element->GetNumChildren(); i++) + { + int child_index = i; + if (!forward) + child_index = element->GetNumChildren() - i - 1; + if (Element * result = SearchFocusSubtree(element->GetChild(child_index), forward)) + return result; + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementHandle.cpp b/thirdparty/RmlUi/Source/Core/ElementHandle.cpp new file mode 100644 index 000000000..dbb95f9ca --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementHandle.cpp @@ -0,0 +1,141 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementHandle.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Event.h" + +namespace Rml { + +ElementHandle::ElementHandle(const String& tag) : Element(tag), drag_start(0, 0) +{ + // Make sure we can be dragged! + SetProperty(PropertyId::Drag, Property(Style::Drag::Drag)); + + move_target = nullptr; + size_target = nullptr; + initialised = false; +} + +ElementHandle::~ElementHandle() +{ +} + +void ElementHandle::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + Element::OnAttributeChange(changed_attributes); + + // Reset initialised state if the move or size targets have changed. + if (changed_attributes.find("move_target") != changed_attributes.end() || + changed_attributes.find("size_target") != changed_attributes.end()) + { + initialised = false; + move_target = nullptr; + size_target = nullptr; + } +} + +void ElementHandle::ProcessDefaultAction(Event& event) +{ + Element::ProcessDefaultAction(event); + + if (event.GetTargetElement() == this) + { + // Lazy initialisation. + if (!initialised && GetOwnerDocument()) + { + String move_target_name = GetAttribute("move_target", ""); + if (!move_target_name.empty()) + move_target = GetElementById(move_target_name); + + String size_target_name = GetAttribute("size_target", ""); + if (!size_target_name.empty()) + size_target = GetElementById(size_target_name); + + initialised = true; + } + + if (event == EventId::Dragstart) + { + // Store the drag starting position + drag_start = event.GetUnprojectedMouseScreenPos(); + + // Store current element position and size + if (move_target) + { + move_original_position.x = move_target->GetOffsetLeft(); + move_original_position.y = move_target->GetOffsetTop(); + } + if (size_target) + size_original_size = size_target->GetBox().GetSize(Box::CONTENT); + } + else if (event == EventId::Drag) + { + // Work out the delta + Vector2f delta = event.GetUnprojectedMouseScreenPos() - drag_start; + + // Update the move and size objects + if (move_target) + { + move_target->SetProperty(PropertyId::Left, Property(Math::RoundFloat(move_original_position.x + delta.x), Property::PX)); + move_target->SetProperty(PropertyId::Top, Property(Math::RoundFloat(move_original_position.y + delta.y), Property::PX)); + } + + if (size_target) + { + using namespace Style; + const auto& computed = size_target->GetComputedValues(); + + // Check if we have auto-margins; if so, they have to be set to the current margins. + if (computed.margin_top.type == Margin::Auto) + size_target->SetProperty(PropertyId::MarginTop, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::TOP)), Property::PX)); + if (computed.margin_right.type == Margin::Auto) + size_target->SetProperty(PropertyId::MarginRight, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::RIGHT)), Property::PX)); + if (computed.margin_bottom.type == Margin::Auto) + size_target->SetProperty(PropertyId::MarginBottom, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM)), Property::PX)); + if (computed.margin_left.type == Margin::Auto) + size_target->SetProperty(PropertyId::MarginLeft, Property((float) Math::RealToInteger(size_target->GetBox().GetEdge(Box::MARGIN, Box::LEFT)), Property::PX)); + + float new_x = Math::RoundFloat(size_original_size.x + delta.x); + float new_y = Math::RoundFloat(size_original_size.y + delta.y); + + size_target->SetProperty(PropertyId::Width, Property(Math::Max< float >(new_x, 0.f), Property::PX)); + size_target->SetProperty(PropertyId::Height, Property(Math::Max< float >(new_y, 0.f), Property::PX)); + } + + Dictionary parameters; + parameters["handle_x"] = delta.x; + parameters["handle_y"] = delta.y; + DispatchEvent(EventId::Handledrag, parameters); + } + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementHandle.h b/thirdparty/RmlUi/Source/Core/ElementHandle.h new file mode 100644 index 000000000..401d2dde2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementHandle.h @@ -0,0 +1,68 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTHANDLE_H +#define RMLUI_CORE_ELEMENTHANDLE_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +/** + A derivation of an element for use as a mouse handle. A handle is designed to be instanced and attached as a non- + DOM element to a window-style element, and listened to for movement events which can be responsed to to move or + resize the element as appropriate. + + @author Peter Curry + */ + +class RMLUICORE_API ElementHandle : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementHandle, Element) + + ElementHandle(const String& tag); + virtual ~ElementHandle(); + +protected: + void OnAttributeChange(const ElementAttributes& changed_attributes) override; + void ProcessDefaultAction(Event& event) override; + + Vector2f drag_start; + Vector2f move_original_position; + Vector2f size_original_size; + + Element* move_target; + Element* size_target; + + bool initialised; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementInstancer.cpp b/thirdparty/RmlUi/Source/Core/ElementInstancer.cpp new file mode 100644 index 000000000..6ea92c145 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementInstancer.cpp @@ -0,0 +1,80 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ElementInstancer.h" +#include "XMLParseTools.h" +#include "Pool.h" +#include "ElementTextDefault.h" + +namespace Rml { + +ElementInstancer::~ElementInstancer() +{ +} + +static Pool< Element > pool_element(200, true); +static Pool< ElementTextDefault > pool_text_default(200, true); + + +ElementPtr ElementInstancerElement::InstanceElement(Element* /*parent*/, const String& tag, const XMLAttributes& /*attributes*/) +{ + Element* ptr = pool_element.AllocateAndConstruct(tag); + return ElementPtr(ptr); +} + +void ElementInstancerElement::ReleaseElement(Element* element) +{ + pool_element.DestroyAndDeallocate(element); +} + +ElementInstancerElement::~ElementInstancerElement() +{ + int num_elements = pool_element.GetNumAllocatedObjects(); + if (num_elements > 0) + { + Log::Message(Log::LT_WARNING, "--- Found %d leaked element(s) ---", num_elements); + + for (auto it = pool_element.Begin(); it; ++it) + Log::Message(Log::LT_WARNING, " %s", it->GetAddress().c_str()); + + Log::Message(Log::LT_WARNING, "------"); + } +} + +ElementPtr ElementInstancerTextDefault::InstanceElement(Element* /*parent*/, const String& tag, const XMLAttributes& /*attributes*/) +{ + ElementTextDefault* ptr = pool_text_default.AllocateAndConstruct(tag); + return ElementPtr(static_cast(ptr)); +} + +void ElementInstancerTextDefault::ReleaseElement(Element* element) +{ + pool_text_default.DestroyAndDeallocate(static_cast(element)); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementScroll.cpp b/thirdparty/RmlUi/Source/Core/ElementScroll.cpp new file mode 100644 index 000000000..8d657b8e3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementScroll.cpp @@ -0,0 +1,284 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ElementScroll.h" +#include "LayoutEngine.h" +#include "WidgetScroll.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/Factory.h" + +namespace Rml { + +ElementScroll::ElementScroll(Element* _element) +{ + element = _element; + corner = nullptr; +} + +ElementScroll::~ElementScroll() +{ + ClearScrollbars(); +} + +void ElementScroll::ClearScrollbars() +{ + for (int i = 0; i < 2; i++) + { + if (scrollbars[i].element != nullptr) + { + scrollbars[i] = Scrollbar(); + } + } + + if (corner != nullptr) + { + corner->GetParentNode()->RemoveChild(element); + corner = nullptr; + } +} + +// Updates the increment / decrement arrows. +void ElementScroll::Update() +{ + for (int i = 0; i < 2; i++) + { + if (scrollbars[i].widget != nullptr) + scrollbars[i].widget->Update(); + } +} + +// Enables and sizes one of the scrollbars. +void ElementScroll::EnableScrollbar(Orientation orientation, float element_width) +{ + if (!scrollbars[orientation].enabled) + { + CreateScrollbar(orientation); + scrollbars[orientation].element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + scrollbars[orientation].enabled = true; + } + + // Determine the size of the scrollbar. + Box box; + LayoutEngine::BuildBox(box, Vector2f(element_width, element_width), scrollbars[orientation].element); + + if (orientation == VERTICAL) + scrollbars[orientation].size = box.GetSize(Box::MARGIN).x; + if (orientation == HORIZONTAL) + { + if (box.GetSize().y < 0) + scrollbars[orientation].size = box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + + box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT) + + ResolveValue(scrollbars[orientation].element->GetComputedValues().height, element_width); + else + scrollbars[orientation].size = box.GetSize(Box::MARGIN).y; + } +} + +// Disables and hides one of the scrollbars. +void ElementScroll::DisableScrollbar(Orientation orientation) +{ + if (scrollbars[orientation].enabled) + { + scrollbars[orientation].element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + scrollbars[orientation].enabled = false; + } +} + +// Updates the position of the scrollbar. +void ElementScroll::UpdateScrollbar(Orientation orientation) +{ + float bar_position; + float traversable_track; + if (orientation == VERTICAL) + { + bar_position = element->GetScrollTop(); + traversable_track = element->GetScrollHeight() - element->GetClientHeight(); + } + else + { + bar_position = element->GetScrollLeft(); + traversable_track = element->GetScrollWidth() - element->GetClientWidth(); + } + + if (traversable_track <= 0) + bar_position = 0; + else + bar_position /= traversable_track; + + if (scrollbars[orientation].widget != nullptr) + { + bar_position = Math::Clamp(bar_position, 0.0f, 1.0f); + + if (scrollbars[orientation].widget->GetBarPosition() != bar_position) + scrollbars[orientation].widget->SetBarPosition(bar_position); + } +} + +// Returns one of the scrollbar elements. +Element* ElementScroll::GetScrollbar(Orientation orientation) +{ + return scrollbars[orientation].element; +} + +// Returns the size, in pixels, of one of the scrollbars; for a vertical scrollbar, this is width, for a horizontal scrollbar, this is height. +float ElementScroll::GetScrollbarSize(Orientation orientation) +{ + if (!scrollbars[orientation].enabled) + return 0; + + return scrollbars[orientation].size; +} + +// Formats the enabled scrollbars based on the current size of the host element. +void ElementScroll::FormatScrollbars() +{ + Vector2f containing_block = element->GetBox().GetSize(Box::PADDING); + + for (int i = 0; i < 2; i++) + { + if (!scrollbars[i].enabled) + continue; + + if (i == VERTICAL) + { + scrollbars[i].widget->SetBarLength(element->GetClientHeight()); + scrollbars[i].widget->SetTrackLength(element->GetScrollHeight()); + + float traversable_track = element->GetScrollHeight() - element->GetClientHeight(); + if (traversable_track > 0) + scrollbars[i].widget->SetBarPosition(element->GetScrollTop() / traversable_track); + else + scrollbars[i].widget->SetBarPosition(0); + } + else + { + scrollbars[i].widget->SetBarLength(element->GetClientWidth()); + scrollbars[i].widget->SetTrackLength(element->GetScrollWidth()); + + float traversable_track = element->GetScrollWidth() - element->GetClientWidth(); + if (traversable_track > 0) + scrollbars[i].widget->SetBarPosition(element->GetScrollLeft() / traversable_track); + else + scrollbars[i].widget->SetBarPosition(0); + } + + float slider_length = containing_block[1 - i]; + float user_scrollbar_margin = scrollbars[i].element->GetComputedValues().scrollbar_margin; + float min_scrollbar_margin = GetScrollbarSize(i == VERTICAL ? HORIZONTAL : VERTICAL); + slider_length -= Math::Max(user_scrollbar_margin, min_scrollbar_margin); + + scrollbars[i].widget->FormatElements(containing_block, slider_length); + scrollbars[i].widget->SetLineHeight(element->GetLineHeight()); + + int variable_axis = i == VERTICAL ? 0 : 1; + Vector2f offset = element->GetBox().GetPosition(Box::PADDING); + offset[variable_axis] += containing_block[variable_axis] - (scrollbars[i].element->GetBox().GetSize(Box::BORDER)[variable_axis] + scrollbars[i].element->GetBox().GetEdge(Box::MARGIN, i == VERTICAL ? Box::RIGHT : Box::BOTTOM)); + // Add the top or left margin (as appropriate) onto the scrollbar's position. + offset[1 - variable_axis] += scrollbars[i].element->GetBox().GetEdge(Box::MARGIN, i == VERTICAL ? Box::TOP : Box::LEFT); + scrollbars[i].element->SetOffset(offset, element, true); + } + + // Format the corner, if it is necessary. + if (scrollbars[0].enabled && + scrollbars[1].enabled) + { + CreateCorner(); + + Box corner_box; + corner_box.SetContent(Vector2f(scrollbars[VERTICAL].size, scrollbars[HORIZONTAL].size)); + corner->SetBox(corner_box); + corner->SetOffset(containing_block - Vector2f(scrollbars[VERTICAL].size, scrollbars[HORIZONTAL].size), element, true); + + corner->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + } + else + { + if (corner != nullptr) + corner->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + } +} + + +// Creates one of the scroll component's scrollbar. +bool ElementScroll::CreateScrollbar(Orientation orientation) +{ + if (scrollbars[orientation].element && + scrollbars[orientation].widget) + return true; + + ElementPtr scrollbar_element = Factory::InstanceElement(element, "*", orientation == VERTICAL ? "scrollbarvertical" : "scrollbarhorizontal", XMLAttributes()); + scrollbars[orientation].element = scrollbar_element.get(); + scrollbars[orientation].element->SetProperty(PropertyId::Clip, Property(1, Property::NUMBER)); + + scrollbars[orientation].widget = new WidgetScroll(scrollbars[orientation].element); + scrollbars[orientation].widget->Initialise(orientation == VERTICAL ? WidgetScroll::VERTICAL : WidgetScroll::HORIZONTAL); + + Element* child = element->AppendChild(std::move(scrollbar_element), false); + + // The construction of scrollbars can occur during layouting, then we need some properties and computed values straight away. + child->UpdateProperties(); + + return true; +} + +// Creates the scrollbar corner. +bool ElementScroll::CreateCorner() +{ + if (corner != nullptr) + return true; + + ElementPtr corner_element = Factory::InstanceElement(element, "*", "scrollbarcorner", XMLAttributes()); + corner = corner_element.get(); + element->AppendChild(std::move(corner_element), false); + + return true; +} + +ElementScroll::Scrollbar::Scrollbar() +{ + element = nullptr; + widget = nullptr; + enabled = false; + size = 0; +} + +ElementScroll::Scrollbar::~Scrollbar() +{ + if (widget != nullptr) + delete widget; + + if (element != nullptr) + { + if (element->GetParentNode() != nullptr) + element->GetParentNode()->RemoveChild(element); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementStyle.cpp b/thirdparty/RmlUi/Source/Core/ElementStyle.cpp new file mode 100644 index 000000000..c65140c49 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementStyle.cpp @@ -0,0 +1,913 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementStyle.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/Math.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/PropertyDictionary.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" +#include "ElementBackground.h" +#include "ElementBorder.h" +#include "ElementDecoration.h" +#include "ElementDefinition.h" +#include "ComputeProperty.h" +#include "PropertiesIterator.h" +#include + + +namespace Rml { + +ElementStyle::ElementStyle(Element* _element) +{ + definition = nullptr; + element = _element; + + definition_dirty = true; +} + +const ElementDefinition* ElementStyle::GetDefinition() const +{ + return definition.get(); +} + +// Returns one of this element's properties. +const Property* ElementStyle::GetLocalProperty(PropertyId id, const PropertyDictionary& inline_properties, const ElementDefinition* definition) +{ + // Check for overriding local properties. + const Property* property = inline_properties.GetProperty(id); + if (property) + return property; + + // Check for a property defined in an RCSS rule. + if (definition) + return definition->GetProperty(id); + + return nullptr; +} + +// Returns one of this element's properties. +const Property* ElementStyle::GetProperty(PropertyId id, const Element* element, const PropertyDictionary& inline_properties, const ElementDefinition* definition) +{ + const Property* local_property = GetLocalProperty(id, inline_properties, definition); + if (local_property) + return local_property; + + // Fetch the property specification. + const PropertyDefinition* property = StyleSheetSpecification::GetProperty(id); + if (!property) + return nullptr; + + // If we can inherit this property, return our parent's property. + if (property->IsInherited()) + { + Element* parent = element->GetParentNode(); + while (parent) + { + const Property* parent_property = parent->GetStyle()->GetLocalProperty(id); + if (parent_property) + return parent_property; + + parent = parent->GetParentNode(); + } + } + + // No property available! Return the default value. + return property->GetDefaultValue(); +} + +// Apply transition to relevant properties if a transition is defined on element. +// Properties that are part of a transition are removed from the properties list. +void ElementStyle::TransitionPropertyChanges(Element* element, PropertyIdSet& properties, const PropertyDictionary& inline_properties, const ElementDefinition* old_definition, const ElementDefinition* new_definition) +{ + RMLUI_ASSERT(element); + if (!old_definition || !new_definition || properties.Empty()) + return; + + // We get the local property instead of the computed value here, because we want to intercept property changes even before the computed values are ready. + // Now that we have the concept of computed values, we may want do this operation directly on them instead. + if (const Property* transition_property = GetLocalProperty(PropertyId::Transition, inline_properties, new_definition)) + { + auto transition_list = transition_property->Get(); + + if (!transition_list.none) + { + static const PropertyDictionary empty_properties; + + auto add_transition = [&](const Transition& transition) { + bool transition_added = false; + const Property* start_value = GetProperty(transition.id, element, inline_properties, old_definition); + const Property* target_value = GetProperty(transition.id, element, empty_properties, new_definition); + if (start_value && target_value && (*start_value != *target_value)) + transition_added = element->StartTransition(transition, *start_value, *target_value); + return transition_added; + }; + + if (transition_list.all) + { + Transition transition = transition_list.transitions[0]; + for (auto it = properties.begin(); it != properties.end(); ) + { + transition.id = *it; + if (add_transition(transition)) + it = properties.Erase(it); + else + ++it; + } + } + else + { + for (auto& transition : transition_list.transitions) + { + if (properties.Contains(transition.id)) + { + if (add_transition(transition)) + properties.Erase(transition.id); + } + } + } + } + } +} + +void ElementStyle::UpdateDefinition() +{ + if (definition_dirty) + { + RMLUI_ZoneScoped; + + definition_dirty = false; + + SharedPtr new_definition; + + if (auto& style_sheet = element->GetStyleSheet()) + { + new_definition = style_sheet->GetElementDefinition(element); + } + + // Switch the property definitions if the definition has changed. + if (new_definition != definition) + { + PropertyIdSet changed_properties; + + if (definition) + changed_properties = definition->GetPropertyIds(); + + if (new_definition) + changed_properties |= new_definition->GetPropertyIds(); + + if (definition && new_definition) + { + // Remove properties that compare equal from the changed list. + const PropertyIdSet properties_in_both_definitions = (definition->GetPropertyIds() & new_definition->GetPropertyIds()); + + for (PropertyId id : properties_in_both_definitions) + { + const Property* p0 = definition->GetProperty(id); + const Property* p1 = new_definition->GetProperty(id); + if (p0 && p1 && *p0 == *p1) + changed_properties.Erase(id); + } + + // Transition changed properties if transition property is set + TransitionPropertyChanges(element, changed_properties, inline_properties, definition.get(), new_definition.get()); + } + + definition = new_definition; + + DirtyProperties(changed_properties); + } + + // Even if the definition was not changed, the child definitions may have changed as a result of anything that + // could change the definition of this element, such as a new pseudo class. + DirtyChildDefinitions(); + } +} + + + +// Sets or removes a pseudo-class on the element. +void ElementStyle::SetPseudoClass(const String& pseudo_class, bool activate) +{ + bool changed = false; + + if (activate) + changed = pseudo_classes.insert(pseudo_class).second; + else + changed = (pseudo_classes.erase(pseudo_class) == 1); + + if (changed) + { + DirtyDefinition(); + } +} + +// Checks if a specific pseudo-class has been set on the element. +bool ElementStyle::IsPseudoClassSet(const String& pseudo_class) const +{ + return (pseudo_classes.count(pseudo_class) == 1); +} + +const PseudoClassList& ElementStyle::GetActivePseudoClasses() const +{ + return pseudo_classes; +} + +// Sets or removes a class on the element. +void ElementStyle::SetClass(const String& class_name, bool activate) +{ + StringList::iterator class_location = std::find(classes.begin(), classes.end(), class_name); + + if (activate) + { + if (class_location == classes.end()) + { + classes.push_back(class_name); + DirtyDefinition(); + } + } + else + { + if (class_location != classes.end()) + { + classes.erase(class_location); + DirtyDefinition(); + } + } +} + +// Checks if a class is set on the element. +bool ElementStyle::IsClassSet(const String& class_name) const +{ + return std::find(classes.begin(), classes.end(), class_name) != classes.end(); +} + +// Specifies the entire list of classes for this element. This will replace any others specified. +void ElementStyle::SetClassNames(const String& class_names) +{ + classes.clear(); + StringUtilities::ExpandString(classes, class_names, ' '); + DirtyDefinition(); +} + +// Returns the list of classes specified for this element. +String ElementStyle::GetClassNames() const +{ + String class_names; + for (size_t i = 0; i < classes.size(); i++) + { + if (i != 0) + { + class_names += " "; + } + class_names += classes[i]; + } + + return class_names; +} + +// Sets a local property override on the element to a pre-parsed value. +bool ElementStyle::SetProperty(PropertyId id, const Property& property) +{ + Property new_property = property; + + new_property.definition = StyleSheetSpecification::GetProperty(id); + if (!new_property.definition) + return false; + + inline_properties.SetProperty(id, new_property); + DirtyProperty(id); + + return true; +} + +// Removes a local property override on the element. +void ElementStyle::RemoveProperty(PropertyId id) +{ + int size_before = inline_properties.GetNumProperties(); + inline_properties.RemoveProperty(id); + + if(inline_properties.GetNumProperties() != size_before) + DirtyProperty(id); +} + + + +// Returns one of this element's properties. +const Property* ElementStyle::GetProperty(PropertyId id) const +{ + return GetProperty(id, element, inline_properties, definition.get()); +} + +// Returns one of this element's properties. +const Property* ElementStyle::GetLocalProperty(PropertyId id) const +{ + return GetLocalProperty(id, inline_properties, definition.get()); +} + +const PropertyMap& ElementStyle::GetLocalStyleProperties() const +{ + return inline_properties.GetProperties(); +} + +float ElementStyle::ResolveNumericProperty(const Property* property, float base_value) const +{ + if (!property || !(property->unit & (Property::NUMBER_LENGTH_PERCENT | Property::ANGLE))) + return 0.0f; + + if (property->unit & Property::NUMBER) + return property->Get() * base_value; + else if (property->unit & Property::PERCENT) + return property->Get() * base_value * 0.01f; + else if (property->unit & Property::ANGLE) + return ComputeAngle(*property); + + const float dp_ratio = ElementUtilities::GetDensityIndependentPixelRatio(element); + const float font_size = element->GetComputedValues().font_size; + + auto doc = element->GetOwnerDocument(); + const float doc_font_size = (doc ? doc->GetComputedValues().font_size : DefaultComputedValues.font_size); + + float result = ComputeLength(property, font_size, doc_font_size, dp_ratio); + + return result; +} + +float ElementStyle::ResolveLength(const Property* property, RelativeTarget relative_target) const +{ + RMLUI_ASSERT(property); + + // There is an exception on font-size properties, as 'em' units here refer to parent font size instead + if ((property->unit & Property::LENGTH) && !(property->unit == Property::EM && relative_target == RelativeTarget::ParentFontSize)) + { + auto doc = element->GetOwnerDocument(); + const float doc_font_size = (doc ? doc->GetComputedValues().font_size : DefaultComputedValues.font_size); + + float result = ComputeLength(property, element->GetComputedValues().font_size, doc_font_size, ElementUtilities::GetDensityIndependentPixelRatio(element)); + + return result; + } + + float base_value = 0.0f; + + switch (relative_target) + { + case RelativeTarget::None: + base_value = 1.0f; + break; + case RelativeTarget::ContainingBlockWidth: + base_value = element->GetContainingBlock().x; + break; + case RelativeTarget::ContainingBlockHeight: + base_value = element->GetContainingBlock().y; + break; + case RelativeTarget::FontSize: + base_value = element->GetComputedValues().font_size; + break; + case RelativeTarget::ParentFontSize: + { + auto p = element->GetParentNode(); + base_value = (p ? p->GetComputedValues().font_size : DefaultComputedValues.font_size); + } + break; + case RelativeTarget::LineHeight: + base_value = element->GetLineHeight(); + break; + default: + break; + } + + float scale_value = 0.0f; + + switch (property->unit) + { + case Property::EM: + case Property::NUMBER: + scale_value = property->value.Get< float >(); + break; + case Property::PERCENT: + scale_value = property->value.Get< float >() * 0.01f; + break; + default: + break; + } + + return base_value * scale_value; +} + +void ElementStyle::DirtyDefinition() +{ + definition_dirty = true; +} + +void ElementStyle::DirtyInheritedProperties() +{ + dirty_properties |= StyleSheetSpecification::GetRegisteredInheritedProperties(); +} + +void ElementStyle::DirtyChildDefinitions() +{ + for (int i = 0; i < element->GetNumChildren(true); i++) + element->GetChild(i)->GetStyle()->DirtyDefinition(); +} + +void ElementStyle::DirtyPropertiesWithUnitRecursive(Property::Unit unit) +{ + // Dirty all the properties of this element that use the unit. + for (auto it = Iterate(); !it.AtEnd(); ++it) + { + auto name_property_pair = *it; + PropertyId id = name_property_pair.first; + const Property& property = name_property_pair.second; + if (property.unit == unit) + DirtyProperty(id); + } + + // Now dirty all of our descendant's properties that use the unit. + int num_children = element->GetNumChildren(true); + for (int i = 0; i < num_children; ++i) + element->GetChild(i)->GetStyle()->DirtyPropertiesWithUnitRecursive(unit); +} + +bool ElementStyle::AnyPropertiesDirty() const +{ + return !dirty_properties.Empty(); +} + +PropertiesIterator ElementStyle::Iterate() const { + // Note: Value initialized iterators are only guaranteed to compare equal in C++14, and only for iterators satisfying the ForwardIterator requirements. +#ifdef _MSC_VER + // Null forward iterator supported since VS 2015 + static_assert(_MSC_VER >= 1900, "Visual Studio 2015 or higher required, see comment."); +#else + static_assert(__cplusplus >= 201402L, "C++14 or higher required, see comment."); +#endif + + const PropertyMap& property_map = inline_properties.GetProperties(); + auto it_style_begin = property_map.begin(); + auto it_style_end = property_map.end(); + + PropertyMap::const_iterator it_definition{}, it_definition_end{}; + if (definition) + { + const PropertyMap& definition_properties = definition->GetProperties().GetProperties(); + it_definition = definition_properties.begin(); + it_definition_end = definition_properties.end(); + } + return PropertiesIterator(it_style_begin, it_style_end, it_definition, it_definition_end); +} + +// Sets a single property as dirty. +void ElementStyle::DirtyProperty(PropertyId id) +{ + dirty_properties.Insert(id); +} + +// Sets a list of properties as dirty. +void ElementStyle::DirtyProperties(const PropertyIdSet& properties) +{ + dirty_properties |= properties; +} + +PropertyIdSet ElementStyle::ComputeValues(Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, bool values_are_default_initialized, float dp_ratio) +{ + if (dirty_properties.Empty()) + return PropertyIdSet(); + + RMLUI_ZoneScopedC(0xFF7F50); + + // Generally, this is how it works: + // 1. Assign default values (clears any removed properties) + // 2. Inherit inheritable values from parent + // 3. Assign any local properties (from inline style or stylesheet) + // 4. Dirty properties in children that are inherited + + const float font_size_before = values.font_size; + const Style::LineHeight line_height_before = values.line_height; + + // The next flag is just a small optimization, if the element was just created we don't need to copy all the default values. + if (!values_are_default_initialized) + { + // This needs to be done in case some properties were removed and thus not in our local style anymore. + // If we skipped this, the old dirty value would be unmodified, instead, now it is set to its default value. + // Strictly speaking, we only really need to do this for the dirty values, and only non-inherited. However, + // it seems assigning the whole thing is faster in most cases. + values = DefaultComputedValues; + } + + bool dirty_em_properties = false; + + // Always do font-size first if dirty, because of em-relative values + if(dirty_properties.Contains(PropertyId::FontSize)) + { + if (auto p = GetLocalProperty(PropertyId::FontSize)) + values.font_size = ComputeFontsize(*p, values, parent_values, document_values, dp_ratio); + else if (parent_values) + values.font_size = parent_values->font_size; + + if (font_size_before != values.font_size) + { + dirty_em_properties = true; + dirty_properties.Insert(PropertyId::LineHeight); + } + } + else + { + values.font_size = font_size_before; + } + + const float font_size = values.font_size; + const float document_font_size = (document_values ? document_values->font_size : DefaultComputedValues.font_size); + + + // Since vertical-align depends on line-height we compute this before iteration + if(dirty_properties.Contains(PropertyId::LineHeight)) + { + if (auto p = GetLocalProperty(PropertyId::LineHeight)) + { + values.line_height = ComputeLineHeight(p, font_size, document_font_size, dp_ratio); + } + else if (parent_values) + { + // Line height has a special inheritance case for numbers/percent: they inherit them directly instead of computed length, but for lengths, they inherit the length. + // See CSS specs for details. Percent is already converted to number. + if (parent_values->line_height.inherit_type == Style::LineHeight::Number) + values.line_height = Style::LineHeight(font_size * parent_values->line_height.inherit_value, Style::LineHeight::Number, parent_values->line_height.inherit_value); + else + values.line_height = parent_values->line_height; + } + + if(line_height_before.value != values.line_height.value || line_height_before.inherit_value != values.line_height.inherit_value) + dirty_properties.Insert(PropertyId::VerticalAlign); + } + else + { + values.line_height = line_height_before; + } + + + if (parent_values) + { + // Inherited properties are copied here, but may be overwritten below by locally defined properties + // Line-height and font-size are computed above + values.clip = parent_values->clip; + + values.color = parent_values->color; + values.opacity = parent_values->opacity; + + values.font_family = parent_values->font_family; + values.font_style = parent_values->font_style; + values.font_weight = parent_values->font_weight; + values.font_face_handle = parent_values->font_face_handle; + + values.text_align = parent_values->text_align; + values.text_decoration = parent_values->text_decoration; + values.text_transform = parent_values->text_transform; + values.white_space = parent_values->white_space; + + values.cursor = parent_values->cursor; + values.focus = parent_values->focus; + + values.pointer_events = parent_values->pointer_events; + + values.font_effect = parent_values->font_effect; + } + + + for (auto it = Iterate(); !it.AtEnd(); ++it) + { + auto name_property_pair = *it; + const PropertyId id = name_property_pair.first; + const Property* p = &name_property_pair.second; + + if (dirty_em_properties && p->unit == Property::EM) + dirty_properties.Insert(id); + + using namespace Style; + + switch (id) + { + case PropertyId::MarginTop: + values.margin_top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MarginRight: + values.margin_right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MarginBottom: + values.margin_bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MarginLeft: + values.margin_left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::PaddingTop: + values.padding_top = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::PaddingRight: + values.padding_right = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::PaddingBottom: + values.padding_bottom = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::PaddingLeft: + values.padding_left = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::BorderTopWidth: + values.border_top_width = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::BorderRightWidth: + values.border_right_width = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::BorderBottomWidth: + values.border_bottom_width = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::BorderLeftWidth: + values.border_left_width = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::BorderTopColor: + values.border_top_color = p->Get(); + break; + case PropertyId::BorderRightColor: + values.border_right_color = p->Get(); + break; + case PropertyId::BorderBottomColor: + values.border_bottom_color = p->Get(); + break; + case PropertyId::BorderLeftColor: + values.border_left_color = p->Get(); + break; + + case PropertyId::Display: + values.display = (Display)p->Get(); + break; + case PropertyId::Position: + values.position = (Position)p->Get(); + break; + + case PropertyId::Top: + values.top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::Right: + values.right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::Bottom: + values.bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::Left: + values.left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::Float: + values.float_ = (Float)p->Get(); + break; + case PropertyId::Clear: + values.clear = (Clear)p->Get(); + break; + + case PropertyId::ZIndex: + values.z_index = (p->unit == Property::KEYWORD ? ZIndex(ZIndex::Auto) : ZIndex(ZIndex::Number, p->Get())); + break; + + case PropertyId::Width: + values.width = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MinWidth: + values.min_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MaxWidth: + values.max_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::Height: + values.height = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MinHeight: + values.min_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::MaxHeight: + values.max_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::LineHeight: + // (Line-height computed above) + break; + case PropertyId::VerticalAlign: + values.vertical_align = ComputeVerticalAlign(p, values.line_height.value, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::OverflowX: + values.overflow_x = (Overflow)p->Get< int >(); + break; + case PropertyId::OverflowY: + values.overflow_y = (Overflow)p->Get< int >(); + break; + case PropertyId::Clip: + values.clip = ComputeClip(p); + break; + case PropertyId::Visibility: + values.visibility = (Visibility)p->Get< int >(); + break; + + case PropertyId::BackgroundColor: + values.background_color = p->Get(); + break; + case PropertyId::Color: + values.color = p->Get(); + break; + case PropertyId::ImageColor: + values.image_color = p->Get(); + break; + case PropertyId::Opacity: + values.opacity = p->Get(); + break; + + case PropertyId::FontFamily: + values.font_family = StringUtilities::ToLower(p->Get()); + values.font_face_handle = 0; + break; + case PropertyId::FontStyle: + values.font_style = (FontStyle)p->Get< int >(); + values.font_face_handle = 0; + break; + case PropertyId::FontWeight: + values.font_weight = (FontWeight)p->Get< int >(); + values.font_face_handle = 0; + break; + case PropertyId::FontSize: + // (font-size computed above) + values.font_face_handle = 0; + break; + + case PropertyId::TextAlign: + values.text_align = (TextAlign)p->Get< int >(); + break; + case PropertyId::TextDecoration: + values.text_decoration = (TextDecoration)p->Get< int >(); + break; + case PropertyId::TextTransform: + values.text_transform = (TextTransform)p->Get< int >(); + break; + case PropertyId::WhiteSpace: + values.white_space = (WhiteSpace)p->Get< int >(); + break; + + case PropertyId::Cursor: + values.cursor = p->Get< String >(); + break; + + case PropertyId::Drag: + values.drag = (Drag)p->Get< int >(); + break; + case PropertyId::TabIndex: + values.tab_index = (TabIndex)p->Get< int >(); + break; + case PropertyId::Focus: + values.focus = (Focus)p->Get(); + break; + case PropertyId::ScrollbarMargin: + values.scrollbar_margin = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::PointerEvents: + values.pointer_events = (PointerEvents)p->Get(); + break; + + case PropertyId::Perspective: + values.perspective = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::PerspectiveOriginX: + values.perspective_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::PerspectiveOriginY: + values.perspective_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::Transform: + values.transform = p->Get(); + break; + case PropertyId::TransformOriginX: + values.transform_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::TransformOriginY: + values.transform_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio); + break; + case PropertyId::TransformOriginZ: + values.transform_origin_z = ComputeLength(p, font_size, document_font_size, dp_ratio); + break; + + case PropertyId::Transition: + values.transition = p->Get(); + break; + case PropertyId::Animation: + values.animation = p->Get(); + break; + + case PropertyId::Decorator: + if (p->unit == Property::DECORATOR) + { + values.decorator = p->Get(); + } + else if (p->unit == Property::STRING) + { + // Usually the decorator is converted from string after the style sheet is set on the ElementDocument. However, if the + // user sets a decorator on the element's style, we may still get a string here which must be parsed and instanced. + if (auto & style_sheet = element->GetStyleSheet()) + { + String value = p->Get(); + values.decorator = style_sheet->InstanceDecoratorsFromString(value, p->source); + } + else + values.decorator.reset(); + } + else + values.decorator.reset(); + break; + case PropertyId::FontEffect: + if (p->unit == Property::FONTEFFECT) + { + values.font_effect = p->Get(); + } + else if (p->unit == Property::STRING) + { + if (auto & style_sheet = element->GetStyleSheet()) + { + String value = p->Get(); + values.font_effect = style_sheet->InstanceFontEffectsFromString(value, p->source); + } + else + values.font_effect.reset(); + } + else + values.font_effect.reset(); + break; + // Unhandled properties. Must be manually retrieved with 'GetProperty()'. + case PropertyId::FillImage: + break; + // Invalid properties + case PropertyId::Invalid: + case PropertyId::NumDefinedIds: + case PropertyId::MaxNumIds: + break; + } + } + + // The font-face handle is nulled when local font properties are set. In that case we need to retrieve a new handle. + if (!values.font_face_handle) + { + RMLUI_ZoneScopedN("FontFaceHandle"); + values.font_face_handle = GetFontEngineInterface()->GetFontFaceHandle(values.font_family, values.font_style, values.font_weight, (int)values.font_size); + } + + // Next, pass inheritable dirty properties onto our children + PropertyIdSet dirty_inherited_properties = (dirty_properties & StyleSheetSpecification::GetRegisteredInheritedProperties()); + + if (!dirty_inherited_properties.Empty()) + { + for (int i = 0; i < element->GetNumChildren(true); i++) + { + auto child = element->GetChild(i); + child->GetStyle()->dirty_properties |= dirty_inherited_properties; + } + } + + PropertyIdSet result(std::move(dirty_properties)); + dirty_properties.Clear(); + return result; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementStyle.h b/thirdparty/RmlUi/Source/Core/ElementStyle.h new file mode 100644 index 000000000..a52f44d52 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementStyle.h @@ -0,0 +1,170 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTSTYLE_H +#define RMLUI_CORE_ELEMENTSTYLE_H + +#include "../../Include/RmlUi/Core/ComputedValues.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../Include/RmlUi/Core/PropertyDictionary.h" + +namespace Rml { + +class ElementDefinition; +class PropertiesIterator; +enum class RelativeTarget; + +/** + Manages an element's style and property information. + @author Lloyd Weehuizen + */ + +class ElementStyle +{ +public: + /// Constructor + /// @param[in] element The element this structure belongs to. + ElementStyle(Element* element); + + /// Returns the element's definition. + const ElementDefinition* GetDefinition() const; + + /// Update this definition if required + void UpdateDefinition(); + + /// Sets or removes a pseudo-class on the element. + /// @param[in] pseudo_class The pseudo class to activate or deactivate. + /// @param[in] activate True if the pseudo-class is to be activated, false to be deactivated. + void SetPseudoClass(const String& pseudo_class, bool activate); + /// Checks if a specific pseudo-class has been set on the element. + /// @param[in] pseudo_class The name of the pseudo-class to check for. + /// @return True if the pseudo-class is set on the element, false if not. + bool IsPseudoClassSet(const String& pseudo_class) const; + /// Gets a list of the current active pseudo classes + const PseudoClassList& GetActivePseudoClasses() const; + + /// Sets or removes a class on the element. + /// @param[in] class_name The name of the class to add or remove from the class list. + /// @param[in] activate True if the class is to be added, false to be removed. + void SetClass(const String& class_name, bool activate); + /// Checks if a class is set on the element. + /// @param[in] class_name The name of the class to check for. + /// @return True if the class is set on the element, false otherwise. + bool IsClassSet(const String& class_name) const; + /// Specifies the entire list of classes for this element. This will replace any others specified. + /// @param[in] class_names The list of class names to set on the style, separated by spaces. + void SetClassNames(const String& class_names); + /// Return the active class list. + /// @return A string containing all the classes on the element, separated by spaces. + String GetClassNames() const; + + /// Sets a local property override on the element to a pre-parsed value. + /// @param[in] name The name of the new property. + /// @param[in] property The parsed property to set. + bool SetProperty(PropertyId id, const Property& property); + /// Removes a local property override on the element; its value will revert to that defined in + /// the style sheet. + /// @param[in] name The name of the local property definition to remove. + void RemoveProperty(PropertyId id); + /// Returns one of this element's properties. If this element is not defined this property, or a parent cannot + /// be found that we can inherit the property from, the default value will be returned. + /// @param[in] name The name of the property to fetch the value for. + /// @return The value of this property for this element, or nullptr if no property exists with the given name. + const Property* GetProperty(PropertyId id) const; + /// Returns one of this element's properties. If this element is not defined this property, nullptr will be + /// returned. + /// @param[in] name The name of the property to fetch the value for. + /// @return The value of this property for this element, or nullptr if this property has not been explicitly defined for this element. + const Property* GetLocalProperty(PropertyId id) const; + /// Returns the local style properties, excluding any properties from local class. + const PropertyMap& GetLocalStyleProperties() const; + + /// Resolves a property with units of number, percentage, length, or angle to their canonical unit (unit-less, 'px', or 'rad'). + /// @param[in] property The property to resolve the value for. + /// @param[in] base_value The value that is scaled by the number or percentage value, if applicable. + /// @return The resolved value in their canonical unit, or zero if it could not be resolved. + float ResolveNumericProperty(const Property* property, float base_value) const; + /// Resolves a property with units of number, length, or percentage to a length in 'px' units. + /// Numbers and percentages are resolved by scaling the size of the specified target. + float ResolveLength(const Property* property, RelativeTarget relative_target) const; + + /// Mark definition and all children dirty. + void DirtyDefinition(); + + /// Mark inherited properties dirty. + /// Inherited properties will automatically be set when parent inherited properties are changed. However, + /// some operations may require to dirty these manually, such as when moving an element into another. + void DirtyInheritedProperties(); + + /// Dirties all properties with a given unit on the current element and recursively on all children. + void DirtyPropertiesWithUnitRecursive(Property::Unit unit); + + /// Returns true if any properties are dirty such that computed values need to be recomputed + bool AnyPropertiesDirty() const; + + /// Turns the local and inherited properties into computed values for this element. These values can in turn be used during the layout procedure. + /// Must be called in correct order, always parent before its children. + PropertyIdSet ComputeValues(Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, bool values_are_default_initialized, float dp_ratio); + + /// Returns an iterator for iterating the local properties of this element. + /// Note: Modifying the element's style invalidates its iterator. + PropertiesIterator Iterate() const; + +private: + // Dirty all child definitions + void DirtyChildDefinitions(); + // Sets a single property as dirty. + void DirtyProperty(PropertyId id); + // Sets a list of properties as dirty. + void DirtyProperties(const PropertyIdSet& properties); + + static const Property* GetLocalProperty(PropertyId id, const PropertyDictionary & inline_properties, const ElementDefinition * definition); + static const Property* GetProperty(PropertyId id, const Element * element, const PropertyDictionary & inline_properties, const ElementDefinition * definition); + static void TransitionPropertyChanges(Element * element, PropertyIdSet & properties, const PropertyDictionary & inline_properties, const ElementDefinition * old_definition, const ElementDefinition * new_definition); + + // Element these properties belong to + Element* element; + + // The list of classes applicable to this object. + StringList classes; + // This element's current pseudo-classes. + PseudoClassList pseudo_classes; + + // Any properties that have been overridden in this element. + PropertyDictionary inline_properties; + // The definition of this element, provides applicable properties from the stylesheet. + SharedPtr definition; + // Set if a new element definition should be fetched from the style. + bool definition_dirty; + + PropertyIdSet dirty_properties; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementText.cpp b/thirdparty/RmlUi/Source/Core/ElementText.cpp new file mode 100644 index 000000000..40ec851ee --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementText.cpp @@ -0,0 +1,41 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +ElementText::ElementText(const String& tag) : Element(tag) +{ +} + +ElementText::~ElementText() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementTextDefault.cpp b/thirdparty/RmlUi/Source/Core/ElementTextDefault.cpp new file mode 100644 index 000000000..6e9a1442a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementTextDefault.cpp @@ -0,0 +1,600 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementTextDefault.h" +#include "ElementDefinition.h" +#include "ElementStyle.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Profiling.h" + +namespace Rml { + +static bool BuildToken(String& token, const char*& token_begin, const char* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation, bool decode_escape_characters); +static bool LastToken(const char* token_begin, const char* string_end, bool collapse_white_space, bool break_at_endline); + +ElementTextDefault::ElementTextDefault(const String& tag) : ElementText(tag), colour(255, 255, 255), decoration(this) +{ + dirty_layout_on_change = true; + + generated_decoration = Style::TextDecoration::None; + decoration_property = Style::TextDecoration::None; + + geometry_dirty = true; + + font_effects_handle = 0; + font_effects_dirty = true; + font_handle_version = 0; +} + +ElementTextDefault::~ElementTextDefault() +{ +} + +void ElementTextDefault::SetText(const String& _text) +{ + if (text != _text) + { + text = _text; + + if (dirty_layout_on_change) + DirtyLayout(); + } +} + +const String& ElementTextDefault::GetText() const +{ + return text; +} + +void ElementTextDefault::OnRender() +{ + RMLUI_ZoneScoped; + + FontFaceHandle font_face_handle = GetFontFaceHandle(); + if (font_face_handle == 0) + return; + + // If our font effects have potentially changed, update it and force a geometry generation if necessary. + if (font_effects_dirty && UpdateFontEffects()) + geometry_dirty = true; + + // Dirty geometry if font version has changed. + int new_version = GetFontEngineInterface()->GetVersion(font_face_handle); + if (new_version != font_handle_version) + { + font_handle_version = new_version; + geometry_dirty = true; + } + + // Regenerate the geometry if the colour or font configuration has altered. + if (geometry_dirty) + GenerateGeometry(font_face_handle); + + Vector2f translation = GetAbsoluteOffset(); + + bool render = true; + Vector2i clip_origin; + Vector2i clip_dimensions; + if (GetContext()->GetActiveClipRegion(clip_origin, clip_dimensions)) + { + float clip_top = (float)clip_origin.y; + float clip_left = (float)clip_origin.x; + float clip_right = (float)(clip_origin.x + clip_dimensions.x); + float clip_bottom = (float)(clip_origin.y + clip_dimensions.y); + float line_height = (float)GetFontEngineInterface()->GetLineHeight(GetFontFaceHandle()); + + render = false; + for (size_t i = 0; i < lines.size(); ++i) + { + const Line& line = lines[i]; + float x = translation.x + line.position.x; + float y = translation.y + line.position.y; + + bool render_line = !(x > clip_right); + render_line = render_line && !(x + line.width < clip_left); + + render_line = render_line && !(y - line_height > clip_bottom); + render_line = render_line && !(y < clip_top); + + if (render_line) + { + render = true; + break; + } + } + } + + translation = translation.Round(); + + if (render) + { + for (size_t i = 0; i < geometry.size(); ++i) + geometry[i].Render(translation); + } + + if (decoration_property != Style::TextDecoration::None) + decoration.Render(translation); +} + +// Generates a token of text from this element, returning only the width. +bool ElementTextDefault::GenerateToken(float& token_width, int line_begin) +{ + RMLUI_ZoneScoped; + + // Bail if we don't have a valid font face. + FontFaceHandle font_face_handle = GetFontFaceHandle(); + if (font_face_handle == 0 || + line_begin >= (int) text.size()) + return 0; + + // Determine how we are processing white-space while formatting the text. + using namespace Style; + auto& computed = GetComputedValues(); + WhiteSpace white_space_property = computed.white_space; + bool collapse_white_space = white_space_property == WhiteSpace::Normal || + white_space_property == WhiteSpace::Nowrap || + white_space_property == WhiteSpace::Preline; + bool break_at_endline = white_space_property == WhiteSpace::Pre || + white_space_property == WhiteSpace::Prewrap || + white_space_property == WhiteSpace::Preline; + + const char* token_begin = text.c_str() + line_begin; + String token; + + BuildToken(token, token_begin, text.c_str() + text.size(), true, collapse_white_space, break_at_endline, computed.text_transform, true); + token_width = (float) GetFontEngineInterface()->GetStringWidth(font_face_handle, token); + + return LastToken(token_begin, text.c_str() + text.size(), collapse_white_space, break_at_endline); +} + +// Generates a line of text rendered from this element +bool ElementTextDefault::GenerateLine(String& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix, bool decode_escape_characters) +{ + RMLUI_ZoneScoped; + + FontFaceHandle font_face_handle = GetFontFaceHandle(); + + // Initialise the output variables. + line.clear(); + line_length = 0; + line_width = 0; + + // Bail if we don't have a valid font face. + if (font_face_handle == 0) + return true; + + // Determine how we are processing white-space while formatting the text. + using namespace Style; + auto& computed = GetComputedValues(); + WhiteSpace white_space_property = computed.white_space; + bool collapse_white_space = white_space_property == WhiteSpace::Normal || + white_space_property == WhiteSpace::Nowrap || + white_space_property == WhiteSpace::Preline; + bool break_at_line = maximum_line_width >= 0 && + (white_space_property == WhiteSpace::Normal || + white_space_property == WhiteSpace::Prewrap || + white_space_property == WhiteSpace::Preline); + bool break_at_endline = white_space_property == WhiteSpace::Pre || + white_space_property == WhiteSpace::Prewrap || + white_space_property == WhiteSpace::Preline; + + // Determine what (if any) text transformation we are putting the characters through. + TextTransform text_transform_property = computed.text_transform; + + // Starting at the line_begin character, we generate sections of the text (we'll call them tokens) depending on the + // white-space parsing parameters. Each section is then appended to the line if it can fit. If not, or if an + // endline is found (and we're processing them), then the line is ended. kthxbai! + const char* token_begin = text.c_str() + line_begin; + const char* string_end = text.c_str() + text.size(); + while (token_begin != string_end) + { + String token; + const char* next_token_begin = token_begin; + Character previous_codepoint = Character::Null; + if (!line.empty()) + previous_codepoint = StringUtilities::ToCharacter(StringUtilities::SeekBackwardUTF8(&line.back(), line.data())); + + // Generate the next token and determine its pixel-length. + bool break_line = BuildToken(token, next_token_begin, string_end, line.empty() && trim_whitespace_prefix, collapse_white_space, break_at_endline, text_transform_property, decode_escape_characters); + int token_width = GetFontEngineInterface()->GetStringWidth(font_face_handle, token, previous_codepoint); + + // If we're breaking to fit a line box, check if the token can fit on the line before we add it. + if (break_at_line) + { + if (!line.empty() && + (line_width + token_width > maximum_line_width || + (LastToken(next_token_begin, string_end, collapse_white_space, break_at_endline) && line_width + token_width > maximum_line_width - right_spacing_width))) + { + return false; + } + } + + // The token can fit on the end of the line, so add it onto the end and increment our width and length + // counters. + line += token; + line_length += (int)(next_token_begin - token_begin); + line_width += token_width; + + // Break out of the loop if an endline was forced. + if (break_line) + return false; + + // Set the beginning of the next token. + token_begin = next_token_begin; + } + + return true; +} + +// Clears all lines of generated text and prepares the element for generating new lines. +void ElementTextDefault::ClearLines() +{ + // Clear the rendering information. + for (size_t i = 0; i < geometry.size(); ++i) + geometry[i].Release(true); + + lines.clear(); + decoration.Release(true); +} + +// Adds a new line into the text element. +void ElementTextDefault::AddLine(const Vector2f& line_position, const String& line) +{ + FontFaceHandle font_face_handle = GetFontFaceHandle(); + + if (font_face_handle == 0) + return; + + if (font_effects_dirty) + UpdateFontEffects(); + + Vector2f baseline_position = line_position + Vector2f(0.0f, (float)GetFontEngineInterface()->GetLineHeight(font_face_handle) - GetFontEngineInterface()->GetBaseline(font_face_handle)); + lines.push_back(Line(line, baseline_position)); + + geometry_dirty = true; +} + +// Prevents the element from dirtying its document's layout when its text is changed. +void ElementTextDefault::SuppressAutoLayout() +{ + dirty_layout_on_change = false; +} + +void ElementTextDefault::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + RMLUI_ZoneScoped; + + Element::OnPropertyChange(changed_properties); + + bool colour_changed = false; + bool font_face_changed = false; + auto& computed = GetComputedValues(); + + if (changed_properties.Contains(PropertyId::Color) || + changed_properties.Contains(PropertyId::Opacity)) + { + // Fetch our (potentially) new colour. + Colourb new_colour = computed.color; + float opacity = computed.opacity; + new_colour.alpha = byte(opacity * float(new_colour.alpha)); + colour_changed = colour != new_colour; + if (colour_changed) + colour = new_colour; + } + + if (changed_properties.Contains(PropertyId::FontFamily) || + changed_properties.Contains(PropertyId::FontWeight) || + changed_properties.Contains(PropertyId::FontStyle) || + changed_properties.Contains(PropertyId::FontSize)) + { + font_face_changed = true; + + geometry.clear(); + font_effects_dirty = true; + } + + if (changed_properties.Contains(PropertyId::FontEffect)) + { + font_effects_dirty = true; + } + + if (changed_properties.Contains(PropertyId::TextDecoration)) + { + decoration_property = computed.text_decoration; + if (decoration_property != Style::TextDecoration::None) + { + if (decoration_property != generated_decoration) + { + decoration.Release(true); + + FontFaceHandle font_face_handle = GetFontFaceHandle(); + if (font_face_handle != 0) + { + for (size_t i = 0; i < lines.size(); ++i) + GenerateLineDecoration(font_face_handle, lines[i]); + } + + generated_decoration = decoration_property; + } + } + } + + if (font_face_changed) + { + // We have to let our document know we need to be regenerated. + if (dirty_layout_on_change) + DirtyLayout(); + } + else if (colour_changed) + { + // Force the geometry to be regenerated. + geometry_dirty = true; + + // Re-colour the decoration geometry. + Vector< Vertex >& vertices = decoration.GetVertices(); + for (size_t i = 0; i < vertices.size(); ++i) + vertices[i].colour = colour; + + decoration.Release(); + } +} + +// Returns the RML of this element +void ElementTextDefault::GetRML(String& content) +{ + content += text; +} + +// Updates the configuration this element uses for its font. +bool ElementTextDefault::UpdateFontEffects() +{ + RMLUI_ZoneScoped; + + if (GetFontFaceHandle() == 0) + return false; + + font_effects_dirty = false; + + static const FontEffectList empty_font_effects; + + // Fetch the font-effect for this text element + const FontEffectList* font_effects = &empty_font_effects; + if (const FontEffects* effects = GetComputedValues().font_effect.get()) + font_effects = &effects->list; + + // Request a font layer configuration to match this set of effects. If this is different from + // our old configuration, then return true to indicate we'll need to regenerate geometry. + FontEffectsHandle new_font_effects_handle = GetFontEngineInterface()->PrepareFontEffects(GetFontFaceHandle(), *font_effects); + if (new_font_effects_handle != font_effects_handle) + { + font_effects_handle = new_font_effects_handle; + return true; + } + + return false; +} + +// Clears and regenerates all of the text's geometry. +void ElementTextDefault::GenerateGeometry(const FontFaceHandle font_face_handle) +{ + RMLUI_ZoneScopedC(0xD2691E); + + // Release the old geometry ... + for (size_t i = 0; i < geometry.size(); ++i) + geometry[i].Release(true); + + // ... and generate it all again! + for (size_t i = 0; i < lines.size(); ++i) + GenerateGeometry(font_face_handle, lines[i]); + + geometry_dirty = false; +} + +void ElementTextDefault::GenerateGeometry(const FontFaceHandle font_face_handle, Line& line) +{ + line.width = GetFontEngineInterface()->GenerateString(font_face_handle, font_effects_handle, line.text, line.position, colour, geometry); + for (size_t i = 0; i < geometry.size(); ++i) + geometry[i].SetHostElement(this); + + if (decoration_property != Style::TextDecoration::None) + GenerateLineDecoration(font_face_handle, line); +} + +// Generates any geometry necessary for rendering a line decoration (underline, strike-through, etc). +void ElementTextDefault::GenerateLineDecoration(const FontFaceHandle font_face_handle, const Line& line) +{ + RMLUI_ZoneScopedC(0xA52A2A); + + GeometryUtilities::GenerateLine(font_face_handle, &decoration, line.position, line.width, decoration_property, colour); +} + +static bool BuildToken(String& token, const char*& token_begin, const char* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation, bool decode_escape_characters) +{ + RMLUI_ASSERT(token_begin != string_end); + + token.reserve(string_end - token_begin + token.size()); + + // Check what the first character of the token is; all we need to know is if it is white-space or not. + bool parsing_white_space = StringUtilities::IsWhitespace(*token_begin); + + // Loop through the string from the token's beginning until we find an end to the token. This can occur in various + // places, depending on the white-space processing; + // - at the end of a section of non-white-space characters, + // - at the end of a section of white-space characters, if we're not collapsing white-space, + // - at an endline token, if we're breaking on endlines. + while (token_begin != string_end) + { + bool force_non_whitespace = false; + char character = *token_begin; + + const char* escape_begin = token_begin; + + // Check for an ampersand; if we find one, we've got an HTML escaped character. + if (decode_escape_characters && character == '&') + { + // Find the terminating ';'. + while (token_begin != string_end && + *token_begin != ';') + ++token_begin; + + // If we couldn't find the ';', print the token like normal text. + if (token_begin == string_end) + { + token_begin = escape_begin; + } + // We could find a ';', parse the escape code. If the escape code is recognised, set the parsed character + // to the appropriate one. If it is a non-breaking space, prevent it being picked up as whitespace. If it + // is not recognised, print the token like normal text. + else + { + String escape_code(escape_begin + 1, token_begin); + + if (escape_code == "lt") + character = '<'; + else if (escape_code == "gt") + character = '>'; + else if (escape_code == "amp") + character = '&'; + else if (escape_code == "quot") + character = '"'; + else if (escape_code == "nbsp") + { + character = ' '; + force_non_whitespace = true; + } + else + token_begin = escape_begin; + } + } + + // Check for an endline token; if we're breaking on endlines and we find one, then return true to indicate a + // forced break. + if (break_at_endline && + character == '\n') + { + token += '\n'; + token_begin++; + return true; + } + + // If we've transitioned from white-space characters to non-white-space characters, or vice-versa, then check + // if should terminate the token; if we're not collapsing white-space, then yes (as sections of white-space are + // non-breaking), otherwise only if we've transitioned from characters to white-space. + bool white_space = !force_non_whitespace && StringUtilities::IsWhitespace(character); + if (white_space != parsing_white_space) + { + if (!collapse_white_space) + { + // Restore pointer to the beginning of the escaped token, if we processed an escape code. + token_begin = escape_begin; + return false; + } + + // We're collapsing white-space; we only tokenise words, not white-space, so we're only done tokenising + // once we've begun parsing non-white-space and then found white-space. + if (!parsing_white_space) + { + // However, if we are the last non-whitespace character in the string, and there are trailing + // whitespace characters after this token, then we need to append a single space to the end of this + // token. + if (token_begin != string_end && + LastToken(token_begin, string_end, collapse_white_space, break_at_endline)) + token += ' '; + + return false; + } + + // We've transitioned from white-space to non-white-space, so we append a single white-space character. + if (!first_token) + token += ' '; + + parsing_white_space = false; + } + + // If the current character is white-space, we'll append a space character to the token if we're not collapsing + // sections of white-space. + if (white_space) + { + if (!collapse_white_space) + token += ' '; + } + else + { + if (text_transformation == Style::TextTransform::Uppercase) + { + if (character >= 'a' && character <= 'z') + character += ('A' - 'a'); + } + else if (text_transformation == Style::TextTransform::Lowercase) + { + if (character >= 'A' && character <= 'Z') + character -= ('A' - 'a'); + } + + token += character; + } + + ++token_begin; + } + + return false; +} + +static bool LastToken(const char* token_begin, const char* string_end, bool collapse_white_space, bool break_at_endline) +{ + bool last_token = (token_begin == string_end); + if (collapse_white_space && + !last_token) + { + last_token = true; + const char* character = token_begin; + + while (character != string_end) + { + if (!StringUtilities::IsWhitespace(*character) || + (break_at_endline && *character == '\n')) + { + last_token = false; + break; + } + + character++; + } + } + + return last_token; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/ElementTextDefault.h b/thirdparty/RmlUi/Source/Core/ElementTextDefault.h new file mode 100644 index 000000000..fba3fb309 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementTextDefault.h @@ -0,0 +1,137 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTTEXTDEFAULT_H +#define RMLUI_CORE_ELEMENTTEXTDEFAULT_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Geometry.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class RMLUICORE_API ElementTextDefault : public ElementText +{ +public: + RMLUI_RTTI_DefineWithParent(ElementTextDefault, ElementText) + + ElementTextDefault(const String& tag); + virtual ~ElementTextDefault(); + + void SetText(const String& text) override; + const String& GetText() const override; + + void OnRender() override; + + /// Generates a token of text from this element, returning only the width. + /// @param[out] token_width The window (in pixels) of the token. + /// @param[in] token_begin The first character to be included in the token. + /// @return True if the token is the end of the element's text, false if not. + bool GenerateToken(float& token_width, int token_begin) override; + /// Generates a line of text rendered from this element + /// @param[out] line The characters making up the line, with white-space characters collapsed and endlines processed appropriately. + /// @param[out] line_length The number of characters from the source string consumed making up this string; this may very well be different from line.size()! + /// @param[out] line_width The width (in pixels) of the generated line. + /// @param[in] line_begin The first character to be rendered in the line. + /// @param[in] maximum_line_width The width (in pixels) of space allowed for the line, or -1 for unlimited space. + /// @param[in] right_spacing_width The width (in pixels) of the spacing (consisting of margins, padding, etc) that must be remaining on the right of the line if the last of the text is rendered onto this line. + /// @param[in] trim_whitespace_prefix If we're collapsing whitespace, whether or remove all prefixing whitespace or collapse it down to a single space. + /// @param[in] decode_escape_characters Decode escaped characters such as & into &. + /// @return True if the line reached the end of the element's text, false if not. + bool GenerateLine(String& line, int& line_length, float& line_width, int line_begin, float maximum_line_width, float right_spacing_width, bool trim_whitespace_prefix, bool decode_escape_characters) override; + + /// Clears all lines of generated text and prepares the element for generating new lines. + void ClearLines() override; + /// Adds a new line into the text element. + /// @param[in] line_position The position of this line, as an offset from the first line. + /// @param[in] line The contents of the line.. + void AddLine(const Vector2f& line_position, const String& line) override; + + /// Prevents the element from dirtying its document's layout when its text is changed. + void SuppressAutoLayout() override; + +protected: + void OnPropertyChange(const PropertyIdSet& properties) override; + + /// Returns the RML of this element + /// @param content[out] The raw text. + void GetRML(String& content) override; + +private: + // Prepares the font effects this element uses for its font. + bool UpdateFontEffects(); + + // Used to store the position and length of each line we have geometry for. + struct Line + { + Line(const String& text, const Vector2f& position) : text(text), position(position), width(0) {} + String text; + Vector2f position; + int width; + }; + + // Clears and regenerates all of the text's geometry. + void GenerateGeometry(const FontFaceHandle font_face_handle); + // Generates the geometry for a single line of text. + void GenerateGeometry(const FontFaceHandle font_face_handle, Line& line); + // Generates any geometry necessary for rendering a line decoration (underline, strike-through, etc). + void GenerateLineDecoration(const FontFaceHandle font_face_handle, const Line& line); + + String text; + + typedef Vector< Line > LineList; + LineList lines; + + bool dirty_layout_on_change; + + GeometryList geometry; + bool geometry_dirty; + + Colourb colour; + + // The decoration geometry we've generated for this string. + Geometry decoration; + // What the decoration type is that we have generated. + Style::TextDecoration generated_decoration; + // What the element's actual text-decoration property is; this may be different from the generated decoration + // if it is set to none; this means we can keep generated decoration and simply toggle it on or off as long as + // it isn't being changed. + Style::TextDecoration decoration_property; + + FontEffectsHandle font_effects_handle; + bool font_effects_dirty; + + int font_handle_version; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ElementUtilities.cpp b/thirdparty/RmlUi/Source/Core/ElementUtilities.cpp new file mode 100644 index 000000000..bf37849be --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ElementUtilities.cpp @@ -0,0 +1,501 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/DataController.h" +#include "../../Include/RmlUi/Core/DataModel.h" +#include "../../Include/RmlUi/Core/DataView.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementScroll.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/RenderInterface.h" +#include "ElementStyle.h" +#include "LayoutEngine.h" +#include "TransformState.h" +#include + +namespace Rml { + +// Builds and sets the box for an element. +static void SetBox(Element* element) +{ + Element* parent = element->GetParentNode(); + RMLUI_ASSERT(parent != nullptr); + + Vector2f containing_block = parent->GetBox().GetSize(); + containing_block.x -= parent->GetElementScroll()->GetScrollbarSize(ElementScroll::VERTICAL); + containing_block.y -= parent->GetElementScroll()->GetScrollbarSize(ElementScroll::HORIZONTAL); + + Box box; + LayoutEngine::BuildBox(box, containing_block, element); + + if (element->GetComputedValues().height.type != Style::Height::Auto) + box.SetContent(Vector2f(box.GetSize().x, containing_block.y)); + + element->SetBox(box); +} + +// Positions an element relative to an offset parent. +static void SetElementOffset(Element* element, const Vector2f& offset) +{ + Vector2f relative_offset = element->GetParentNode()->GetBox().GetPosition(Box::CONTENT); + relative_offset += offset; + relative_offset.x += element->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + relative_offset.y += element->GetBox().GetEdge(Box::MARGIN, Box::TOP); + + element->SetOffset(relative_offset, element->GetParentNode()); +} + +Element* ElementUtilities::GetElementById(Element* root_element, const String& id) +{ + // Breadth first search on elements for the corresponding id + typedef Queue SearchQueue; + SearchQueue search_queue; + search_queue.push(root_element); + + while (!search_queue.empty()) + { + Element* element = search_queue.front(); + search_queue.pop(); + + if (element->GetId() == id) + { + return element; + } + + // Add all children to search + for (int i = 0; i < element->GetNumChildren(); i++) + search_queue.push(element->GetChild(i)); + } + + return nullptr; +} + +void ElementUtilities::GetElementsByTagName(ElementList& elements, Element* root_element, const String& tag) +{ + // Breadth first search on elements for the corresponding id + typedef Queue< Element* > SearchQueue; + SearchQueue search_queue; + for (int i = 0; i < root_element->GetNumChildren(); ++i) + search_queue.push(root_element->GetChild(i)); + + while (!search_queue.empty()) + { + Element* element = search_queue.front(); + search_queue.pop(); + + if (element->GetTagName() == tag) + elements.push_back(element); + + // Add all children to search. + for (int i = 0; i < element->GetNumChildren(); i++) + search_queue.push(element->GetChild(i)); + } +} + +void ElementUtilities::GetElementsByClassName(ElementList& elements, Element* root_element, const String& class_name) +{ + // Breadth first search on elements for the corresponding id + typedef Queue< Element* > SearchQueue; + SearchQueue search_queue; + for (int i = 0; i < root_element->GetNumChildren(); ++i) + search_queue.push(root_element->GetChild(i)); + + while (!search_queue.empty()) + { + Element* element = search_queue.front(); + search_queue.pop(); + + if (element->IsClassSet(class_name)) + elements.push_back(element); + + // Add all children to search. + for (int i = 0; i < element->GetNumChildren(); i++) + search_queue.push(element->GetChild(i)); + } +} + +float ElementUtilities::GetDensityIndependentPixelRatio(Element * element) +{ + Context* context = element->GetContext(); + if (context == nullptr) + return 1.0f; + + return context->GetDensityIndependentPixelRatio(); +} + +// Returns the width of a string rendered within the context of the given element. +int ElementUtilities::GetStringWidth(Element* element, const String& string) +{ + FontFaceHandle font_face_handle = element->GetFontFaceHandle(); + if (font_face_handle == 0) + return 0; + + return GetFontEngineInterface()->GetStringWidth(font_face_handle, string); +} + +void ElementUtilities::BindEventAttributes(Element* element) +{ + // Check for and instance the on* events + for (const auto& pair: element->GetAttributes()) + { + if (pair.first.size() > 2 && pair.first[0] == 'o' && pair.first[1] == 'n') + { + EventListener* listener = Factory::InstanceEventListener(pair.second.Get(), element); + if (listener) + element->AddEventListener(pair.first.substr(2), listener, false); + } + } +} + +// Generates the clipping region for an element. +bool ElementUtilities::GetClippingRegion(Vector2i& clip_origin, Vector2i& clip_dimensions, Element* element) +{ + clip_origin = Vector2i(-1, -1); + clip_dimensions = Vector2i(-1, -1); + + int num_ignored_clips = element->GetClippingIgnoreDepth(); + if (num_ignored_clips < 0) + return false; + + // Search through the element's ancestors, finding all elements that clip their overflow and have overflow to clip. + // For each that we find, we combine their clipping region with the existing clipping region, and so build up a + // complete clipping region for the element. + Element* clipping_element = element->GetParentNode(); + + while (clipping_element != nullptr) + { + // Merge the existing clip region with the current clip region if we aren't ignoring clip regions. + if (num_ignored_clips == 0 && clipping_element->IsClippingEnabled()) + { + // Ignore nodes that don't clip. + if (clipping_element->GetClientWidth() < clipping_element->GetScrollWidth() + || clipping_element->GetClientHeight() < clipping_element->GetScrollHeight()) + { + Vector2f element_origin_f = clipping_element->GetAbsoluteOffset(Box::CONTENT); + Vector2f element_dimensions_f = clipping_element->GetBox().GetSize(Box::CONTENT); + + Vector2i element_origin(Math::RealToInteger(element_origin_f.x), Math::RealToInteger(element_origin_f.y)); + Vector2i element_dimensions(Math::RealToInteger(element_dimensions_f.x), Math::RealToInteger(element_dimensions_f.y)); + + if (clip_origin == Vector2i(-1, -1) && clip_dimensions == Vector2i(-1, -1)) + { + clip_origin = element_origin; + clip_dimensions = element_dimensions; + } + else + { + Vector2i top_left(Math::Max(clip_origin.x, element_origin.x), + Math::Max(clip_origin.y, element_origin.y)); + + Vector2i bottom_right(Math::Min(clip_origin.x + clip_dimensions.x, element_origin.x + element_dimensions.x), + Math::Min(clip_origin.y + clip_dimensions.y, element_origin.y + element_dimensions.y)); + + clip_origin = top_left; + clip_dimensions.x = Math::Max(0, bottom_right.x - top_left.x); + clip_dimensions.y = Math::Max(0, bottom_right.y - top_left.y); + } + } + } + + // If this region is meant to clip and we're skipping regions, update the counter. + if (num_ignored_clips > 0) + { + if (clipping_element->IsClippingEnabled()) + num_ignored_clips--; + } + + // Determine how many clip regions this ancestor ignores, and inherit the value. If this region ignores all + // clipping regions, then we do too. + int clipping_element_ignore_clips = clipping_element->GetClippingIgnoreDepth(); + if (clipping_element_ignore_clips < 0) + break; + + num_ignored_clips = Math::Max(num_ignored_clips, clipping_element_ignore_clips); + + // Climb the tree to this region's parent. + clipping_element = clipping_element->GetParentNode(); + } + + return clip_dimensions.x >= 0 && clip_dimensions.y >= 0; +} + +// Sets the clipping region from an element and its ancestors. +bool ElementUtilities::SetClippingRegion(Element* element, Context* context) +{ + RenderInterface* render_interface = nullptr; + if (element) + { + render_interface = element->GetRenderInterface(); + if (!context) + context = element->GetContext(); + } + else if (context) + { + render_interface = context->GetRenderInterface(); + if (!render_interface) + render_interface = GetRenderInterface(); + } + + if (!render_interface || !context) + return false; + + Vector2i clip_origin = { -1, -1 }; + Vector2i clip_dimensions = { -1, -1 }; + bool clip = element && GetClippingRegion(clip_origin, clip_dimensions, element); + + Vector2i current_origin = { -1, -1 }; + Vector2i current_dimensions = { -1, -1 }; + bool current_clip = context->GetActiveClipRegion(current_origin, current_dimensions); + if (current_clip != clip || (clip && (clip_origin != current_origin || clip_dimensions != current_dimensions))) + { + context->SetActiveClipRegion(clip_origin, clip_dimensions); + ApplyActiveClipRegion(context, render_interface); + } + + return true; +} + +void ElementUtilities::ApplyActiveClipRegion(Context* context, RenderInterface* render_interface) +{ + if (render_interface == nullptr) + return; + + Vector2i origin; + Vector2i dimensions; + bool clip_enabled = context->GetActiveClipRegion(origin, dimensions); + + render_interface->EnableScissorRegion(clip_enabled); + if (clip_enabled) + { + render_interface->SetScissorRegion(origin.x, origin.y, dimensions.x, dimensions.y); + } +} + +// Formats the contents of an element. +bool ElementUtilities::FormatElement(Element* element, const Vector2f& containing_block) +{ + LayoutEngine layout_engine; + return layout_engine.FormatElement(element, containing_block); +} + +// Generates the box for an element. +void ElementUtilities::BuildBox(Box& box, const Vector2f& containing_block, Element* element, bool inline_element) +{ + LayoutEngine::BuildBox(box, containing_block, element, inline_element); +} + +// Sizes an element, and positions it within its parent offset from the borders of its content area. +bool ElementUtilities::PositionElement(Element* element, const Vector2f& offset, PositionAnchor anchor) +{ + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + SetBox(element); + + Vector2f containing_block = element->GetParentNode()->GetBox().GetSize(Box::CONTENT); + Vector2f element_block = element->GetBox().GetSize(Box::MARGIN); + + Vector2f resolved_offset = offset; + + if (anchor & RIGHT) + resolved_offset.x = containing_block.x - (element_block.x + offset.x); + + if (anchor & BOTTOM) + resolved_offset.y = containing_block.y - (element_block.y + offset.y); + + SetElementOffset(element, resolved_offset); + + return true; +} + +bool ElementUtilities::ApplyTransform(Element &element) +{ + RenderInterface *render_interface = element.GetRenderInterface(); + if (!render_interface) + return false; + + struct PreviousMatrix { + const Matrix4f* pointer; // This may be expired, dereferencing not allowed! + Matrix4f value; + }; + static SmallUnorderedMap previous_matrix; + + auto it = previous_matrix.find(render_interface); + if (it == previous_matrix.end()) + it = previous_matrix.emplace(render_interface, PreviousMatrix{ nullptr, Matrix4f::Identity() }).first; + + RMLUI_ASSERT(it != previous_matrix.end()); + + const Matrix4f*& old_transform = it->second.pointer; + const Matrix4f* new_transform = nullptr; + + if (const TransformState* state = element.GetTransformState()) + new_transform = state->GetTransform(); + + // Only changed transforms are submitted. + if (old_transform != new_transform) + { + Matrix4f& old_transform_value = it->second.value; + + // Do a deep comparison as well to avoid submitting a new transform which is equal. + if(!old_transform || !new_transform || (old_transform_value != *new_transform)) + { + render_interface->SetTransform(new_transform); + + if(new_transform) + old_transform_value = *new_transform; + } + + old_transform = new_transform; + } + + return true; +} + + +static bool ApplyDataViewsControllersInternal(Element* element, const bool construct_structural_view, const String& structural_view_inner_rml) +{ + RMLUI_ASSERT(element); + bool result = false; + + // If we have an active data model, check the attributes for any data bindings + if (DataModel* data_model = element->GetDataModel()) + { + struct ViewControllerInitializer { + String type; + String modifier_or_inner_rml; + String expression; + DataViewPtr view; + DataControllerPtr controller; + explicit operator bool() const { return view || controller; } + }; + + // Since data views and controllers may modify the element's attributes during initialization, we + // need to iterate over all the attributes _before_ initializing any views or controllers. We store + // the information needed to initialize them in the following container. + Vector initializer_list; + + for (auto& attribute : element->GetAttributes()) + { + // Data views and controllers are declared by the following element attribute: + // data-[type]-[modifier]="[expression]" + + constexpr size_t data_str_length = sizeof("data-") - 1; + + const String& name = attribute.first; + + if (name.size() > data_str_length && name[0] == 'd' && name[1] == 'a' && name[2] == 't' && name[3] == 'a' && name[4] == '-') + { + const size_t type_end = name.find('-', data_str_length); + const size_t type_size = (type_end == String::npos ? String::npos : type_end - data_str_length); + String type_name = name.substr(data_str_length, type_size); + + ViewControllerInitializer initializer; + + // Structural data views are applied in a separate step from the normal views and controllers. + if (construct_structural_view) + { + if (DataViewPtr view = Factory::InstanceDataView(type_name, element, true)) + { + initializer.modifier_or_inner_rml = structural_view_inner_rml; + initializer.view = std::move(view); + } + } + else + { + const size_t modifier_offset = data_str_length + type_name.size() + 1; + if (modifier_offset < name.size()) + initializer.modifier_or_inner_rml = name.substr(modifier_offset); + + if (DataViewPtr view = Factory::InstanceDataView(type_name, element, false)) + initializer.view = std::move(view); + + if (DataControllerPtr controller = Factory::InstanceDataController(type_name, element)) + initializer.controller = std::move(controller); + } + + if (initializer) + { + initializer.type = std::move(type_name); + initializer.expression = attribute.second.Get(); + + initializer_list.push_back(std::move(initializer)); + } + } + } + + // Now, we can safely initialize the data views and controllers, even modifying the element's attributes when desired. + for (ViewControllerInitializer& initializer : initializer_list) + { + DataViewPtr& view = initializer.view; + DataControllerPtr& controller = initializer.controller; + + if (view) + { + if (view->Initialize(*data_model, element, initializer.expression, initializer.modifier_or_inner_rml)) + { + data_model->AddView(std::move(view)); + result = true; + } + else + Log::Message(Log::LT_WARNING, "Could not add data-%s view to element: %s", initializer.type.c_str(), element->GetAddress().c_str()); + } + + if (controller) + { + if (controller->Initialize(*data_model, element, initializer.expression, initializer.modifier_or_inner_rml)) + { + data_model->AddController(std::move(controller)); + result = true; + } + else + Log::Message(Log::LT_WARNING, "Could not add data-%s controller to element: %s", initializer.type.c_str(), element->GetAddress().c_str()); + } + } + } + + return result; +} + + +bool ElementUtilities::ApplyDataViewsControllers(Element* element) +{ + return ApplyDataViewsControllersInternal(element, false, String()); +} + +bool ElementUtilities::ApplyStructuralDataViews(Element* element, const String& inner_rml) +{ + return ApplyDataViewsControllersInternal(element, true, inner_rml); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/DataFormatter.cpp b/thirdparty/RmlUi/Source/Core/Elements/DataFormatter.cpp new file mode 100644 index 000000000..6a872c2ed --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/DataFormatter.cpp @@ -0,0 +1,75 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/DataFormatter.h" +#include "../../../Include/RmlUi/Core/StringUtilities.h" + +namespace Rml { + +typedef UnorderedMap< String, DataFormatter* > DataFormatterMap; +static DataFormatterMap data_formatters; + +DataFormatter::DataFormatter(const String& _name) +{ + if (!_name.empty()) + { + name = _name; + } + else + { + name = CreateString(64, "%x", this); + } + data_formatters[name] = this; +} + +DataFormatter::~DataFormatter() +{ +} + +const String& DataFormatter::GetDataFormatterName() +{ + return name; +} + +DataFormatter* DataFormatter::GetDataFormatter(const String& data_formatter_name) +{ + DataFormatterMap::iterator i = data_formatters.find(data_formatter_name); + if (i == data_formatters.end()) + { + return nullptr; + } + + return (*i).second; +} + +void* DataFormatter::GetScriptObject() const +{ + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/DataQuery.cpp b/thirdparty/RmlUi/Source/Core/Elements/DataQuery.cpp new file mode 100644 index 000000000..d674ce1d1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/DataQuery.cpp @@ -0,0 +1,159 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/DataQuery.h" +#include "../../../Include/RmlUi/Core/Elements/DataSource.h" +#include + +namespace Rml { + +class DataQuerySort +{ + public: + DataQuerySort(const StringList& _order_parameters) + { + order_parameters = _order_parameters; + } + + bool operator()(const StringList& RMLUI_UNUSED_PARAMETER(left), const StringList& RMLUI_UNUSED_PARAMETER(right)) + { + RMLUI_UNUSED(left); + RMLUI_UNUSED(right); + + return false; + } + + private: + StringList order_parameters; +}; + + + +DataQuery::DataQuery(DataSource* data_source, const String& table, const String& _fields, int offset, int limit, const String& order) +{ + ExecuteQuery(data_source, table, _fields, offset, limit, order); +} + + + +DataQuery::DataQuery() +{ + data_source = nullptr; + table = ""; + offset = -1; + limit = -1; +} + + + +DataQuery::~DataQuery() +{ +} + + + +void DataQuery::ExecuteQuery(DataSource* _data_source, const String& _table, const String& _fields, int _offset, int _limit, const String& order) +{ + data_source = _data_source; + table = _table; + offset = _offset; + limit = _limit; + + // Set up the field list and field index cache. + StringUtilities::ExpandString(fields, _fields); + for (size_t i = 0; i < fields.size(); i++) + { + field_indices[fields[i]] = i; + } + + // Initialise the row pointer. + current_row = -1; + + // If limit is -1, then we fetch to the end of the data source. + if (limit == -1) + { + limit = data_source->GetNumRows(table) - offset; + } + + if (!order.empty()) + { + // Fetch the rows from offset to limit. + rows.resize(limit); + for (int i = 0; i < limit; i++) + { + data_source->GetRow(rows[i], table, offset + i, fields); + } + + // Now sort the rows, based on the ordering requirements. + StringList order_parameters; + StringUtilities::ExpandString(order_parameters, order); + std::sort(rows.begin(), rows.end(), DataQuerySort(order_parameters)); + } +} + + + +bool DataQuery::NextRow() +{ + current_row++; + + if (current_row >= limit) + { + return false; + } + + LoadRow(); + return true; +} + + + +bool DataQuery::IsFieldSet(const String& field) const +{ + FieldIndices::const_iterator itr = field_indices.find(field); + if (itr == field_indices.end() || (*itr).second >= rows[current_row].size()) + { + return false; + } + + return true; +} + + + +void DataQuery::LoadRow() +{ + RMLUI_ASSERT(current_row <= (int)rows.size()); + if (current_row >= (int)rows.size()) + { + rows.push_back(StringList()); + data_source->GetRow(rows[current_row], table, offset + current_row, fields); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/DataSource.cpp b/thirdparty/RmlUi/Source/Core/Elements/DataSource.cpp new file mode 100644 index 000000000..4547a50af --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/DataSource.cpp @@ -0,0 +1,170 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/DataSource.h" +#include "../../../Include/RmlUi/Core/Elements/DataSourceListener.h" +#include "../../../Include/RmlUi/Core/StringUtilities.h" +#include "../../../Include/RmlUi/Core/Log.h" +#include + +namespace Rml { + +const String DataSource::CHILD_SOURCE("#child_data_source"); +const String DataSource::DEPTH("#depth"); +const String DataSource::NUM_CHILDREN("#num_children"); + +typedef UnorderedMap< String, DataSource* > DataSourceMap; +static DataSourceMap data_sources; + +DataSource::DataSource(const String& _name) +{ + if (!_name.empty()) + { + name = _name; + } + else + { + name = CreateString(64, "%x", this); + } + data_sources[name] = this; +} + +DataSource::~DataSource() +{ + ListenerList listeners_copy = listeners; + for (ListenerList::iterator i = listeners_copy.begin(); i != listeners_copy.end(); ++i) + { + (*i)->OnDataSourceDestroy(this); + } + + DataSourceMap::iterator iterator = data_sources.find(name); + if (iterator != data_sources.end() && + iterator->second == this) + { + data_sources.erase(name); + } +} + +const String& DataSource::GetDataSourceName() +{ + return name; +} + +DataSource* DataSource::GetDataSource(const String& data_source_name) +{ + DataSourceMap::iterator i = data_sources.find(data_source_name); + if (i == data_sources.end()) + { + return nullptr; + } + + return (*i).second; +} + +void DataSource::AttachListener(DataSourceListener* listener) +{ + if (find(listeners.begin(), listeners.end(), listener) != listeners.end()) + { + RMLUI_ERROR; + return; + } + listeners.push_back(listener); +} + +void DataSource::DetachListener(DataSourceListener* listener) +{ + ListenerList::iterator i = find(listeners.begin(), listeners.end(), listener); + RMLUI_ASSERT(i != listeners.end()); + if (i != listeners.end()) + { + listeners.erase(i); + } +} + +void* DataSource::GetScriptObject() const +{ + return nullptr; +} + +void DataSource::NotifyRowAdd(const String& table, int first_row_added, int num_rows_added) +{ + ListenerList listeners_copy = listeners; + for (ListenerList::iterator i = listeners_copy.begin(); i != listeners_copy.end(); ++i) + { + (*i)->OnRowAdd(this, table, first_row_added, num_rows_added); + } +} + +void DataSource::NotifyRowRemove(const String& table, int first_row_removed, int num_rows_removed) +{ + ListenerList listeners_copy = listeners; + for (ListenerList::iterator i = listeners_copy.begin(); i != listeners_copy.end(); ++i) + { + (*i)->OnRowRemove(this, table, first_row_removed, num_rows_removed); + } +} + +void DataSource::NotifyRowChange(const String& table, int first_row_changed, int num_rows_changed) +{ + ListenerList listeners_copy = listeners; + for (ListenerList::iterator i = listeners_copy.begin(); i != listeners_copy.end(); ++i) + { + (*i)->OnRowChange(this, table, first_row_changed, num_rows_changed); + } +} + +void DataSource::NotifyRowChange(const String& table) +{ + ListenerList listeners_copy = listeners; + for (ListenerList::iterator i = listeners_copy.begin(); i != listeners_copy.end(); ++i) + { + (*i)->OnRowChange(this, table); + } +} + +void DataSource::BuildRowEntries(StringList& row, const RowMap& row_map, const StringList& columns) +{ + // Reserve the number of entries. + row.resize(columns.size()); + for (size_t i = 0; i < columns.size(); i++) + { + // Look through our row_map for each entry and add it to the result set + RowMap::const_iterator itr = row_map.find(columns[i]); + if (itr != row_map.end()) + { + row[i] = (*itr).second; + } + else + { + row[i] = ""; + Log::Message(Log::LT_ERROR, "Failed to find required data source column %s", columns[i].c_str()); + } + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/DataSourceListener.cpp b/thirdparty/RmlUi/Source/Core/Elements/DataSourceListener.cpp new file mode 100644 index 000000000..3628b63d9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/DataSourceListener.cpp @@ -0,0 +1,112 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/DataSourceListener.h" +#include "../../../Include/RmlUi/Core/Elements/DataSource.h" +#include "../../../Include/RmlUi/Core/StringUtilities.h" +#include "../../../Include/RmlUi/Core/Log.h" + +namespace Rml { + +DataSourceListener::DataSourceListener() +{ +} + +DataSourceListener::~DataSourceListener() +{ +} + +// Notification of the destruction of an observed data source. +void DataSourceListener::OnDataSourceDestroy(DataSource* RMLUI_UNUSED_PARAMETER(data_source)) +{ + RMLUI_UNUSED(data_source); +} + +// Notification of the addition of one or more rows to an observed data source's table. +void DataSourceListener::OnRowAdd(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& RMLUI_UNUSED_PARAMETER(table), int RMLUI_UNUSED_PARAMETER(first_row_added), int RMLUI_UNUSED_PARAMETER(num_rows_added)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(table); + RMLUI_UNUSED(first_row_added); + RMLUI_UNUSED(num_rows_added); +} + +// Notification of the removal of one or more rows from an observed data source's table. +void DataSourceListener::OnRowRemove(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& RMLUI_UNUSED_PARAMETER(table), int RMLUI_UNUSED_PARAMETER(first_row_removed), int RMLUI_UNUSED_PARAMETER(num_rows_removed)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(table); + RMLUI_UNUSED(first_row_removed); + RMLUI_UNUSED(num_rows_removed); +} + +// Notification of the changing of one or more rows from an observed data source's table. +void DataSourceListener::OnRowChange(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& RMLUI_UNUSED_PARAMETER(table), int RMLUI_UNUSED_PARAMETER(first_row_changed), int RMLUI_UNUSED_PARAMETER(num_rows_changed)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(table); + RMLUI_UNUSED(first_row_changed); + RMLUI_UNUSED(num_rows_changed); +} + +// Notification of the change of all of the data of an observed data source's table. +void DataSourceListener::OnRowChange(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& RMLUI_UNUSED_PARAMETER(table)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(table); +} + +// Sets up data source and table from a given string. +bool DataSourceListener::ParseDataSource(DataSource*& data_source, String& table_name, const String& data_source_name) +{ + if (data_source_name.size() == 0) + { + data_source = nullptr; + table_name = ""; + return false; + } + + StringList data_source_parts; + StringUtilities::ExpandString(data_source_parts, data_source_name, '.'); + + DataSource* new_data_source = DataSource::GetDataSource(data_source_parts[0]); + + if (data_source_parts.size() != 2 || !new_data_source) + { + Log::Message(Log::LT_ERROR, "Bad data source name %s", data_source_name.c_str()); + data_source = nullptr; + table_name = ""; + return false; + } + + data_source = new_data_source; + table_name = data_source_parts[1]; + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementDataGrid.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGrid.cpp new file mode 100644 index 000000000..e940f6834 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGrid.cpp @@ -0,0 +1,280 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementDataGrid.h" +#include "../../../Include/RmlUi/Core/Elements/DataSource.h" +#include "../../../Include/RmlUi/Core/Math.h" +#include "../../../Include/RmlUi/Core/XMLParser.h" +#include "../../../Include/RmlUi/Core/Event.h" +#include "../../../Include/RmlUi/Core/ElementDocument.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/Property.h" +#include "../../../Include/RmlUi/Core/Elements/DataFormatter.h" +#include "../../../Include/RmlUi/Core/Elements/ElementDataGridRow.h" + +namespace Rml { + +ElementDataGrid::ElementDataGrid(const String& tag) : Element(tag) +{ + XMLAttributes attributes; + + // Create the row for the column headers: + ElementPtr element = Factory::InstanceElement(this, "#rmlctl_datagridrow", "datagridheader", attributes); + header = static_cast(element.get()); + header->SetProperty(PropertyId::Display, Property(Style::Display::Block)); + header->Initialise(this); + AppendChild(std::move(element)); + + element = Factory::InstanceElement(this, "*", "datagridbody", attributes); + body = element.get(); + body->SetProperty(PropertyId::Display, Property(Style::Display::Block)); + body->SetProperty(PropertyId::Width, Property(Style::Width::Auto)); + AppendChild(std::move(element)); + + element = Factory::InstanceElement(this, "#rmlctl_datagridrow", "datagridroot", attributes); + root = static_cast(element.get()); + root->SetProperty(PropertyId::Display, Property(Style::Display::None)); + root->Initialise(this); + AppendChild(std::move(element), false); + + SetProperty(PropertyId::OverflowX, Property(Style::Overflow::Auto)); + SetProperty(PropertyId::OverflowY, Property(Style::Overflow::Auto)); + + new_data_source = ""; +} + +ElementDataGrid::~ElementDataGrid() +{ +} + +void ElementDataGrid::SetDataSource(const String& data_source_name) +{ + new_data_source = data_source_name; +} + +// Adds a column to the table. +bool ElementDataGrid::AddColumn(const String& fields, const String& formatter, float initial_width, const String& header_rml) +{ + ElementPtr header_element = Factory::InstanceElement(this, "datagridcolumn", "datagridcolumn", XMLAttributes()); + if (!header_element) + return false; + + if (!Factory::InstanceElementText(header_element.get(), header_rml)) + { + return false; + } + + AddColumn(fields, formatter, initial_width, std::move(header_element)); + return true; +} + +// Adds a column to the table. +void ElementDataGrid::AddColumn(const String& fields, const String& formatter, float initial_width, ElementPtr header_element) +{ + Column column; + StringUtilities::ExpandString(column.fields, fields); + column.formatter = DataFormatter::GetDataFormatter(formatter); + column.header = header; + column.current_width = initial_width; + column.refresh_on_child_change = false; + + // The header elements are added to the header row at the top of the table. + if (header_element) + { + header_element->SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); + + // Push all the width properties from the column onto the header element. + String width = header_element->GetAttribute("width", "100%"); + header_element->SetProperty("width", width); + + header->AppendChild(std::move(header_element)); + } + + // Add the fields that this column requires to the concatenated string of all column fields. + for (size_t i = 0; i < column.fields.size(); i++) + { + // Don't append the depth or num_children fields, as they're handled by the row. + if (column.fields[i] == DataSource::NUM_CHILDREN) + { + column.refresh_on_child_change = true; + } + else if (column.fields[i] != DataSource::DEPTH) + { + if (!column_fields.empty()) + { + column_fields += ","; + } + column_fields += column.fields[i]; + } + } + + columns.push_back(column); + + Dictionary parameters; + parameters["index"] = (int)(columns.size() - 1); + if (DispatchEvent(EventId::Columnadd, parameters)) + { + root->RefreshRows(); + DirtyLayout(); + } +} + +// Returns the number of columns in this table +int ElementDataGrid::GetNumColumns() +{ + return (int)columns.size(); +} + +// Returns the column at the specified index. +const ElementDataGrid::Column* ElementDataGrid::GetColumn(int column_index) +{ + if (column_index < 0 || column_index >= (int)columns.size()) + { + RMLUI_ERROR; + return nullptr; + } + + return &columns[column_index]; +} + +/// Returns a CSV string containing all the fields that each column requires, in order. +const String& ElementDataGrid::GetAllColumnFields() +{ + return column_fields; +} + +// Adds a new row to the table - usually only called by child rows. +ElementDataGridRow* ElementDataGrid::AddRow(ElementDataGridRow* parent, int index) +{ + // Now we make a new row at the right place then return it. + XMLAttributes attributes; + ElementPtr element = Factory::InstanceElement(this, "#rmlctl_datagridrow", "datagridrow", attributes); + ElementDataGridRow* new_row = rmlui_dynamic_cast< ElementDataGridRow* >(element.get()); + + new_row->Initialise(this, parent, index, header, parent->GetDepth() + 1); + + // We need to work out the table-specific row. + int table_relative_index = parent->GetChildTableRelativeIndex(index); + + Element* child_to_insert_before = nullptr; + if (table_relative_index < body->GetNumChildren()) + { + child_to_insert_before = body->GetChild(table_relative_index); + } + body->InsertBefore(std::move(element), child_to_insert_before); + + // As the rows have changed, we need to lay out the document again. + DirtyLayout(); + + return new_row; +} + +// Removes a row from the table. +void ElementDataGrid::RemoveRows(int index, int num_rows) +{ + for (int i = 0; i < num_rows; i++) + { + ElementDataGridRow* row = GetRow(index); + row->SetDataSource(""); + body->RemoveChild(row); + } + + // As the rows have changed, we need to lay out the document again. + DirtyLayout(); +} + +// Returns the number of rows in the table +int ElementDataGrid::GetNumRows() const +{ + return body->GetNumChildren(); +} + +// Returns the row at the given index in the table. +ElementDataGridRow* ElementDataGrid::GetRow(int index) const +{ + // We need to add two to the index, to skip the header row. + ElementDataGridRow* row = rmlui_dynamic_cast< ElementDataGridRow* >(body->GetChild(index)); + return row; +} + +void ElementDataGrid::OnUpdate() +{ + if (!new_data_source.empty()) + { + root->SetDataSource(new_data_source); + new_data_source = ""; + } + + bool any_new_children = root->UpdateChildren(); + if (any_new_children) + { + DispatchEvent(EventId::Rowupdate, Dictionary()); + } +} + + +void ElementDataGrid::OnResize() +{ + SetScrollTop(GetScrollHeight() - GetClientHeight()); + + for (int i = 0; i < header->GetNumChildren(); i++) + { + Element* child = header->GetChild(i); + columns[i].current_width = child->GetBox().GetSize(Box::MARGIN).x; + } +} + +// Gets the markup and content of the element. +void ElementDataGrid::GetInnerRML(String& content) const +{ + // The only content we have is the columns, and inside them the header elements. + for (size_t i = 0; i < columns.size(); i++) + { + Element* header_element = header->GetChild((int)i); + + String column_fields; + for (size_t j = 0; j < columns[i].fields.size(); j++) + { + if (j != columns[i].fields.size() - 1) + { + column_fields += ","; + } + column_fields += columns[i].fields[j]; + } + String width_attribute = header_element->GetAttribute("width", ""); + + content += CreateString(column_fields.size() + 32, "GetInnerRML(content); + content += ""; + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridCell.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridCell.cpp new file mode 100644 index 000000000..706d5f31f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridCell.cpp @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementDataGridCell.h" +#include "../../../Include/RmlUi/Core/Event.h" +#include "../../../Include/RmlUi/Core/Property.h" +#include "../../../Include/RmlUi/Core/Elements/ElementDataGrid.h" + +namespace Rml { + +ElementDataGridCell::ElementDataGridCell(const String& tag) : Element(tag), column(0), header(nullptr) +{ +} + +ElementDataGridCell::~ElementDataGridCell() +{ +} + +void ElementDataGridCell::Initialise(int _column, Element* _header) +{ + column = _column; + header = _header; + if (header) + { + if(auto p = header->GetLocalProperty("width")) + SetProperty(PropertyId::Width, *p); + } +} + +int ElementDataGridCell::GetColumn() +{ + return column; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridExpandButton.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridExpandButton.cpp new file mode 100644 index 000000000..35b1faa57 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridExpandButton.cpp @@ -0,0 +1,78 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementDataGridExpandButton.h" +#include "../../../Include/RmlUi/Core/Elements/ElementDataGridRow.h" + +namespace Rml { + +ElementDataGridExpandButton::ElementDataGridExpandButton(const String& tag) : Element(tag) +{ + SetClass("collapsed", true); +} + +ElementDataGridExpandButton::~ElementDataGridExpandButton() +{ +} + +void ElementDataGridExpandButton::ProcessDefaultAction(Event& event) +{ + Element::ProcessDefaultAction(event); + + if (event == EventId::Click && event.GetCurrentElement() == this) + { + // Look for the first data grid row above us, and toggle their on/off + // state. + Element* parent = GetParentNode(); + ElementDataGridRow* parent_row; + do + { + parent_row = rmlui_dynamic_cast< ElementDataGridRow* >(parent); + parent = parent->GetParentNode(); + } + while (parent && !parent_row); + + if (parent_row) + { + parent_row->ToggleRow(); + + if (parent_row->IsRowExpanded()) + { + SetClass("collapsed", false); + SetClass("expanded", true); + } + else + { + SetClass("collapsed", true); + SetClass("expanded", false); + } + } + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridRow.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridRow.cpp new file mode 100644 index 000000000..b33478369 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementDataGridRow.cpp @@ -0,0 +1,695 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementDataGridRow.h" +#include "../../../Include/RmlUi/Core/Elements/DataSource.h" +#include "../../../Include/RmlUi/Core/Elements/DataFormatter.h" +#include "../../../Include/RmlUi/Core/Elements/ElementDataGrid.h" +#include "../../../Include/RmlUi/Core/Elements/ElementDataGridCell.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/Types.h" +#include "../Clock.h" + +namespace Rml { + +static const float MAX_UPDATE_TIME = 0.001f; + +ElementDataGridRow::ElementDataGridRow(const String& tag) : Element(tag) +{ + parent_grid = nullptr; + parent_row = nullptr; + child_index = -1; + depth = -1; + + data_source = nullptr; + + table_relative_index = -1; + table_relative_index_dirty = true; + dirty_cells = true; + dirty_children = false; + row_expanded = true; + + SetProperty(PropertyId::WhiteSpace, Property(Style::WhiteSpace::Nowrap)); + SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); +} + +ElementDataGridRow::~ElementDataGridRow() +{ + if (data_source) + { + data_source->DetachListener(this); + data_source = nullptr; + } +} + +void ElementDataGridRow::Initialise(ElementDataGrid* _parent_grid, ElementDataGridRow* _parent_row, int _child_index, ElementDataGridRow* header_row, int _depth) +{ + parent_grid = _parent_grid; + parent_row = _parent_row; + child_index = _child_index; + depth = _depth; + + // We start all the rows collapsed, except for the root row. + if (child_index != -1) + { + row_expanded = false; + } + + int num_columns = parent_grid->GetNumColumns(); + XMLAttributes cell_attributes; + for (int i = 0; i < num_columns; i++) + { + ElementPtr element = Factory::InstanceElement(this, "#rmlctl_datagridcell", "datagridcell", cell_attributes); + ElementDataGridCell* cell = rmlui_dynamic_cast< ElementDataGridCell* >(element.get()); + cell->Initialise(i, header_row->GetChild(i)); + cell->SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); + AppendChild(std::move(element)); + } +} + +void ElementDataGridRow::SetChildIndex(int _child_index) +{ + if (child_index != _child_index) + { + child_index = _child_index; + + if (parent_row) + { + parent_row->ChildChanged(child_index); + } + } +} + +int ElementDataGridRow::GetDepth() +{ + return depth; +} + +void ElementDataGridRow::SetDataSource(const String& data_source_name) +{ + if (data_source != nullptr) + { + data_source->DetachListener(this); + data_source = nullptr; + } + + if (ParseDataSource(data_source, data_table, data_source_name)) + { + data_source->AttachListener(this); + RefreshRows(); + } +} + +bool ElementDataGridRow::UpdateChildren() +{ + if (dirty_children) + { + double start_time = Clock::GetElapsedTime(); + + RowQueue dirty_rows; + dirty_rows.push(this); + + while (!dirty_rows.empty()) + { + ElementDataGridRow* dirty_row = dirty_rows.front(); + dirty_rows.pop(); + + float time_slice = MAX_UPDATE_TIME - float(Clock::GetElapsedTime() - start_time); + if (time_slice <= 0.0f) + break; + + dirty_row->LoadChildren(time_slice); + for (size_t i = 0; i < dirty_row->children.size(); i++) + { + if (dirty_row->children[i]->dirty_cells || dirty_row->children[i]->dirty_children) + { + dirty_rows.push(dirty_row->children[i]); + } + } + } + + return true; + } + + return false; +} + +// Returns the number of children that aren't dirty (have been loaded) +int ElementDataGridRow::GetNumLoadedChildren() +{ + int num_loaded_children = 0; + for (size_t i = 0; i < children.size(); i++) + { + if (!children[i]->dirty_cells) + { + num_loaded_children++; + } + num_loaded_children += children[i]->GetNumLoadedChildren(); + } + + return num_loaded_children; +} + +bool ElementDataGridRow::IsRowExpanded() +{ + return row_expanded; +} + +void ElementDataGridRow::ExpandRow() +{ + row_expanded = true; + + for (size_t i = 0; i < children.size(); i++) + { + children[i]->Show(); + } + + DirtyLayout(); +} + +void ElementDataGridRow::CollapseRow() +{ + row_expanded = false; + + for (size_t i = 0; i < children.size(); i++) + { + children[i]->Hide(); + } + + DirtyLayout(); +} + +void ElementDataGridRow::ToggleRow() +{ + if (row_expanded) + { + CollapseRow(); + } + else + { + ExpandRow(); + } +} + +// Returns the index of this row, relative to its parent. +int ElementDataGridRow::GetParentRelativeIndex() +{ + return child_index; +} + +// Returns the index of this row, relative to the table rather than its parent. +int ElementDataGridRow::GetTableRelativeIndex() +{ + if (!parent_row) + { + return -1; + } + + if (table_relative_index_dirty) + { + table_relative_index = parent_row->GetChildTableRelativeIndex(child_index); + table_relative_index_dirty = false; + } + + return table_relative_index; +} + +// Returns the parent row of this row. +ElementDataGridRow* ElementDataGridRow::GetParentRow() +{ + return parent_row; +} + +// Returns the grid that this row belongs to. +ElementDataGrid* ElementDataGridRow::GetParentGrid() +{ + return parent_grid; +} + +void ElementDataGridRow::OnDataSourceDestroy(DataSource* /*data_source*/) +{ + if(data_source != nullptr) + { + data_source->DetachListener(this); + data_source = nullptr; + } + RemoveChildren(); +} + +void ElementDataGridRow::OnRowAdd(DataSource* _data_source, const String& _data_table, int first_row_added, int num_rows_added) +{ + if (_data_source == data_source && _data_table == data_table) + AddChildren(first_row_added, num_rows_added); +} + +void ElementDataGridRow::OnRowRemove(DataSource* _data_source, const String& _data_table, int first_row_removed, int num_rows_removed) +{ + if (_data_source == data_source && _data_table == data_table) + RemoveChildren(first_row_removed, num_rows_removed); +} + +void ElementDataGridRow::OnRowChange(DataSource* _data_source, const String& _data_table, int first_row_changed, int num_rows_changed) +{ + if (_data_source == data_source && _data_table == data_table) + ChangeChildren(first_row_changed, num_rows_changed); +} + +void ElementDataGridRow::OnRowChange(DataSource* _data_source, const String& _data_table) +{ + if (_data_source == data_source && _data_table == data_table) + RefreshRows(); +} + +// Removes all the child cells and fetches them again from the data source. +void ElementDataGridRow::RefreshRows() +{ + // Remove all our child rows from the table. + RemoveChildren(); + + // Load the children from the data source. + if (data_source != nullptr) + { + int num_rows = data_source->GetNumRows(data_table); + if (num_rows > 0) + { + AddChildren(0, num_rows); + } + } +} + +// Called when a row change (addition or removal) occurs in one of our +// children. +void ElementDataGridRow::ChildChanged(int child_row_index) +{ + for (int i = child_row_index + 1; i < (int)children.size(); i++) + { + children[i]->DirtyTableRelativeIndex(); + } + + if (parent_row) + { + parent_row->ChildChanged(child_index); + } +} + +// Checks if any columns are dependent on the number of children present, and +// refreshes them from the data source if they are. +void ElementDataGridRow::RefreshChildDependentCells() +{ + if (child_index != -1) + { + for (int i = 0; i < parent_grid->GetNumColumns(); i++) + { + const ElementDataGrid::Column* column = parent_grid->GetColumn(i); + if (column->refresh_on_child_change) + { + DirtyCells(); + } + } + } +} + +// Called whenever a row is added or removed above ours. +void ElementDataGridRow::DirtyTableRelativeIndex() +{ + if (table_relative_index_dirty) + return; + + for (size_t i = 0; i < children.size(); i++) + { + children[i]->DirtyTableRelativeIndex(); + } + + table_relative_index_dirty = true; +} + +int ElementDataGridRow::GetChildTableRelativeIndex(int child_index) +{ + // We start with our index, then count down each of the children until we + // reach child_index. For each child we skip by add one (for the child + // itself) and all of its descendants. + int child_table_index = GetTableRelativeIndex() + 1; + + for (int i = 0; i < child_index; i++) + { + child_table_index++; + child_table_index += children[i]->GetNumDescendants(); + } + + return child_table_index; +} + +// Adds children underneath this row, and fetches their contents (and possible +// children) from the row's data source. +void ElementDataGridRow::AddChildren(int first_row_added, int num_rows_added) +{ + if (first_row_added == -1) + { + first_row_added = (int)children.size(); + } + + // We need to make a row for each new child, then pass through the cell + // information and the child's data source (if one exists.) + if (data_source != nullptr) + { + for (int i = 0; i < num_rows_added; i++) + { + int row_index = first_row_added + i; + + // Make a new row: + ElementDataGridRow* new_row = parent_grid->AddRow(this, row_index); + children.insert(children.begin() + row_index, new_row); + + if (!row_expanded) + { + new_row->SetProperty(PropertyId::Display, Property(Style::Display::None)); + } + } + + for (int i = first_row_added + num_rows_added; i < (int)children.size(); i++) + { + children[i]->SetChildIndex(i); + children[i]->DirtyTableRelativeIndex(); + } + + if (parent_row) + { + parent_row->ChildChanged(child_index); + } + } + + RefreshChildDependentCells(); + DirtyRow(); + + Dictionary parameters; + parameters["first_row_added"] = GetChildTableRelativeIndex(first_row_added); + parameters["num_rows_added"] = num_rows_added; + + parent_grid->DispatchEvent(EventId::Rowadd, parameters); +} + +void ElementDataGridRow::RemoveChildren(int first_row_removed, int num_rows_removed) +{ + if (num_rows_removed == -1) + num_rows_removed = (int)children.size() - first_row_removed; + + for (int i = num_rows_removed - 1; i >= 0; i--) + { + children[first_row_removed + i]->RemoveChildren(); + parent_grid->RemoveRows(children[first_row_removed + i]->GetTableRelativeIndex()); + } + + children.erase(children.begin() + first_row_removed, children.begin() + (first_row_removed + num_rows_removed)); + for (int i = first_row_removed; i < (int) children.size(); i++) + { + children[i]->SetChildIndex(i); + children[i]->DirtyTableRelativeIndex(); + } + + Dictionary parameters; + parameters["first_row_removed"] = GetChildTableRelativeIndex(first_row_removed); + parameters["num_rows_removed"] = num_rows_removed; + + parent_grid->DispatchEvent(EventId::Rowremove, parameters); +} + +void ElementDataGridRow::ChangeChildren(int first_row_changed, int num_rows_changed) +{ + for (int i = first_row_changed; i < first_row_changed + num_rows_changed; i++) + children[i]->DirtyCells(); + + Dictionary parameters; + parameters["first_row_changed"] = GetChildTableRelativeIndex(first_row_changed); + parameters["num_rows_changed"] = num_rows_changed; + + parent_grid->DispatchEvent(EventId::Rowchange, parameters); +} + +// Returns the number of rows under this row (children, grandchildren, etc) +int ElementDataGridRow::GetNumDescendants() +{ + int num_descendants = (int)children.size(); + + for (size_t i = 0; i < children.size(); i++) + num_descendants += children[i]->GetNumDescendants(); + + return num_descendants; +} + +// Adds the cell contents, and marks the row as loaded. +void ElementDataGridRow::Load(const DataQuery& row_information) +{ + // Check for a data source. If they're both set then we set + // ourselves up with it. + if (row_information.IsFieldSet(DataSource::CHILD_SOURCE)) + { + String data_source = row_information.Get< String >(DataSource::CHILD_SOURCE, ""); + if (!data_source.empty()) + { + SetDataSource(data_source); + } + else + { + // If we've no data source, then we should remove any children. + RemoveChildren(); + } + } + + // Now load our cells. + for (int i = 0; i < parent_grid->GetNumColumns(); i++) + { + Element* cell = GetChild(i); + + if (cell) + { + // Fetch the column: + const ElementDataGrid::Column* column = parent_grid->GetColumn(i); + + // Now we use the column's formatter to process the raw data into the + // XML string, and parse that into the actual Elements. If there is + // no formatter, then we just send through the raw text, in CVS form. + StringList raw_data; + raw_data.reserve(column->fields.size()); + size_t raw_data_total_len = 0; + for (size_t j = 0; j < column->fields.size(); j++) + { + if (column->fields[j] == DataSource::DEPTH) + { + raw_data.push_back(CreateString(8, "%d", depth)); + raw_data_total_len += raw_data.back().length(); + } + else if (column->fields[j] == DataSource::NUM_CHILDREN) + { + raw_data.push_back(CreateString(8, "%d", children.size())); + raw_data_total_len += raw_data.back().length(); + } + else + { + raw_data.push_back(row_information.Get< String >(column->fields[j], "")); + raw_data_total_len += raw_data.back().length(); + } + } + + String cell_string; + if (column->formatter) + { + column->formatter->FormatData(cell_string, raw_data); + } + else + { + cell_string.reserve(raw_data_total_len + raw_data.size() + 1); + for (size_t j = 0; j < raw_data.size(); j++) + { + if (j > 0) + { + cell_string += ","; + } + cell_string += raw_data[j]; + } + } + + // Remove all the cell's current contents. + while (cell->GetNumChildren(true) > 0) + { + cell->RemoveChild(cell->GetChild(0)); + } + + // Add the new contents to the cell. + Factory::InstanceElementText(cell, cell_string); + } + else + { + RMLUI_ERROR; + } + } + + dirty_cells = false; +} + +// Instantiates the children that haven't been fully loaded yet. +void ElementDataGridRow::LoadChildren(float time_slice) +{ + double start_time = Clock::GetElapsedTime(); + + int data_query_offset = -1; + int data_query_limit = -1; + + // Iterate through the list of children and find the holes of unloaded + // rows. + // - If we find an unloaded element, and we haven't set the offset + // (beginning of the hole), then we've hit a new hole. We set the offset + // to the current index and the limit (size of the hole) to 1. If we've + // found a hole already and we find an unloaded element, then we + // increase the size of the hole. + // - The end of a hole is either a loaded element or the end of the list. + // In either case, we check if we have a hole that's unfilled, and if + // so, we fill it. + bool any_dirty_children = false; + for (size_t i = 0; i < children.size() && float(Clock::GetElapsedTime() - start_time) < time_slice; i++) + { + if (children[i]->dirty_cells) + { + any_dirty_children = true; + if (data_query_offset == -1) + { + data_query_offset = (int)i; + data_query_limit = 1; + } + else + { + data_query_limit++; + } + } + else if (children[i]->dirty_children) + { + any_dirty_children = true; + } + + bool end_of_list = i == children.size() - 1; + bool unfilled_hole = data_query_offset != -1; + bool end_of_hole_found = !children[i]->dirty_cells; + + // If this is the last element and we've found no holes (or filled them + // all in) then all our children are loaded. + if (end_of_list && !unfilled_hole) + { + if (!any_dirty_children) + { + dirty_children = false; + } + } + // Otherwise, if we have a hole outstanding and we've either hit the + // end of the list or the end of the hole, fill the hole. + else if (unfilled_hole && (end_of_list || end_of_hole_found)) + { + float load_time_slice = time_slice - float(Clock::GetElapsedTime() - start_time); + LoadChildren(data_query_offset, data_query_limit, load_time_slice); + data_query_offset = -1; + data_query_limit = -1; + } + } + + if (children.empty()) + { + dirty_children = false; + } +} + +void ElementDataGridRow::LoadChildren(int first_row_to_load, int num_rows_to_load, double time_slice) +{ + double start_time = Clock::GetElapsedTime(); + + // Now fetch these new children from the data source, pass them + // through each column's data formatter, and add them as our new + // child rows. + String column_query = parent_grid->GetAllColumnFields() + "," + DataSource::CHILD_SOURCE; + DataQuery query(data_source, data_table, column_query, first_row_to_load, num_rows_to_load); + + for (int i = 0; i < num_rows_to_load; i++) + { + int index = first_row_to_load + i; + + if (!query.NextRow()) + { + Log::Message(Log::LT_WARNING, "Failed to load row %d from data source %s", i, data_table.c_str()); + } + + // Now load the child with the row in the query. + children[index]->Load(query); + + if (float(Clock::GetElapsedTime() - start_time) > time_slice) + { + break; + } + } +} + +void ElementDataGridRow::DirtyCells() +{ + dirty_cells = true; + if (parent_row) + { + parent_row->DirtyRow(); + } +} + +void ElementDataGridRow::DirtyRow() +{ + dirty_children = true; + if (parent_row) + { + parent_row->DirtyRow(); + } +} + +// Sets this row's child rows to be visible. +void ElementDataGridRow::Show() +{ + SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); + + if (row_expanded) + { + for (size_t i = 0; i < children.size(); i++) + { + children[i]->Show(); + } + } +} + +// Sets this row's children to be invisible. +void ElementDataGridRow::Hide() +{ + SetProperty(PropertyId::Display, Property(Style::Display::None)); + + for (size_t i = 0; i < children.size(); i++) + { + children[i]->Hide(); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementForm.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementForm.cpp new file mode 100644 index 000000000..f1361d011 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementForm.cpp @@ -0,0 +1,92 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementForm.h" +#include "../../../Include/RmlUi/Core/Dictionary.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h" + +namespace Rml { + +// Constructs a new ElementForm. This should not be called directly; use the Factory instead. +ElementForm::ElementForm(const String& tag) : Element(tag) +{ +} + +ElementForm::~ElementForm() +{ +} + +// Submits the form. +void ElementForm::Submit(const String& name, const String& submit_value) +{ + Dictionary values; + if (name.empty()) + values["submit"] = submit_value; + else + values[name] = submit_value; + + ElementList form_controls; + ElementUtilities::GetElementsByTagName(form_controls, this, "input"); + ElementUtilities::GetElementsByTagName(form_controls, this, "textarea"); + ElementUtilities::GetElementsByTagName(form_controls, this, "select"); + ElementUtilities::GetElementsByTagName(form_controls, this, "dataselect"); + + for (size_t i = 0; i < form_controls.size(); i++) + { + ElementFormControl* control = rmlui_dynamic_cast< ElementFormControl* >(form_controls[i]); + if (!control) + continue; + + // Skip disabled controls. + if (control->IsDisabled()) + continue; + + // Only process controls that should be submitted. + if (!control->IsSubmitted()) + continue; + + String control_name = control->GetName(); + String control_value = control->GetValue(); + + // Skip over unnamed form controls. + if (control_name.empty()) + continue; + + // If the item already exists, append to it. + Variant* value = GetIf(values, control_name); + if (value != nullptr) + *value = value->Get< String >() + ", " + control_value; + else + values[control_name] = control_value; + } + + DispatchEvent(EventId::Submit, values); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementFormControl.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControl.cpp new file mode 100644 index 000000000..59a1e031f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControl.cpp @@ -0,0 +1,98 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h" +#include "../../../Include/RmlUi/Core/ComputedValues.h" + +namespace Rml { + +ElementFormControl::ElementFormControl(const String& tag) : Element(tag) +{ + SetProperty(PropertyId::TabIndex, Property(Style::TabIndex::Auto)); +} + +ElementFormControl::~ElementFormControl() +{ +} + +// Returns the name of the form control. +String ElementFormControl::GetName() const +{ + return GetAttribute("name", ""); +} + +// Sets the name of the form control. +void ElementFormControl::SetName(const String& name) +{ + SetAttribute("name", name); +} + +// Returns if this value should be submitted with the form +bool ElementFormControl::IsSubmitted() +{ + return true; +} + +// Returns the disabled status of the form control. +bool ElementFormControl::IsDisabled() const +{ + return HasAttribute("disabled"); +} + +// Sets the disabled status of the form control. +void ElementFormControl::SetDisabled(bool disable) +{ + if (disable) + SetAttribute("disabled", ""); + else + RemoveAttribute("disabled"); +} + +// Checks for changes to the 'disabled' attribute. +void ElementFormControl::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + Element::OnAttributeChange(changed_attributes); + + if (changed_attributes.find("disabled") != changed_attributes.end()) + { + bool is_disabled = IsDisabled(); + SetPseudoClass("disabled", is_disabled); + + // Disable focus when element is disabled. This will also prevent click + // events (when originating from user inputs, see Context) to reach the element. + if (is_disabled) + { + SetProperty(PropertyId::Focus, Property(Style::Focus::None)); + Blur(); + } + else + RemoveProperty("focus"); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlDataSelect.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlDataSelect.cpp new file mode 100644 index 000000000..6d1460015 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlDataSelect.cpp @@ -0,0 +1,236 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlDataSelect.h" +#include "../../../Include/RmlUi/Core/Elements/DataQuery.h" +#include "../../../Include/RmlUi/Core/Elements/DataSource.h" +#include "../../../Include/RmlUi/Core/Elements/DataFormatter.h" +#include "WidgetDropDown.h" + +namespace Rml { + +// Constructs a new ElementFormControlDataSelect. +ElementFormControlDataSelect::ElementFormControlDataSelect(const String& tag) : ElementFormControlSelect(tag) +{ + data_source = nullptr; + initialised = false; +} + +ElementFormControlDataSelect::~ElementFormControlDataSelect() +{ + if (data_source != nullptr) { + data_source->DetachListener(this); + data_source = nullptr; + } +} + +// Sets the data source the control's options are driven from. +void ElementFormControlDataSelect::SetDataSource(const String& _data_source) +{ + SetAttribute("source", _data_source); +} + +// If a new data source has been set on the control, this will attach to it and build the initial +// options. +void ElementFormControlDataSelect::OnUpdate() +{ + if (!initialised) + { + initialised = true; + + if (ParseDataSource(data_source, data_table, GetAttribute< String >("source", ""))) + { + data_source->AttachListener(this); + BuildOptions(); + } + } +} + +// Checks for changes to the data source or formatting attributes. +void ElementFormControlDataSelect::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + ElementFormControlSelect::OnAttributeChange(changed_attributes); + + if (changed_attributes.find("source") != changed_attributes.end()) + { + if (data_source != nullptr) { + data_source->DetachListener(this); + data_source = nullptr; + } + + initialised = false; + } + else if (changed_attributes.find("fields") != changed_attributes.end() || + changed_attributes.find("valuefield") != changed_attributes.end() || + changed_attributes.find("formatter") != changed_attributes.end()) + { + BuildOptions(); + } +} + +// Detaches from the data source and rebuilds the options. +void ElementFormControlDataSelect::OnDataSourceDestroy(DataSource* _data_source) +{ + if (data_source == _data_source) + { + data_source->DetachListener(this); + data_source = nullptr; + data_table = ""; + + BuildOptions(); + } +} + +// Rebuilds the available options from the data source. +void ElementFormControlDataSelect::OnRowAdd(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& table, int RMLUI_UNUSED_PARAMETER(first_row_added), int RMLUI_UNUSED_PARAMETER(num_rows_added)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(first_row_added); + RMLUI_UNUSED(num_rows_added); + + if (table == data_table) + BuildOptions(); +} + +// Rebuilds the available options from the data source. +void ElementFormControlDataSelect::OnRowRemove(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& table, int RMLUI_UNUSED_PARAMETER(first_row_removed), int RMLUI_UNUSED_PARAMETER(num_rows_removed)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(first_row_removed); + RMLUI_UNUSED(num_rows_removed); + + if (table == data_table) + BuildOptions(); +} + +// Rebuilds the available options from the data source. +void ElementFormControlDataSelect::OnRowChange(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& table, int RMLUI_UNUSED_PARAMETER(first_row_changed), int RMLUI_UNUSED_PARAMETER(num_rows_changed)) +{ + RMLUI_UNUSED(data_source); + RMLUI_UNUSED(first_row_changed); + RMLUI_UNUSED(num_rows_changed); + + if (table == data_table) + BuildOptions(); +} + +// Rebuilds the available options from the data source. +void ElementFormControlDataSelect::OnRowChange(DataSource* RMLUI_UNUSED_PARAMETER(data_source), const String& table) +{ + RMLUI_UNUSED(data_source); + + if (table == data_table) + BuildOptions(); +} + +// Builds the option list from the data source. +void ElementFormControlDataSelect::BuildOptions() +{ + widget->ClearOptions(); + + if (data_source == nullptr) + return; + + // Store the old selection value and index. These will be used to restore the selection to the + // most appropriate option after the options have been rebuilt. + String old_value = GetValue(); + int old_selection = GetSelection(); + + String fields_attribute = GetAttribute("fields", ""); + String valuefield_attribute = GetAttribute("valuefield", ""); + String data_formatter_attribute = GetAttribute("formatter", ""); + DataFormatter* data_formatter = nullptr; + + // Process the attributes. + if (fields_attribute.empty()) + { + Log::Message(Log::LT_ERROR, "DataQuery failed, no fields specified for %s.", GetTagName().c_str()); + return; + } + + if (valuefield_attribute.empty()) + { + valuefield_attribute = fields_attribute.substr(0, fields_attribute.find(",")); + } + + if (!data_formatter_attribute.empty()) + { + data_formatter = DataFormatter::GetDataFormatter(data_formatter_attribute); + if (!data_formatter) + Log::Message(Log::LT_WARNING, "Unable to find data formatter named '%s', formatting skipped.", data_formatter_attribute.c_str()); + } + + // Build a list of attributes + String fields(valuefield_attribute); + fields += ","; + fields += fields_attribute; + + DataQuery query(data_source, data_table, fields); + while (query.NextRow()) + { + StringList fields_list; + String value = query.Get(0, ""); + + for (size_t i = 1; i < query.GetNumFields(); ++i) + fields_list.push_back(query.Get< String>(i, "")); + + String formatted; + if (fields_list.size() > 0) + formatted = fields_list[0]; + + if (data_formatter) + data_formatter->FormatData(formatted, fields_list); + + // Add the data as an option. + widget->AddOption(formatted, value, -1, false); + } + + // If an option was selected before, attempt to restore the selection to it. + if (old_selection > -1) + { + // Try to find a selection with the same value as the previous one. + for (int i = 0; i < GetNumOptions(); ++i) + { + SelectOption* option = GetOption(i); + if (option->GetValue() == old_value) + { + widget->SetSelection(i, true); + return; + } + } + + // Failed to find an option with the same value. Attempt to at least set the same index. + int new_selection = Math::Clamp(old_selection, 0, GetNumOptions() - 1); + if (GetNumOptions() == 0) + new_selection = -1; + + widget->SetSelection(new_selection, true); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlInput.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlInput.cpp new file mode 100644 index 000000000..8a39ba73e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlInput.cpp @@ -0,0 +1,187 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" +#include "../../../Include/RmlUi/Core/Event.h" +#include "InputTypeButton.h" +#include "InputTypeCheckbox.h" +#include "InputTypeRadio.h" +#include "InputTypeRange.h" +#include "InputTypeSubmit.h" +#include "InputTypeText.h" + +namespace Rml { + +// Constructs a new ElementFormControlInput. +ElementFormControlInput::ElementFormControlInput(const String& tag) : ElementFormControl(tag) +{ + // OnAttributeChange will be called right after this, possible with a non-default type. Thus, + // creating the default InputTypeText here may result in it being destroyed in just a few moments. + // Instead, we create the InputTypeText in OnAttributeChange in the case where the type attribute has not been set. + type = nullptr; +} + +ElementFormControlInput::~ElementFormControlInput() +{ + delete type; +} + +// Returns a string representation of the current value of the form control. +String ElementFormControlInput::GetValue() const +{ + RMLUI_ASSERT(type); + return type->GetValue(); +} + +// Sets the current value of the form control. +void ElementFormControlInput::SetValue(const String& value) +{ + SetAttribute("value", value); +} + +// Returns if this value should be submitted with the form. +bool ElementFormControlInput::IsSubmitted() +{ + RMLUI_ASSERT(type); + return type->IsSubmitted(); +} + +// Updates the element's underlying type. +void ElementFormControlInput::OnUpdate() +{ + RMLUI_ASSERT(type); + type->OnUpdate(); +} + +// Renders the element's underlying type. +void ElementFormControlInput::OnRender() +{ + RMLUI_ASSERT(type); + type->OnRender(); +} + +void ElementFormControlInput::OnResize() +{ + RMLUI_ASSERT(type); + type->OnResize(); +} + +// Checks for necessary functional changes in the control as a result of changed attributes. +void ElementFormControlInput::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + ElementFormControl::OnAttributeChange(changed_attributes); + + String new_type_name; + + auto it_type = changed_attributes.find("type"); + if (it_type != changed_attributes.end()) + { + new_type_name = it_type->second.Get("text"); + } + + if (!type || (!new_type_name.empty() && new_type_name != type_name)) + { + InputType* new_type = nullptr; + + if (new_type_name == "password") + new_type = new InputTypeText(this, InputTypeText::OBSCURED); + else if (new_type_name == "radio") + new_type = new InputTypeRadio(this); + else if (new_type_name == "checkbox") + new_type = new InputTypeCheckbox(this); + else if (new_type_name == "range") + new_type = new InputTypeRange(this); + else if (new_type_name == "submit") + new_type = new InputTypeSubmit(this); + else if (new_type_name == "button") + new_type = new InputTypeButton(this); + else + { + new_type_name = "text"; + new_type = new InputTypeText(this); + } + + if (new_type) + { + delete type; + type = new_type; + + if(!type_name.empty()) + SetClass(type_name, false); + SetClass(new_type_name, true); + type_name = new_type_name; + + DirtyLayout(); + } + } + + RMLUI_ASSERT(type); + + if (!type->OnAttributeChange(changed_attributes)) + DirtyLayout(); +} + +// Called when properties on the element are changed. +void ElementFormControlInput::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + ElementFormControl::OnPropertyChange(changed_properties); + + if (type != nullptr) + type->OnPropertyChange(changed_properties); +} + +// If we are the added element, this will pass the call onto our type handler. +void ElementFormControlInput::OnChildAdd(Element* child) +{ + if (child == this && type != nullptr) + type->OnChildAdd(); +} + +// If we are the removed element, this will pass the call onto our type handler. +void ElementFormControlInput::OnChildRemove(Element* child) +{ + if (child == this && type != nullptr) + type->OnChildRemove(); +} + +// Handles the "click" event to toggle the control's checked status. +void ElementFormControlInput::ProcessDefaultAction(Event& event) +{ + ElementFormControl::ProcessDefaultAction(event); + if(type != nullptr) + type->ProcessDefaultAction(event); +} + +bool ElementFormControlInput::GetIntrinsicDimensions(Vector2f& dimensions) +{ + if (!type) + return false; + return type->GetIntrinsicDimensions(dimensions); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlSelect.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlSelect.cpp new file mode 100644 index 000000000..5e8e36e45 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlSelect.cpp @@ -0,0 +1,169 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlSelect.h" +#include "../../../Include/RmlUi/Core/ElementText.h" +#include "../../../Include/RmlUi/Core/Event.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "WidgetDropDown.h" + +namespace Rml { + +// Constructs a new ElementFormControlSelect. +ElementFormControlSelect::ElementFormControlSelect(const String& tag) : ElementFormControl(tag) +{ + widget = new WidgetDropDown(this); +} + +ElementFormControlSelect::~ElementFormControlSelect() +{ + delete widget; +} + +// Returns a string representation of the current value of the form control. +String ElementFormControlSelect::GetValue() const +{ + RMLUI_ASSERT(widget != nullptr); + return widget->GetValue(); +} + +// Sets the current value of the form control. +void ElementFormControlSelect::SetValue(const String& value) +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + widget->SetValue(value); +} + +// Sets the index of the selection. If the new index lies outside of the bounds, it will be clamped. +void ElementFormControlSelect::SetSelection(int selection) +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + widget->SetSelection(selection); +} + +// Returns the index of the currently selected item. +int ElementFormControlSelect::GetSelection() const +{ + RMLUI_ASSERT(widget != nullptr); + return widget->GetSelection(); +} + +// Returns one of the select control's option elements. +SelectOption* ElementFormControlSelect::GetOption(int index) +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + return widget->GetOption(index); +} + +// Returns the number of options in the select control. +int ElementFormControlSelect::GetNumOptions() +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + return widget->GetNumOptions(); +} + +// Adds a new option to the select control. +int ElementFormControlSelect::Add(const String& rml, const String& value, int before, bool selectable) +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + return widget->AddOption(rml, value, before, false, selectable); +} + +// Removes an option from the select control. +void ElementFormControlSelect::Remove(int index) +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + widget->RemoveOption(index); +} + +// Removes all options from the select control. +void ElementFormControlSelect::RemoveAll() +{ + OnUpdate(); + + RMLUI_ASSERT(widget != nullptr); + widget->ClearOptions(); +} + +// Moves all children to be under control of the widget. +void ElementFormControlSelect::OnUpdate() +{ + ElementFormControl::OnUpdate(); + + // Move any child elements into the widget (except for the three functional elements). + while (Element * raw_child = GetFirstChild()) + { + ElementPtr child = RemoveChild(raw_child); + + bool select = child->GetAttribute("selected"); + bool selectable = !child->GetAttribute("disabled"); + String option_value = child->GetAttribute("value", String()); + + child->RemoveAttribute("selected"); + child->RemoveAttribute("disabled"); + child->RemoveAttribute("value"); + + widget->AddOption(std::move(child), option_value, -1, select, selectable); + } +} + +// Updates the layout of the widget's elements. +void ElementFormControlSelect::OnRender() +{ + ElementFormControl::OnRender(); + + widget->OnRender(); +} + +// Forces an internal layout. +void ElementFormControlSelect::OnLayout() +{ + widget->OnLayout(); +} + +// Returns true to mark this element as replaced. +bool ElementFormControlSelect::GetIntrinsicDimensions(Vector2f& intrinsic_dimensions) +{ + intrinsic_dimensions.x = 128; + intrinsic_dimensions.y = 16; + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlTextArea.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlTextArea.cpp new file mode 100644 index 000000000..88350ab34 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementFormControlTextArea.cpp @@ -0,0 +1,194 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlTextArea.h" +#include "../../../Include/RmlUi/Core/Math.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/ElementText.h" +#include "../../../Include/RmlUi/Core/PropertyIdSet.h" +#include "WidgetTextInputMultiLine.h" + +namespace Rml { + +// Constructs a new ElementFormControlTextArea. +ElementFormControlTextArea::ElementFormControlTextArea(const String& tag) : ElementFormControl(tag) +{ + widget = new WidgetTextInputMultiLine(this); + + SetProperty(PropertyId::OverflowX, Property(Style::Overflow::Auto)); + SetProperty(PropertyId::OverflowY, Property(Style::Overflow::Auto)); + SetProperty(PropertyId::WhiteSpace, Property(Style::WhiteSpace::Prewrap)); +} + +ElementFormControlTextArea::~ElementFormControlTextArea() +{ + delete widget; +} + +// Returns a string representation of the current value of the form control. +String ElementFormControlTextArea::GetValue() const +{ + return GetAttribute< String >("value", ""); +} + +// Sets the current value of the form control. +void ElementFormControlTextArea::SetValue(const String& value) +{ + SetAttribute("value", value); +} + +// Sets the number of characters visible across the text area. Note that this will only be precise when using a +// fixed-width font. +void ElementFormControlTextArea::SetNumColumns(int num_columns) +{ + SetAttribute< int >("cols", Math::Max(1, num_columns)); +} + +// Returns the approximate number of characters visible at once. +int ElementFormControlTextArea::GetNumColumns() const +{ + return GetAttribute< int >("cols", 20); +} + +// Sets the number of visible lines of text in the text area. +void ElementFormControlTextArea::SetNumRows(int num_rows) +{ + SetAttribute< int >("rows", Math::Max(1, num_rows)); +} + +// Returns the number of visible lines of text in the text area. +int ElementFormControlTextArea::GetNumRows() const +{ + return GetAttribute< int >("rows", 2); +} + +// Sets the maximum length (in characters) of this text field. +void ElementFormControlTextArea::SetMaxLength(int max_length) +{ + SetAttribute< int >("maxlength", max_length); +} + +// Returns the maximum length (in characters) of this text field. +int ElementFormControlTextArea::GetMaxLength() const +{ + return GetAttribute< int >("maxlength", -1); +} + +// Enables or disables word-wrapping in the text area. +void ElementFormControlTextArea::SetWordWrap(bool word_wrap) +{ + if (word_wrap != GetWordWrap()) + { + if (word_wrap) + RemoveAttribute("wrap"); + else + SetAttribute("wrap", "nowrap"); + } +} + +// Returns the state of word-wrapping in the text area. +bool ElementFormControlTextArea::GetWordWrap() +{ + String attribute = GetAttribute< String >("wrap", ""); + return attribute != "nowrap"; +} + +// Returns the control's inherent size, based on the length of the input field and the current font size. +bool ElementFormControlTextArea::GetIntrinsicDimensions(Vector2f& dimensions) +{ + dimensions.x = (float) (GetNumColumns() * ElementUtilities::GetStringWidth(this, "m")); + dimensions.y = (float)GetNumRows() * GetLineHeight(); + + return true; +} + +// Updates the control's widget. +void ElementFormControlTextArea::OnUpdate() +{ + widget->OnUpdate(); +} + +// Renders the control's widget. +void ElementFormControlTextArea::OnRender() +{ + widget->OnRender(); +} + +// Formats the element. +void ElementFormControlTextArea::OnResize() +{ + widget->OnResize(); +} + +// Formats the element. +void ElementFormControlTextArea::OnLayout() +{ + widget->OnLayout(); +} + +// Called when attributes on the element are changed. +void ElementFormControlTextArea::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + ElementFormControl::OnAttributeChange(changed_attributes); + + if (changed_attributes.find("wrap") != changed_attributes.end()) + { + if (GetWordWrap()) + SetProperty(PropertyId::WhiteSpace, Property(Style::WhiteSpace::Prewrap)); + else + SetProperty(PropertyId::WhiteSpace, Property(Style::WhiteSpace::Pre)); + } + + if (changed_attributes.find("rows") != changed_attributes.end() || + changed_attributes.find("cols") != changed_attributes.end()) + DirtyLayout(); + + if (changed_attributes.find("maxlength") != changed_attributes.end()) + widget->SetMaxLength(GetMaxLength()); + + if (changed_attributes.find("value") != changed_attributes.end()) + widget->SetValue(GetValue()); +} + +// Called when properties on the control are changed. +void ElementFormControlTextArea::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + ElementFormControl::OnPropertyChange(changed_properties); + + if (changed_properties.Contains(PropertyId::Color) || + changed_properties.Contains(PropertyId::BackgroundColor)) + widget->UpdateSelectionColours(); +} + +// Returns the text content of the element. +void ElementFormControlTextArea::GetInnerRML(String& content) const +{ + content = GetValue(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementImage.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementImage.cpp new file mode 100644 index 000000000..bb5c9cb41 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementImage.cpp @@ -0,0 +1,289 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementImage.h" +#include "../TextureDatabase.h" +#include "../../../Include/RmlUi/Core/URL.h" +#include "../../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../../Include/RmlUi/Core/ElementDocument.h" +#include "../../../Include/RmlUi/Core/StyleSheet.h" + +namespace Rml { + +// Constructs a new ElementImage. +ElementImage::ElementImage(const String& tag) : Element(tag), dimensions(-1, -1), rect_source(RectSource::None), geometry(this) +{ + geometry_dirty = false; + texture_dirty = true; +} + +ElementImage::~ElementImage() +{ +} + +// Sizes the box to the element's inherent size. +bool ElementImage::GetIntrinsicDimensions(Vector2f& _dimensions) +{ + // Check if we need to reload the texture. + if (texture_dirty) + LoadTexture(); + + // Calculate the x dimension. + if (HasAttribute("width")) + dimensions.x = GetAttribute< float >("width", -1); + else if (rect_source != RectSource::None) + dimensions.x = rect.width; + else + dimensions.x = (float)texture.GetDimensions(GetRenderInterface()).x; + + // Calculate the y dimension. + if (HasAttribute("height")) + dimensions.y = GetAttribute< float >("height", -1); + else if (rect_source != RectSource::None) + dimensions.y = rect.height; + else + dimensions.y = (float)texture.GetDimensions(GetRenderInterface()).y; + + // Return the calculated dimensions. If this changes the size of the element, it will result in + // a call to 'onresize' below which will regenerate the geometry. + _dimensions = dimensions; + return true; +} + +// Renders the element. +void ElementImage::OnRender() +{ + // Regenerate the geometry if required (this will be set if 'rect' changes but does not result in a resize). + if (geometry_dirty) + GenerateGeometry(); + + // Render the geometry beginning at this element's content region. + geometry.Render(GetAbsoluteOffset(Box::CONTENT).Round()); +} + +// Called when attributes on the element are changed. +void ElementImage::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + // Call through to the base element's OnAttributeChange(). + Element::OnAttributeChange(changed_attributes); + + float dirty_layout = false; + + // Check for a changed 'src' attribute. If this changes, the old texture handle is released, + // forcing a reload when the layout is regenerated. + if (changed_attributes.find("src") != changed_attributes.end() || + changed_attributes.find("sprite") != changed_attributes.end()) + { + texture_dirty = true; + dirty_layout = true; + } + + // Check for a changed 'width' attribute. If this changes, a layout is forced which will + // recalculate the dimensions. + if (changed_attributes.find("width") != changed_attributes.end() || + changed_attributes.find("height") != changed_attributes.end()) + { + dirty_layout = true; + } + + // Check for a change to the 'rect' attribute. If this changes, the coordinates are + // recomputed and a layout forced. If a sprite is set to source, then that will override any attribute. + if (changed_attributes.find("rect") != changed_attributes.end()) + { + UpdateRect(); + + // Rectangle has changed; this will most likely result in a size change, so we need to force a layout. + dirty_layout = true; + } + + if (dirty_layout) + DirtyLayout(); +} + +void ElementImage::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + Element::OnPropertyChange(changed_properties); + + if (changed_properties.Contains(PropertyId::ImageColor) || + changed_properties.Contains(PropertyId::Opacity)) { + GenerateGeometry(); + } +} + +// Regenerates the element's geometry. +void ElementImage::OnResize() +{ + GenerateGeometry(); +} + +void ElementImage::GenerateGeometry() +{ + // Release the old geometry before specifying the new vertices. + geometry.Release(true); + + Vector< Vertex >& vertices = geometry.GetVertices(); + Vector< int >& indices = geometry.GetIndices(); + + vertices.resize(4); + indices.resize(6); + + // Generate the texture coordinates. + Vector2f texcoords[2]; + if (rect_source != RectSource::None) + { + Vector2f texture_dimensions((float) texture.GetDimensions(GetRenderInterface()).x, (float) texture.GetDimensions(GetRenderInterface()).y); + if (texture_dimensions.x == 0) + texture_dimensions.x = 1; + if (texture_dimensions.y == 0) + texture_dimensions.y = 1; + + texcoords[0].x = rect.x / texture_dimensions.x; + texcoords[0].y = rect.y / texture_dimensions.y; + + texcoords[1].x = (rect.x + rect.width) / texture_dimensions.x; + texcoords[1].y = (rect.y + rect.height) / texture_dimensions.y; + } + else + { + texcoords[0] = Vector2f(0, 0); + texcoords[1] = Vector2f(1, 1); + } + + const ComputedValues& computed = GetComputedValues(); + + float opacity = computed.opacity; + Colourb quad_colour = computed.image_color; + quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha); + + Vector2f quad_size = GetBox().GetSize(Box::CONTENT).Round(); + + GeometryUtilities::GenerateQuad(&vertices[0], &indices[0], Vector2f(0, 0), quad_size, quad_colour, texcoords[0], texcoords[1]); + + geometry_dirty = false; +} + +bool ElementImage::LoadTexture() +{ + texture_dirty = false; + geometry_dirty = true; + + // Check for a sprite first, this takes precedence. + const String sprite_name = GetAttribute< String >("sprite", ""); + if (!sprite_name.empty()) + { + // Load sprite. + bool valid_sprite = false; + + if (ElementDocument* document = GetOwnerDocument()) + { + if (auto& style_sheet = document->GetStyleSheet()) + { + if (const Sprite* sprite = style_sheet->GetSprite(sprite_name)) + { + rect = sprite->rectangle; + rect_source = RectSource::Sprite; + texture = sprite->sprite_sheet->texture; + valid_sprite = true; + } + } + } + + if (!valid_sprite) + { + texture = Texture(); + rect_source = RectSource::None; + UpdateRect(); + Log::Message(Log::LT_WARNING, "Could not find sprite '%s' specified in img element.", sprite_name.c_str()); + return false; + } + } + else + { + // Load image from source URL. + const String source_name = GetAttribute< String >("src", ""); + if (source_name.empty()) + { + texture = Texture(); + rect_source = RectSource::None; + return false; + } + + URL source_url; + + if (ElementDocument* document = GetOwnerDocument()) + source_url.SetURL(document->GetSourceURL()); + + texture.Set(source_name, source_url.GetPath()); + } + + // Set the texture onto our geometry object. + geometry.SetTexture(&texture); + + return true; +} + +void ElementImage::UpdateRect() +{ + if(rect_source != RectSource::Sprite) + { + bool valid_rect = false; + + String rect_string = GetAttribute< String >("rect", ""); + if (!rect_string.empty()) + { + StringList coords_list; + StringUtilities::ExpandString(coords_list, rect_string, ' '); + + if (coords_list.size() != 4) + { + Log::Message(Log::LT_WARNING, "Element '%s' has an invalid 'rect' attribute; rect requires 4 space-separated values, found %d.", GetAddress().c_str(), coords_list.size()); + } + else + { + rect.x = (float)std::atof(coords_list[0].c_str()); + rect.y = (float)std::atof(coords_list[1].c_str()); + rect.width = (float)std::atof(coords_list[2].c_str()); + rect.height = (float)std::atof(coords_list[3].c_str()); + + // We have new, valid coordinates; force the geometry to be regenerated. + valid_rect = true; + geometry_dirty = true; + rect_source = RectSource::Attribute; + } + } + + if (!valid_rect) + { + rect = {}; + rect_source = RectSource::None; + } + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementImage.h b/thirdparty/RmlUi/Source/Core/Elements/ElementImage.h new file mode 100644 index 000000000..a47164b7f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementImage.h @@ -0,0 +1,122 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTIMAGE_H +#define RMLUI_CORE_ELEMENTS_ELEMENTIMAGE_H + +#include "../../../Include/RmlUi/Core/Header.h" +#include "../../../Include/RmlUi/Core/Element.h" +#include "../../../Include/RmlUi/Core/Geometry.h" +#include "../../../Include/RmlUi/Core/Texture.h" +#include "../../../Include/RmlUi/Core/Spritesheet.h" + +namespace Rml { + +/** + The 'img' element can render images and sprites. + + The 'src' attribute is used to specify an image url. If instead the `sprite` attribute is set, + it will load a sprite and ignore the `src` and `rect` attributes. + + The 'rect' attribute takes four space-separated integer values, specifying a rectangle + using 'x y width height' in pixel coordinates inside the image. No clamping to the + dimensions of the source image will occur; rendered results in this case will + depend on the user's texture addressing mode. + + The intrinsic dimensions of the image can now come from three different sources. They are + used in the following order: + + 1) 'width' / 'height' attributes if present + 2) pixel width / height of the sprite + 3) pixel width / height given by the 'rect' attribute + 4) width / height of the image texture + + This has the result of sizing the element to the pixel-size of the rendered image, unless + overridden by the 'width' or 'height' attributes. + + @author Peter Curry + */ + +class RMLUICORE_API ElementImage : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementImage, Element) + + /// Constructs a new ElementImage. This should not be called directly; use the Factory instead. + /// @param[in] tag The tag the element was declared as in RML. + ElementImage(const String& tag); + virtual ~ElementImage(); + + /// Returns the element's inherent size. + /// @param[out] The element's intrinsic dimensions. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; + +protected: + /// Renders the image. + void OnRender() override; + + /// Regenerates the element's geometry. + void OnResize() override; + + /// Checks for changes to the image's source or dimensions. + /// @param[in] changed_attributes A list of attributes changed on the element. + void OnAttributeChange(const ElementAttributes& changed_attributes) override; + + /// Called when properties on the element are changed. + /// @param[in] changed_properties The properties changed on the element. + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + +private: + // Generates the element's geometry. + void GenerateGeometry(); + // Loads the element's texture, as specified by the 'src' attribute. + bool LoadTexture(); + // Loads the rect value from the element's attribute, but only if we're not a sprite. + void UpdateRect(); + + // The texture this element is rendering from. + Texture texture; + // True if we need to refetch the texture's source from the element's attributes. + bool texture_dirty; + // The element's computed intrinsic dimensions. If either of these values are set to -1, then + // that dimension has not been computed yet. + Vector2f dimensions; + + // The rectangle extracted from the sprite or 'rect' attribute. The rect_source will be None if + // these have not been specified or are invalid. + Rectangle rect; + enum class RectSource { None, Attribute, Sprite } rect_source; + + // The geometry used to render this element. + Geometry geometry; + bool geometry_dirty; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementProgressBar.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementProgressBar.cpp new file mode 100644 index 000000000..03ba05cc2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementProgressBar.cpp @@ -0,0 +1,384 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementProgressBar.h" +#include "../../../Include/RmlUi/Core/Math.h" +#include "../../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/ElementDocument.h" +#include "../../../Include/RmlUi/Core/StyleSheet.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/URL.h" +#include + +namespace Rml { + +ElementProgressBar::ElementProgressBar(const String& tag) : Element(tag), direction(DefaultDirection), start_edge(DefaultStartEdge), value(0), fill(nullptr), rect_set(false), geometry(this) +{ + geometry_dirty = false; + texture_dirty = true; + + // Add the fill element as a non-DOM element. + ElementPtr fill_element = Factory::InstanceElement(this, "*", "fill", XMLAttributes()); + RMLUI_ASSERT(fill_element); + fill = AppendChild(std::move(fill_element), false); +} + +ElementProgressBar::~ElementProgressBar() +{ +} + +float ElementProgressBar::GetValue() const +{ + return value; +} + +void ElementProgressBar::SetValue(float in_value) +{ + SetAttribute("value", in_value); +} + +void ElementProgressBar::OnRender() +{ + // Some properties may change geometry without dirtying the layout, eg. opacity. + if (geometry_dirty) + GenerateGeometry(); + + // Render the geometry at the fill element's content region. + geometry.Render(fill->GetAbsoluteOffset().Round()); +} + +void ElementProgressBar::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + Element::OnAttributeChange(changed_attributes); + + if (changed_attributes.find("value") != changed_attributes.end()) + { + value = Math::Clamp( GetAttribute< float >("value", 0.0f), 0.0f, 1.0f); + geometry_dirty = true; + } + + if (changed_attributes.find("direction") != changed_attributes.end()) + { + using DirectionNameList = Array; + static const DirectionNameList names = { "top", "right", "bottom", "left", "clockwise", "counter-clockwise" }; + + direction = DefaultDirection; + + String name = StringUtilities::ToLower( GetAttribute< String >("direction", "") ); + auto it = std::find(names.begin(), names.end(), name); + + size_t index = size_t(it - names.begin()); + if (index < size_t(Direction::Count)) + direction = Direction(index); + + geometry_dirty = true; + } + + if (changed_attributes.find("start-edge") != changed_attributes.end()) + { + using StartEdgeNameList = Array; + static const StartEdgeNameList names = { "top", "right", "bottom", "left" }; + + start_edge = DefaultStartEdge; + + String name = StringUtilities::ToLower(GetAttribute< String >("start-edge", "")); + auto it = std::find(names.begin(), names.end(), name); + + size_t index = size_t(it - names.begin()); + if (index < size_t(StartEdge::Count)) + start_edge = StartEdge(index); + + geometry_dirty = true; + } +} + +void ElementProgressBar::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + Element::OnPropertyChange(changed_properties); + + if (changed_properties.Contains(PropertyId::ImageColor) || + changed_properties.Contains(PropertyId::Opacity)) { + geometry_dirty = true; + } + + if (changed_properties.Contains(PropertyId::FillImage)) { + texture_dirty = true; + } +} + +void ElementProgressBar::OnResize() +{ + const Vector2f element_size = GetBox().GetSize(); + + // Build and set the 'fill' element's box. Here we are mainly interested in all the edge sizes set by the user. + // The content size of the box is here scaled to fit inside the progress bar. Then, during 'CreateGeometry()', + // the 'fill' element's content size is further shrunk according to 'value' along the proper direction. + Box fill_box; + + ElementUtilities::BuildBox(fill_box, element_size, fill); + + const Vector2f margin_top_left( + fill_box.GetEdge(Box::MARGIN, Box::LEFT), + fill_box.GetEdge(Box::MARGIN, Box::TOP) + ); + const Vector2f edge_size = fill_box.GetSize(Box::MARGIN) - fill_box.GetSize(Box::CONTENT); + + fill_offset = GetBox().GetPosition() + margin_top_left; + fill_size = element_size - edge_size; + + fill_box.SetContent(fill_size); + fill->SetBox(fill_box); + + geometry_dirty = true; +} + +void ElementProgressBar::GenerateGeometry() +{ + Vector2f render_size = fill_size; + + { + // Size and offset the fill element depending on the progressbar value. + Vector2f offset = fill_offset; + + switch (direction) { + case Direction::Top: + render_size.y = fill_size.y * value; + offset.y = fill_offset.y + fill_size.y - render_size.y; + break; + case Direction::Right: + render_size.x = fill_size.x * value; + break; + case Direction::Bottom: + render_size.y = fill_size.y * value; + break; + case Direction::Left: + render_size.x = fill_size.x * value; + offset.x = fill_offset.x + fill_size.x - render_size.x; + break; + case Direction::Clockwise: + case Direction::CounterClockwise: + // Circular progress bars cannot use a box to shape the fill element, instead we need to manually create the geometry from the image texture. + // Thus, we leave the size and offset untouched as a canvas for the manual geometry. + break; + + RMLUI_UNUSED_SWITCH_ENUM(Direction::Count); + } + + Box fill_box = fill->GetBox(); + fill_box.SetContent(render_size); + fill->SetBox(fill_box); + fill->SetOffset(offset, this); + } + + if (texture_dirty) + LoadTexture(); + + geometry.Release(true); + geometry_dirty = false; + + // If we don't have a fill texture, then there is no need to generate manual geometry, and we are done here. + // Instead, users can style the fill element eg. by decorators. + if (!texture) + return; + + // Otherwise, the 'fill-image' property is set, let's generate its geometry. + auto& vertices = geometry.GetVertices(); + auto& indices = geometry.GetIndices(); + + Vector2f texcoords[2]; + if (rect_set) + { + Vector2f texture_dimensions((float)texture.GetDimensions(GetRenderInterface()).x, (float)texture.GetDimensions(GetRenderInterface()).y); + if (texture_dimensions.x == 0) + texture_dimensions.x = 1; + if (texture_dimensions.y == 0) + texture_dimensions.y = 1; + + texcoords[0].x = rect.x / texture_dimensions.x; + texcoords[0].y = rect.y / texture_dimensions.y; + + texcoords[1].x = (rect.x + rect.width) / texture_dimensions.x; + texcoords[1].y = (rect.y + rect.height) / texture_dimensions.y; + } + else + { + texcoords[0] = Vector2f(0, 0); + texcoords[1] = Vector2f(1, 1); + } + + Colourb quad_colour; + { + const ComputedValues& computed = GetComputedValues(); + const float opacity = computed.opacity; + quad_colour = computed.image_color; + quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha); + } + + + switch (direction) + { + // For the top, right, bottom, left directions the fill element already describes where we should draw the fill, + // we only need to generate the final texture coordinates here. + case Direction::Top: texcoords[0].y = texcoords[0].y + (1.0f - value) * (texcoords[1].y - texcoords[0].y); break; + case Direction::Right: texcoords[1].x = texcoords[0].x + value * (texcoords[1].x - texcoords[0].x); break; + case Direction::Bottom: texcoords[1].y = texcoords[0].y + value * (texcoords[1].y - texcoords[0].y); break; + case Direction::Left: texcoords[0].x = texcoords[0].x + (1.0f - value) * (texcoords[1].x - texcoords[0].x); break; + + case Direction::Clockwise: + case Direction::CounterClockwise: + { + // The circular directions require custom geometry as a box is insufficient. + // We divide the "circle" into eight parts, here called octants, such that each part can be represented by a triangle. + // 'num_octants' tells us how many of these are completely or partially filled. + const int num_octants = Math::Clamp(Math::RoundUpToInteger(8.f * value), 0, 8); + const int num_vertices = 2 + num_octants; + const int num_triangles = num_octants; + const bool cw = (direction == Direction::Clockwise); + + if (num_octants == 0) + break; + + vertices.resize(num_vertices); + indices.resize(3 * num_triangles); + + RMLUI_ASSERT(int(start_edge) >= int(StartEdge::Top) && int(start_edge) <= int(StartEdge::Left)); + + // The octant our "circle" expands from. + const int start_octant = 2 * int(start_edge); + + // Positions along the unit square (clockwise, index 0 on top) + const float x[8] = { 0, 1, 1, 1, 0, -1, -1, -1 }; + const float y[8] = { -1, -1, 0, 1, 1, 1, 0, -1 }; + + // Set the position of the octant vertices to be rendered. + for (int i = 0; i <= num_octants; i++) + { + int j = (cw ? i : 8 - i); + j = ((j + start_octant) % 8); + vertices[i].position = Vector2f(x[j], y[j]); + } + + // Find the position of the vertex representing the partially filled triangle. + if (value < 1.f) + { + using namespace Math; + const float angle_offset = float(start_octant) / 8.f * 2.f * RMLUI_PI; + const float angle = angle_offset + (cw ? 1.f : -1.f) * value * 2.f * RMLUI_PI; + Vector2f pos(Sin(angle), -Cos(angle)); + // Project it from the circle towards the surrounding unit square. + pos = pos / Max(AbsoluteValue(pos.x), AbsoluteValue(pos.y)); + vertices[num_octants].position = pos; + } + + const int i_center = num_vertices - 1; + vertices[i_center].position = Vector2f(0, 0); + + for (int i = 0; i < num_triangles; i++) + { + indices[i * 3 + 0] = i_center; + indices[i * 3 + 2] = i; + indices[i * 3 + 1] = i + 1; + } + + for (int i = 0; i < num_vertices; i++) + { + // Transform position from [-1, 1] to [0, 1] and then to [0, size] + const Vector2f pos = (Vector2f(1, 1) + vertices[i].position) * 0.5f; + vertices[i].position = pos * render_size; + vertices[i].tex_coord = texcoords[0] + pos * (texcoords[1] - texcoords[0]); + vertices[i].colour = quad_colour; + } + } + break; + RMLUI_UNUSED_SWITCH_ENUM(Direction::Count); + } + + const bool is_circular = (direction == Direction::Clockwise || direction == Direction::CounterClockwise); + + if(!is_circular) + { + vertices.resize(4); + indices.resize(6); + GeometryUtilities::GenerateQuad(&vertices[0], &indices[0], Vector2f(0), render_size, quad_colour, texcoords[0], texcoords[1]); + } +} + +bool ElementProgressBar::LoadTexture() +{ + texture_dirty = false; + geometry_dirty = true; + rect_set = false; + + String name; + + if (auto property = fill->GetLocalProperty(PropertyId::FillImage)) + name = property->Get(); + + ElementDocument* document = GetOwnerDocument(); + + bool texture_set = false; + + if(!name.empty() && document) + { + // Check for a sprite first, this takes precedence. + if (auto& style_sheet = document->GetStyleSheet()) + { + if (const Sprite* sprite = style_sheet->GetSprite(name)) + { + rect = sprite->rectangle; + rect_set = true; + texture = sprite->sprite_sheet->texture; + texture_set = true; + } + } + + // Otherwise, treat it as a path + if (!texture_set) + { + URL source_url; + source_url.SetURL(document->GetSourceURL()); + texture.Set(name, source_url.GetPath()); + texture_set = true; + } + } + + if (!texture_set) + { + texture = {}; + rect = {}; + } + + // Set the texture onto our geometry object. + geometry.SetTexture(&texture); + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementTabSet.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementTabSet.cpp new file mode 100644 index 000000000..2be8bde57 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementTabSet.cpp @@ -0,0 +1,213 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/ElementTabSet.h" +#include "../../../Include/RmlUi/Core/Math.h" +#include "../../../Include/RmlUi/Core/Factory.h" + +namespace Rml { + +ElementTabSet::ElementTabSet(const String& tag) : Element(tag) +{ + active_tab = 0; +} + +ElementTabSet::~ElementTabSet() +{ +} + +// Sets the specifed tab index's tab title RML. +void ElementTabSet::SetTab(int tab_index, const String& rml) +{ + ElementPtr element = Factory::InstanceElement(nullptr, "*", "tab", XMLAttributes()); + Factory::InstanceElementText(element.get(), rml); + SetTab(tab_index, std::move(element)); +} + +// Sets the specifed tab index's tab panel RML. +void ElementTabSet::SetPanel(int tab_index, const String& rml) +{ + ElementPtr element = Factory::InstanceElement(nullptr, "*", "panel", XMLAttributes()); + Factory::InstanceElementText(element.get(), rml); + SetPanel(tab_index, std::move(element)); +} + +// Set the specifed tab index's title element. +void ElementTabSet::SetTab(int tab_index, ElementPtr element) +{ + Element* tabs = GetChildByTag("tabs"); + if (tab_index >= 0 && + tab_index < tabs->GetNumChildren()) + tabs->ReplaceChild(std::move(element), GetChild(tab_index)); + else + tabs->AppendChild(std::move(element)); +} + +// Set the specified tab index's body element. +void ElementTabSet::SetPanel(int tab_index, ElementPtr element) +{ + // append the window + Element* windows = GetChildByTag("panels"); + if (tab_index >= 0 && + tab_index < windows->GetNumChildren()) + windows->ReplaceChild(std::move(element), GetChild(tab_index)); + else + windows->AppendChild(std::move(element)); +} + +// Remove one of the tab set's panels and its corresponding tab. +void ElementTabSet::RemoveTab(int tab_index) +{ + if (tab_index < 0) + return; + + Element* panels = GetChildByTag("panels"); + Element* tabs = GetChildByTag("tabs"); + + if (panels->GetNumChildren() > tab_index && + tabs->GetNumChildren() > tab_index) + { + panels->RemoveChild(panels->GetChild(tab_index)); + tabs->RemoveChild(tabs->GetChild(tab_index)); + } +} + +// Retrieve the number of tabs in the tabset. +int ElementTabSet::GetNumTabs() +{ + return GetChildByTag("tabs")->GetNumChildren(); +} + +void ElementTabSet::SetActiveTab(int tab_index) +{ + // Update display if the tab has changed + if (tab_index != active_tab) + { + Element* tabs = GetChildByTag("tabs"); + Element* old_tab = tabs->GetChild(active_tab); + Element* new_tab = tabs->GetChild(tab_index); + + if (old_tab) + old_tab->SetPseudoClass("selected", false); + if (new_tab) + new_tab->SetPseudoClass("selected", true); + + Element* windows = GetChildByTag("panels"); + Element* old_window = windows->GetChild(active_tab); + Element* new_window = windows->GetChild(tab_index); + + if (old_window) + old_window->SetProperty(PropertyId::Display, Property(Style::Display::None)); + if (new_window) + new_window->SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); + + active_tab = tab_index; + + Dictionary parameters; + parameters["tab_index"] = active_tab; + DispatchEvent(EventId::Tabchange, parameters); + } +} + +int ElementTabSet::GetActiveTab() const +{ + return active_tab; +} + +void ElementTabSet::ProcessDefaultAction(Event& event) +{ + Element::ProcessDefaultAction(event); + + if (event == EventId::Click) + { + // Find the tab that this click occured on + Element* tabs = GetChildByTag("tabs"); + Element* tab = event.GetTargetElement(); + while (tab && tab != this && tab->GetParentNode() != tabs) + tab = tab->GetParentNode(); + + // Abort if we couldn't find the tab the click occured on + if (!tab || tab == this) + return; + + // Determine the new active tab index + int new_active_tab = active_tab; + for (int i = 0; i < tabs->GetNumChildren(); i++) + { + if (tabs->GetChild(i) == tab) + { + new_active_tab = i; + break; + } + } + + SetActiveTab(new_active_tab); + } +} + +void ElementTabSet::OnChildAdd(Element* child) +{ + Element::OnChildAdd(child); + + if (child->GetParentNode() == GetChildByTag("tabs")) + { + // Set up the new button and append it + child->SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); + + if (child->GetParentNode()->GetChild(active_tab) == child) + child->SetPseudoClass("selected", true); + } + + if (child->GetParentNode() == GetChildByTag("panels")) + { + // Hide the new tab window + child->SetProperty(PropertyId::Display, Property(Style::Display::None)); + + // Make the new element visible if its the active tab + if (child->GetParentNode()->GetChild(active_tab) == child) + child->SetProperty(PropertyId::Display, Property(Style::Display::InlineBlock)); + } +} + +Element* ElementTabSet::GetChildByTag(const String& tag) +{ + // Look for the existing child + for (int i = 0; i < GetNumChildren(); i++) + { + if (GetChild(i)->GetTagName() == tag) + return GetChild(i); + } + + // If it doesn't exist, create it + ElementPtr element = Factory::InstanceElement(this, "*", tag, XMLAttributes()); + Element* result = AppendChild(std::move(element)); + return result; +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementTextSelection.cpp b/thirdparty/RmlUi/Source/Core/Elements/ElementTextSelection.cpp new file mode 100644 index 000000000..036e61408 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementTextSelection.cpp @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementTextSelection.h" +#include "WidgetTextInput.h" +#include "../../../Include/RmlUi/Core/PropertyIdSet.h" + +namespace Rml { + +ElementTextSelection::ElementTextSelection(const String& tag) : Element(tag) +{ + widget = nullptr; +} + +ElementTextSelection::~ElementTextSelection() +{ +} + +// Set the widget that this selection element was created for. +void ElementTextSelection::SetWidget(WidgetTextInput* _widget) +{ + widget = _widget; +} + +// Processes 'color' and 'background-color' property changes. +void ElementTextSelection::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + Element::OnPropertyChange(changed_properties); + + if (widget == nullptr) + return; + + // Check for a colour change. + if (changed_properties.Contains(PropertyId::Color) || + changed_properties.Contains(PropertyId::BackgroundColor)) + { + widget->UpdateSelectionColours(); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/ElementTextSelection.h b/thirdparty/RmlUi/Source/Core/Elements/ElementTextSelection.h new file mode 100644 index 000000000..3eb1bd18c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/ElementTextSelection.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_ELEMENTTEXTSELECTION_H +#define RMLUI_CORE_ELEMENTS_ELEMENTTEXTSELECTION_H + +#include "../../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +class WidgetTextInput; + +/** + A stub element used by the WidgetTextInput to query the RCSS-specified text colour and + background colour for selected text. + + @author Peter Curry + */ + +class ElementTextSelection : public Element +{ +public: + RMLUI_RTTI_DefineWithParent(ElementTextSelection, Element) + + ElementTextSelection(const String& tag); + virtual ~ElementTextSelection(); + + /// Set the widget that this selection element was created for. This is the widget that will be + /// notified when this element's properties are altered. + void SetWidget(WidgetTextInput* widget); + +protected: + /// Processes 'color' and 'background-color' property changes. + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + +private: + WidgetTextInput* widget; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputType.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputType.cpp new file mode 100644 index 000000000..ce69e6560 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputType.cpp @@ -0,0 +1,92 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputType.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" + +namespace Rml { + +InputType::InputType(ElementFormControlInput* element) : element(element) +{ +} + +InputType::~InputType() +{ +} + +// Returns a string representation of the current value of the form control. +String InputType::GetValue() const +{ + return element->GetAttribute< String >("value", ""); +} + +// Returns if this value should be submitted with the form. +bool InputType::IsSubmitted() +{ + return true; +} + +// Called every update from the host element. +void InputType::OnUpdate() +{ +} + +// Called every render from the host element. +void InputType::OnRender() +{ +} + +void InputType::OnResize() +{ +} + +// Checks for necessary functional changes in the control as a result of changed attributes. +bool InputType::OnAttributeChange(const ElementAttributes& RMLUI_UNUSED_PARAMETER(changed_attributes)) +{ + RMLUI_UNUSED(changed_attributes); + + return true; +} + +// Called when properties on the control are changed. +void InputType::OnPropertyChange(const PropertyIdSet& RMLUI_UNUSED_PARAMETER(changed_properties)) +{ + RMLUI_UNUSED(changed_properties); +} + +// Called when the element is added into a hierarchy. +void InputType::OnChildAdd() +{ +} + +// Called when the element is removed from a hierarchy. +void InputType::OnChildRemove() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputType.h b/thirdparty/RmlUi/Source/Core/Elements/InputType.h new file mode 100644 index 000000000..3e95d0433 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputType.h @@ -0,0 +1,94 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPE_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPE_H + +#include "../../../Include/RmlUi/Core/Event.h" +#include "../../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class ElementFormControlInput; + +/** + An interface for a input type handler used by ElementFormControlInput. A concrete InputType object handles the + functionality of an input element. + + @author Peter Curry + */ + +class InputType +{ +public: + InputType(ElementFormControlInput* element); + virtual ~InputType(); + + /// Returns a string representation of the current value of the form control. + /// @return The value of the form control. + virtual String GetValue() const; + /// Returns if this value should be submitted with the form. + /// @return True if the form control is to be submitted, false otherwise. + virtual bool IsSubmitted(); + + /// Called every update from the host element. + virtual void OnUpdate(); + + /// Called every render from the host element. + virtual void OnRender(); + + /// Called every time the host element's size changes. + virtual void OnResize(); + + /// Checks for necessary functional changes in the control as a result of changed attributes. + /// @param[in] changed_attributes The list of changed attributes. + /// @return True if no layout is required, false if the layout needs to be dirtied. + virtual bool OnAttributeChange(const ElementAttributes& changed_attributes); + /// Called when properties on the control are changed. + /// @param[in] changed_properties The properties changed on the element. + virtual void OnPropertyChange(const PropertyIdSet& changed_properties); + + /// Called when the element is added into a hierarchy. + virtual void OnChildAdd(); + /// Called when the element is removed from a hierarchy. + virtual void OnChildRemove(); + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + virtual void ProcessDefaultAction(Event& event) = 0; + + /// Sizes the dimensions to the element's inherent size. + /// @return True. + virtual bool GetIntrinsicDimensions(Vector2f& dimensions) = 0; + +protected: + ElementFormControlInput* element; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeButton.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputTypeButton.cpp new file mode 100644 index 000000000..8b736618f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeButton.cpp @@ -0,0 +1,59 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputTypeButton.h" +#include "../../../Include/RmlUi/Core/Elements/ElementForm.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" + +namespace Rml { + +InputTypeButton::InputTypeButton(ElementFormControlInput* element) : InputType(element) +{ +} + +InputTypeButton::~InputTypeButton() +{ +} + +// Buttons are never submitted. +bool InputTypeButton::IsSubmitted() +{ + return false; +} + +void InputTypeButton::ProcessDefaultAction(Event& /*event*/) +{ +} + +// Sizes the dimensions to the element's inherent size. +bool InputTypeButton::GetIntrinsicDimensions(Vector2f& /*dimensions*/) +{ + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeButton.h b/thirdparty/RmlUi/Source/Core/Elements/InputTypeButton.h new file mode 100644 index 000000000..1478bac83 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeButton.h @@ -0,0 +1,65 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPEBUTTON_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPEBUTTON_H + +#include "../../../Include/RmlUi/Core/EventListener.h" +#include "../../../Include/RmlUi/Core/ElementDocument.h" +#include "InputType.h" + +namespace Rml { + +/** + A button input type handler. The only functionality a button provides over a normal element is the ability + to be disabled. This prevents 'click' events on this element and the ability to receive focus. + + @author Peter Curry + */ + +class InputTypeButton : public InputType +{ +public: + InputTypeButton(ElementFormControlInput* element); + virtual ~InputTypeButton(); + + /// Returns if this value should be submitted with the form. + /// @return True if the form control is to be submitted, false otherwise. + bool IsSubmitted() override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return False. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeCheckbox.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputTypeCheckbox.cpp new file mode 100644 index 000000000..1060c3dde --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeCheckbox.cpp @@ -0,0 +1,87 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputTypeCheckbox.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" + +namespace Rml { + +InputTypeCheckbox::InputTypeCheckbox(ElementFormControlInput* element) : InputType(element) +{ +} + +InputTypeCheckbox::~InputTypeCheckbox() +{ +} + +// Returns if this value should be submitted with the form. +bool InputTypeCheckbox::IsSubmitted() +{ + return element->HasAttribute("checked"); +} + +// Checks for necessary functional changes in the control as a result of changed attributes. +bool InputTypeCheckbox::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + // Check if maxlength has been defined. + if (changed_attributes.find("checked") != changed_attributes.end()) + { + bool checked = element->HasAttribute("checked"); + element->SetPseudoClass("checked", checked); + + Dictionary parameters; + parameters["value"] = String(checked ? GetValue() : ""); + element->DispatchEvent(EventId::Change, parameters); + } + + return true; +} + +// Checks for necessary functional changes in the control as a result of the event. +void InputTypeCheckbox::ProcessDefaultAction(Event& event) +{ + if (event == EventId::Click && + !element->IsDisabled()) + { + if (element->HasAttribute("checked")) + element->RemoveAttribute("checked"); + else + element->SetAttribute("checked", ""); + } +} + +// Sizes the dimensions to the element's inherent size. +bool InputTypeCheckbox::GetIntrinsicDimensions(Vector2f& dimensions) +{ + dimensions.x = 16; + dimensions.y = 16; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeCheckbox.h b/thirdparty/RmlUi/Source/Core/Elements/InputTypeCheckbox.h new file mode 100644 index 000000000..abd17e016 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeCheckbox.h @@ -0,0 +1,67 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPECHECKBOX_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPECHECKBOX_H + +#include "InputType.h" + +namespace Rml { + +/** + A checkbox input type handler. + + @author Peter Curry + */ + +class InputTypeCheckbox : public InputType +{ +public: + InputTypeCheckbox(ElementFormControlInput* element); + virtual ~InputTypeCheckbox(); + + /// Returns if this value should be submitted with the form. + /// @return True if the form control is to be submitted, false otherwise. + bool IsSubmitted() override; + + /// Checks for necessary functional changes in the control as a result of changed attributes. + /// @param[in] changed_attributes The list of changed attributes. + /// @return True if no layout is required, false if the layout needs to be dirtied. + bool OnAttributeChange(const ElementAttributes& changed_attributes) override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeRadio.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRadio.cpp new file mode 100644 index 000000000..fb801d583 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRadio.cpp @@ -0,0 +1,125 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputTypeRadio.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/Elements/ElementForm.h" + +namespace Rml { + +InputTypeRadio::InputTypeRadio(ElementFormControlInput* element) : InputType(element) +{ + if (element->HasAttribute("checked")) + PopRadioSet(); +} + +InputTypeRadio::~InputTypeRadio() +{ +} + +// Returns if this value should be submitted with the form. +bool InputTypeRadio::IsSubmitted() +{ + return element->HasAttribute("checked"); +} + +// Checks for necessary functional changes in the control as a result of changed attributes. +bool InputTypeRadio::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + // Check if maxlength has been defined. + if (changed_attributes.find("checked") != changed_attributes.end()) + { + bool checked = element->HasAttribute("checked"); + element->SetPseudoClass("checked", checked); + + if (checked) + PopRadioSet(); + + Dictionary parameters; + parameters["value"] = String(checked ? GetValue() : ""); + element->DispatchEvent(EventId::Change, parameters); + } + + return true; +} + +// Pops the element's radio set if we are checked. +void InputTypeRadio::OnChildAdd() +{ + if (element->HasAttribute("checked")) + PopRadioSet(); +} + +// Checks for necessary functional changes in the control as a result of the event. +void InputTypeRadio::ProcessDefaultAction(Event& event) +{ + if (event == EventId::Click && + !element->IsDisabled()) + element->SetAttribute("checked", ""); +} + +// Sizes the dimensions to the element's inherent size. +bool InputTypeRadio::GetIntrinsicDimensions(Vector2f& dimensions) +{ + dimensions.x = 16; + dimensions.y = 16; + + return true; +} + +// Pops all other radio buttons in our form that share our name. +void InputTypeRadio::PopRadioSet() +{ + // Uncheck all other radio buttons with our name in the form. + ElementForm* form = nullptr; + Element* parent = element->GetParentNode(); + while (parent != nullptr && + (form = rmlui_dynamic_cast< ElementForm* >(parent)) == nullptr) + parent = parent->GetParentNode(); + + if (form != nullptr) + { + ElementList form_controls; + ElementUtilities::GetElementsByTagName(form_controls, form, "input"); + + for (size_t i = 0; i < form_controls.size(); ++i) + { + ElementFormControlInput* radio_control = rmlui_dynamic_cast< ElementFormControlInput* >(form_controls[i]); + if (radio_control != nullptr && + element != radio_control && + radio_control->GetAttribute< String >("type", "text") == "radio" && + radio_control->GetName() == element->GetName()) + { + radio_control->RemoveAttribute("checked"); + } + } + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeRadio.h b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRadio.h new file mode 100644 index 000000000..b97a4497c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRadio.h @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPERADIO_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPERADIO_H + +#include "InputType.h" + +namespace Rml { + +/** + A radio button input type handler. + + @author Peter Curry + */ + +class InputTypeRadio : public InputType +{ +public: + InputTypeRadio(ElementFormControlInput* element); + virtual ~InputTypeRadio(); + + /// Returns if this value should be submitted with the form. + /// @return True if the form control is to be submitted, false otherwise. + bool IsSubmitted() override; + + /// Checks for necessary functional changes in the control as a result of changed attributes. + /// @param[in] changed_attributes The list of changed attributes. + /// @return True if no layout is required, false if the layout needs to be dirtied. + bool OnAttributeChange(const ElementAttributes& changed_attributes) override; + + /// Pops the element's radio set if we are checked. + void OnChildAdd() override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; + +private: + /// Pops all other radio buttons in our form that share our name. + void PopRadioSet(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeRange.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRange.cpp new file mode 100644 index 000000000..a7651ca72 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRange.cpp @@ -0,0 +1,107 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputTypeRange.h" +#include "WidgetSlider.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" + +namespace Rml { + +InputTypeRange::InputTypeRange(ElementFormControlInput* element) : InputType(element) +{ + widget = new WidgetSlider(element); + widget->Initialise(); +} + +InputTypeRange::~InputTypeRange() +{ + delete widget; +} + +// Returns a string representation of the current value of the form control. +String InputTypeRange::GetValue() const +{ + return CreateString(32, "%f", widget->GetValue()); +} + +// Called every update from the host element. +void InputTypeRange::OnUpdate() +{ + widget->Update(); +} + +void InputTypeRange::OnResize() +{ + widget->FormatElements(); +} + +// Checks for necessary functional changes in the control as a result of changed attributes. +bool InputTypeRange::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + bool dirty_layout = false; + + auto it_orientation = changed_attributes.find("orientation"); + if (it_orientation != changed_attributes.end()) + { + bool is_vertical = (it_orientation->second.Get() == "vertical"); + widget->SetOrientation(is_vertical ? WidgetSlider::VERTICAL : WidgetSlider::HORIZONTAL); + dirty_layout = true; + } + + auto it_step = changed_attributes.find("step"); + if (it_step != changed_attributes.end()) + widget->SetStep(it_step->second.Get(1.0f)); + + auto it_min = changed_attributes.find("min"); + if (it_min != changed_attributes.end()) + widget->SetMinValue(it_min->second.Get(0.0f)); + + auto it_max = changed_attributes.find("max"); + if (it_max != changed_attributes.end()) + widget->SetMaxValue(it_max->second.Get(100.f)); + + auto it_value = changed_attributes.find("value"); + if (it_value != changed_attributes.end()) + widget->SetValue(it_value->second.Get(0.0f)); + + return !dirty_layout; +} + +// Checks for necessary functional changes in the control as a result of the event. +void InputTypeRange::ProcessDefaultAction(Event& /*event*/) +{ +} + +// Sizes the dimensions to the element's inherent size. +bool InputTypeRange::GetIntrinsicDimensions(Vector2f& dimensions) +{ + widget->GetDimensions(dimensions); + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeRange.h b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRange.h new file mode 100644 index 000000000..1722940c7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeRange.h @@ -0,0 +1,78 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPERANGE_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPERANGE_H + +#include "InputType.h" + +namespace Rml { + +class WidgetSlider; + +/** + A range input type handler. + + @author Peter Curry + */ + +class InputTypeRange : public InputType +{ +public: + InputTypeRange(ElementFormControlInput* element); + virtual ~InputTypeRange(); + + /// Returns a string representation of the current value of the form control. + /// @return The value of the form control. + String GetValue() const override; + + /// Called every update from the host element. + void OnUpdate() override; + + /// Called every time the host element's size changes. + void OnResize() override; + + /// Checks for necessary functional changes in the control as a result of changed attributes. + /// @param[in] changed_attributes The list of changed attributes. + /// @return True if no layout is required, false if the layout needs to be dirtied. + bool OnAttributeChange(const ElementAttributes& changed_attributes) override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; + +private: + WidgetSlider* widget; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeSubmit.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputTypeSubmit.cpp new file mode 100644 index 000000000..c4fdaca11 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeSubmit.cpp @@ -0,0 +1,80 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputTypeSubmit.h" +#include "../../../Include/RmlUi/Core/Elements/ElementForm.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" + +namespace Rml { + +InputTypeSubmit::InputTypeSubmit(ElementFormControlInput* element) : InputType(element) +{ +} + +InputTypeSubmit::~InputTypeSubmit() +{ +} + +// Submit buttons are never submitted; they submit themselves if appropriate. +bool InputTypeSubmit::IsSubmitted() +{ + return false; +} + +// Checks for necessary functional changes in the control as a result of the event. +void InputTypeSubmit::ProcessDefaultAction(Event& event) +{ + if (event == EventId::Click && + !element->IsDisabled()) + { + Element* parent = element->GetParentNode(); + while (parent) + { + ElementForm* form = rmlui_dynamic_cast< ElementForm* >(parent); + if (form != nullptr) + { + form->Submit(element->GetAttribute< String >("name", ""), element->GetAttribute< String >("value", "")); + return; + } + else + { + parent = parent->GetParentNode(); + } + } + } +} + +// Sizes the dimensions to the element's inherent size. +bool InputTypeSubmit::GetIntrinsicDimensions(Vector2f& RMLUI_UNUSED_PARAMETER(dimensions)) +{ + RMLUI_UNUSED(dimensions); + + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeSubmit.h b/thirdparty/RmlUi/Source/Core/Elements/InputTypeSubmit.h new file mode 100644 index 000000000..38ca46833 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeSubmit.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPESUBMIT_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPESUBMIT_H + +#include "InputType.h" + +namespace Rml { + +/** + A submit input type handler. + + @author Peter Curry + */ + +class InputTypeSubmit : public InputType +{ +public: + InputTypeSubmit(ElementFormControlInput* element); + virtual ~InputTypeSubmit(); + + /// Returns if this value should be submitted with the form. + /// @return True if the form control is to be submitted, false otherwise. + bool IsSubmitted() override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return False. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeText.cpp b/thirdparty/RmlUi/Source/Core/Elements/InputTypeText.cpp new file mode 100644 index 000000000..d7f32e36b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeText.cpp @@ -0,0 +1,122 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "InputTypeText.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "WidgetTextInputSingleLine.h" +#include "WidgetTextInputSingleLinePassword.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" +#include "../../../Include/RmlUi/Core/PropertyIdSet.h" + +namespace Rml { + +InputTypeText::InputTypeText(ElementFormControlInput* element, Visibility visibility) : InputType(element) +{ + if (visibility == VISIBLE) + widget = new WidgetTextInputSingleLine(element); + else + widget = new WidgetTextInputSingleLinePassword(element); + + widget->SetMaxLength(element->GetAttribute< int >("maxlength", -1)); + widget->SetValue(element->GetAttribute< String >("value", "")); + + size = element->GetAttribute< int >("size", 20); +} + +InputTypeText::~InputTypeText() +{ + delete widget; +} + +// Called every update from the host element. +void InputTypeText::OnUpdate() +{ + widget->OnUpdate(); +} + +// Called every render from the host element. +void InputTypeText::OnRender() +{ + widget->OnRender(); +} + +void InputTypeText::OnResize() +{ + widget->OnResize(); +} + +// Checks for necessary functional changes in the control as a result of changed attributes. +bool InputTypeText::OnAttributeChange(const ElementAttributes& changed_attributes) +{ + bool dirty_layout = false; + + // Check if maxlength has been defined. + auto it = changed_attributes.find("maxlength"); + if (it != changed_attributes.end()) + widget->SetMaxLength(it->second.Get(-1)); + + // Check if size has been defined. + it = changed_attributes.find("size"); + if (it != changed_attributes.end()) + { + size = it->second.Get(20); + dirty_layout = true; + } + + // Check if the value has been changed. + it = changed_attributes.find("value"); + if (it != changed_attributes.end()) + widget->SetValue(it->second.Get()); + + return !dirty_layout; +} + +// Called when properties on the control are changed. +void InputTypeText::OnPropertyChange(const PropertyIdSet& changed_properties) +{ + if (changed_properties.Contains(PropertyId::Color) || + changed_properties.Contains(PropertyId::BackgroundColor)) + widget->UpdateSelectionColours(); +} + +// Checks for necessary functional changes in the control as a result of the event. +void InputTypeText::ProcessDefaultAction(Event& RMLUI_UNUSED_PARAMETER(event)) +{ + RMLUI_UNUSED(event); +} + +// Sizes the dimensions to the element's inherent size. +bool InputTypeText::GetIntrinsicDimensions(Vector2f& dimensions) +{ + dimensions.x = (float) (size * ElementUtilities::GetStringWidth(element, "m")); + dimensions.y = element->GetLineHeight() + 2.0f; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/InputTypeText.h b/thirdparty/RmlUi/Source/Core/Elements/InputTypeText.h new file mode 100644 index 000000000..95513a528 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/InputTypeText.h @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_INPUTTYPETEXT_H +#define RMLUI_CORE_ELEMENTS_INPUTTYPETEXT_H + +#include "InputType.h" + +namespace Rml { + +class WidgetTextInput; + +/** + A single-line input type handler. + + @author Peter Curry + */ + +class InputTypeText : public InputType +{ +public: + enum Visibility + { + VISIBLE, + OBSCURED + }; + + InputTypeText(ElementFormControlInput* element, Visibility visibility = VISIBLE); + virtual ~InputTypeText(); + + /// Called every update from the host element. + void OnUpdate() override; + + /// Called every render from the host element. + void OnRender() override; + + /// Called when the parent element's size changes. + void OnResize() override; + + /// Checks for necessary functional changes in the control as a result of changed attributes. + /// @param[in] changed_attributes The list of changed attributes. + /// @return True if no layout is required, false if the layout needs to be dirtied. + bool OnAttributeChange(const ElementAttributes& changed_attributes) override; + /// Called when properties on the control are changed. + /// @param[in] changed_properties The properties changed on the element. + void OnPropertyChange(const PropertyIdSet& changed_properties) override; + + /// Checks for necessary functional changes in the control as a result of the event. + /// @param[in] event The event to process. + void ProcessDefaultAction(Event& event) override; + + /// Sizes the dimensions to the element's inherent size. + /// @return True. + bool GetIntrinsicDimensions(Vector2f& dimensions) override; + +private: + int size; + + WidgetTextInput* widget; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/SelectOption.cpp b/thirdparty/RmlUi/Source/Core/Elements/SelectOption.cpp new file mode 100644 index 000000000..9c8978961 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/SelectOption.cpp @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Elements/SelectOption.h" + +namespace Rml { + +SelectOption::SelectOption(Element* _element, const String& value, bool selectable) : value(value) , selectable(selectable) +{ + element = _element; +} + +SelectOption::~SelectOption() +{ +} + +// Returns the element that represents the option visually. +Element* SelectOption::GetElement() +{ + return element; +} + +// Returns the value of the option. +const String& SelectOption::GetValue() const +{ + return value; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetDropDown.cpp b/thirdparty/RmlUi/Source/Core/Elements/WidgetDropDown.cpp new file mode 100644 index 000000000..11b58060e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetDropDown.cpp @@ -0,0 +1,536 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "WidgetDropDown.h" +#include "../../../Include/RmlUi/Core/Context.h" +#include "../../../Include/RmlUi/Core/ElementDocument.h" +#include "../../../Include/RmlUi/Core/Math.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/Event.h" +#include "../../../Include/RmlUi/Core/Input.h" +#include "../../../Include/RmlUi/Core/Property.h" +#include "../../../Include/RmlUi/Core/Profiling.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h" + +namespace Rml { + +WidgetDropDown::WidgetDropDown(ElementFormControl* element) +{ + parent_element = element; + + box_layout_dirty = false; + value_layout_dirty = false; + box_visible = false; + + selected_option = -1; + + // Create the button and selection elements. + button_element = parent_element->AppendChild(Factory::InstanceElement(parent_element, "*", "selectarrow", XMLAttributes()), false); + value_element = parent_element->AppendChild(Factory::InstanceElement(parent_element, "*", "selectvalue", XMLAttributes()), false); + selection_element = parent_element->AppendChild(Factory::InstanceElement(parent_element, "*", "selectbox", XMLAttributes()), false); + + value_element->SetProperty(PropertyId::OverflowX, Property(Style::Overflow::Hidden)); + value_element->SetProperty(PropertyId::OverflowY, Property(Style::Overflow::Hidden)); + + selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + selection_element->SetProperty(PropertyId::ZIndex, Property(1.0f, Property::NUMBER)); + selection_element->SetProperty(PropertyId::Clip, Property(Style::Clip::Type::None)); + selection_element->SetProperty(PropertyId::OverflowY, Property(Style::Overflow::Auto)); + + parent_element->AddEventListener(EventId::Click, this, true); + parent_element->AddEventListener(EventId::Blur, this); + parent_element->AddEventListener(EventId::Focus, this); + parent_element->AddEventListener(EventId::Keydown, this, true); + + selection_element->AddEventListener(EventId::Mousescroll, this); +} + +WidgetDropDown::~WidgetDropDown() +{ + // We shouldn't clear the options ourselves, as removing the element will automatically clear children. + // However, we do need to remove events of children. + for(auto& option : options) + option.GetElement()->RemoveEventListener(EventId::Click, this); + + parent_element->RemoveEventListener(EventId::Click, this, true); + parent_element->RemoveEventListener(EventId::Blur, this); + parent_element->RemoveEventListener(EventId::Focus, this); + parent_element->RemoveEventListener(EventId::Keydown, this, true); + + selection_element->RemoveEventListener(EventId::Mousescroll, this); + + DetachScrollEvent(); +} + +// Updates the selection box layout if necessary. +void WidgetDropDown::OnRender() +{ + if (box_visible && box_layout_dirty) + { + // Layout the selection box. + // The following procedure should ensure that the selection box is never (partly) outside of the context's window. + // This is achieved by positioning the box either above or below the 'select' element, and possibly shrinking + // the element's height. + // We try to respect user values of 'height', 'min-height', and 'max-height'. However, when we need to shrink the box + // we will override the 'height' property. + + // Previously set 'height' property from this procedure must be removed for the calculations below to work as intended. + if(selection_element->GetLocalStyleProperties().count(PropertyId::Height) == 1) + { + selection_element->RemoveProperty(PropertyId::Height); + selection_element->GetOwnerDocument()->UpdateDocument(); + } + + Box box; + ElementUtilities::BuildBox(box, parent_element->GetBox().GetSize(), selection_element); + + // The user can use 'margin-left/top/bottom' to offset the box away from the 'select' element, respectively + // horizontally, vertically when box below, and vertically when box above. + const float offset_x = box.GetEdge(Box::MARGIN, Box::LEFT); + const float offset_y_below = parent_element->GetBox().GetSize(Box::BORDER).y + box.GetEdge(Box::MARGIN, Box::TOP); + const float offset_y_above = -box.GetEdge(Box::MARGIN, Box::BOTTOM); + + float window_height = 100'000.f; + if (Context* context = parent_element->GetContext()) + window_height = float(context->GetDimensions().y); + + const float absolute_y = parent_element->GetAbsoluteOffset(Box::BORDER).y; + + const float height_below = window_height - absolute_y - offset_y_below; + const float height_above = absolute_y + offset_y_above; + + // Format the selection box and retrieve the 'native' height occupied by all the options, while respecting + // the 'min/max-height' properties. + ElementUtilities::FormatElement(selection_element, parent_element->GetBox().GetSize(Box::BORDER)); + const float content_height = selection_element->GetOffsetHeight(); + + if (content_height < height_below) + { + // Position box below + selection_element->SetOffset(Vector2f(offset_x, offset_y_below), parent_element); + } + else if (content_height < height_above) + { + // Position box above + selection_element->SetOffset(Vector2f(offset_x, -content_height + offset_y_above), parent_element); + } + else + { + // Shrink box and position either below or above + const float padding_border_size = + box.GetEdge(Box::BORDER, Box::TOP) + box.GetEdge(Box::BORDER, Box::BOTTOM) + + box.GetEdge(Box::PADDING, Box::TOP) + box.GetEdge(Box::PADDING, Box::BOTTOM); + + float height = 0.f; + float offset_y = 0.f; + + if (height_below > height_above) + { + // Position below + height = height_below - padding_border_size; + offset_y = offset_y_below; + } + else + { + // Position above + height = height_above - padding_border_size; + offset_y = offset_y_above - height_above; + } + + // Set the height and re-format the selection box. + selection_element->SetProperty(PropertyId::Height, Property(height, Property::PX)); + selection_element->GetOwnerDocument()->UpdateDocument(); + ElementUtilities::FormatElement(selection_element, parent_element->GetBox().GetSize(Box::BORDER)); + + selection_element->SetOffset(Vector2f(offset_x, offset_y), parent_element); + } + + box_layout_dirty = false; + } + + if (value_layout_dirty) + { + ElementUtilities::FormatElement(value_element, parent_element->GetBox().GetSize(Box::BORDER)); + value_element->SetOffset(parent_element->GetBox().GetPosition(Box::CONTENT), parent_element); + + value_layout_dirty = false; + } +} + +void WidgetDropDown::OnLayout() +{ + RMLUI_ZoneScopedNC("DropDownLayout", 0x7FFF00); + + if(parent_element->IsDisabled()) + { + // Propagate disabled state to selectvalue and selectarrow + value_element->SetPseudoClass("disabled", true); + button_element->SetPseudoClass("disabled", true); + } + + // Layout the button and selection boxes. + Box parent_box = parent_element->GetBox(); + + ElementUtilities::PositionElement(button_element, Vector2f(0, 0), ElementUtilities::TOP_RIGHT); + ElementUtilities::PositionElement(selection_element, Vector2f(0, 0), ElementUtilities::TOP_LEFT); + + // Calculate the value element position and size. + Vector2f size; + size.x = parent_element->GetBox().GetSize(Box::CONTENT).x - button_element->GetBox().GetSize(Box::MARGIN).x; + size.y = parent_element->GetBox().GetSize(Box::CONTENT).y; + + value_element->SetOffset(parent_element->GetBox().GetPosition(Box::CONTENT), parent_element); + value_element->SetBox(Box(size)); + + box_layout_dirty = true; + value_layout_dirty = true; +} + +// Sets the value of the widget. +void WidgetDropDown::SetValue(const String& _value) +{ + for (size_t i = 0; i < options.size(); ++i) + { + if (options[i].GetValue() == _value) + { + SetSelection((int) i); + return; + } + } + + if (selected_option >= 0 && selected_option < (int)options.size()) + options[selected_option].GetElement()->SetPseudoClass("checked", false); + + value = _value; + value_element->SetInnerRML(value); + value_layout_dirty = true; + + selected_option = -1; +} + +// Returns the current value of the widget. +const String& WidgetDropDown::GetValue() const +{ + return value; +} + +// Sets the index of the selection. If the new index lies outside of the bounds, it will be clamped. +void WidgetDropDown::SetSelection(int selection, bool force) +{ + String new_value; + + if (selection < 0 || + selection >= (int) options.size()) + { + selection = -1; + } + else + { + new_value = options[selection].GetValue(); + } + + if (force || + selection != selected_option || + value != new_value) + { + if (selected_option >= 0 && selected_option < (int)options.size()) + options[selected_option].GetElement()->SetPseudoClass("checked", false); + + selected_option = selection; + value = new_value; + + String value_rml; + if (selected_option >= 0) + { + auto* el = options[selected_option].GetElement(); + el->GetInnerRML(value_rml); + el->SetPseudoClass("checked", true); + } + + + value_element->SetInnerRML(value_rml); + value_layout_dirty = true; + + Dictionary parameters; + parameters["value"] = value; + parent_element->DispatchEvent(EventId::Change, parameters); + } +} + +// Returns the index of the currently selected item. +int WidgetDropDown::GetSelection() const +{ + return selected_option; +} + +// Adds a new option to the select control. +int WidgetDropDown::AddOption(const String& rml, const String& new_value, int before, bool select, bool selectable) +{ + ElementPtr element = Factory::InstanceElement(selection_element, "*", "option", XMLAttributes()); + element->SetInnerRML(rml); + + int result = AddOption(std::move(element), new_value, before, select, selectable); + + return result; +} + +int WidgetDropDown::AddOption(ElementPtr element, const String& new_value, int before, bool select, bool selectable) +{ + static const String str_option = "option"; + + if (element->GetTagName() != str_option) + { + Log::Message(Log::LT_WARNING, "A child of '%s' must be of type 'option' but '%s' was given. See element '%s'.", parent_element->GetTagName().c_str(), element->GetTagName().c_str(), parent_element->GetAddress().c_str()); + return -1; + } + + // Force to block display. Register a click handler so we can be notified of selection. + element->SetProperty(PropertyId::Display, Property(Style::Display::Block)); + element->SetProperty(PropertyId::Clip, Property(Style::Clip::Type::Auto)); + element->AddEventListener(EventId::Click, this); + + int option_index; + if (before < 0 || before >= (int)options.size()) + { + Element* ptr = selection_element->AppendChild(std::move(element)); + options.push_back(SelectOption(ptr, new_value, selectable)); + option_index = (int)options.size() - 1; + } + else + { + Element* ptr = selection_element->InsertBefore(std::move(element), selection_element->GetChild(before)); + options.insert(options.begin() + before, SelectOption(ptr, new_value, selectable)); + option_index = before; + } + + // Select the option if appropriate. + if (select) + SetSelection(option_index); + + box_layout_dirty = true; + return option_index; +} + +// Removes an option from the select control. +void WidgetDropDown::RemoveOption(int index) +{ + if (index < 0 || + index >= (int) options.size()) + return; + + // Remove the listener and delete the option element. + options[index].GetElement()->RemoveEventListener(EventId::Click, this); + selection_element->RemoveChild(options[index].GetElement()); + options.erase(options.begin() + index); + + box_layout_dirty = true; +} + +// Removes all options from the list. +void WidgetDropDown::ClearOptions() +{ + while (!options.empty()) + RemoveOption((int) options.size() - 1); +} + +// Returns on of the widget's options. +SelectOption* WidgetDropDown::GetOption(int index) +{ + if (index < 0 || + index >= GetNumOptions()) + return nullptr; + + return &options[index]; +} + +// Returns the number of options in the widget. +int WidgetDropDown::GetNumOptions() const +{ + return (int) options.size(); +} + +void WidgetDropDown::AttachScrollEvent() +{ + if (ElementDocument* document = parent_element->GetOwnerDocument()) + document->AddEventListener(EventId::Scroll, this, true); +} + +void WidgetDropDown::DetachScrollEvent() +{ + if (ElementDocument* document = parent_element->GetOwnerDocument()) + document->RemoveEventListener(EventId::Scroll, this, true); +} + +void WidgetDropDown::ProcessEvent(Event& event) +{ + if (parent_element->IsDisabled()) + return; + + // Process the button onclick + switch (event.GetId()) + { + case EventId::Click: + { + + if (event.GetCurrentElement()->GetParentNode() == selection_element) + { + // Find the element in the options and fire the selection event + for (size_t i = 0; i < options.size(); i++) + { + if (options[i].GetElement() == event.GetCurrentElement()) + { + if (options[i].IsSelectable()) + { + SetSelection((int)i); + event.StopPropagation(); + + ShowSelectBox(false); + parent_element->Focus(); + } + } + } + } + else + { + // We have to check that this event isn't targeted to an element + // inside the selection box as we'll get all events coming from our + // root level select element as well as the ones coming from options (which + // get caught in the above if) + Element* element = event.GetTargetElement(); + while (element && element != parent_element) + { + if (element == selection_element) + return; + element = element->GetParentNode(); + } + + if (selection_element->GetComputedValues().visibility == Style::Visibility::Hidden) + ShowSelectBox(true); + else + ShowSelectBox(false); + } + } + break; + case EventId::Focus: + { + if (event.GetTargetElement() == parent_element) + { + value_element->SetPseudoClass("focus", true); + button_element->SetPseudoClass("focus", true); + } + } + break; + case EventId::Blur: + { + if (event.GetTargetElement() == parent_element) + { + ShowSelectBox(false); + value_element->SetPseudoClass("focus", false); + button_element->SetPseudoClass("focus", false); + } + } + break; + case EventId::Keydown: + { + Input::KeyIdentifier key_identifier = (Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0); + + switch (key_identifier) + { + case Input::KI_UP: + SetSelection((selected_option - 1 + (int)options.size()) % (int)options.size()); + break; + case Input::KI_DOWN: + SetSelection((selected_option + 1) % (int)options.size()); + break; + default: + break; + } + } + break; + case EventId::Mousescroll: + { + if (event.GetCurrentElement() == selection_element) + { + // Prevent scrolling in the parent window when mouse is inside the selection box. + event.StopPropagation(); + // Stopping propagation also stops all default scrolling actions. However, we still want to be able + // to scroll in the selection box, so call the default action manually. + selection_element->ProcessDefaultAction(event); + } + } + break; + case EventId::Scroll: + { + if (box_visible) + { + // Close the select box if we scroll outside the select box. + bool scrolls_selection_box = false; + + for (Element* element = event.GetTargetElement(); element; element = element->GetParentNode()) + { + if (element == selection_element) + { + scrolls_selection_box = true; + break; + } + } + + if (!scrolls_selection_box) + ShowSelectBox(false); + } + } + break; + default: + break; + } +} + +// Shows or hides the selection box. +void WidgetDropDown::ShowSelectBox(bool show) +{ + if (show) + { + selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + value_element->SetPseudoClass("checked", true); + button_element->SetPseudoClass("checked", true); + box_layout_dirty = true; + AttachScrollEvent(); + } + else + { + selection_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + selection_element->RemoveProperty(PropertyId::Height); + value_element->SetPseudoClass("checked", false); + button_element->SetPseudoClass("checked", false); + DetachScrollEvent(); + } + box_visible = show; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetDropDown.h b/thirdparty/RmlUi/Source/Core/Elements/WidgetDropDown.h new file mode 100644 index 000000000..5762c667c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetDropDown.h @@ -0,0 +1,133 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_WIDGETDROPDOWN_H +#define RMLUI_CORE_ELEMENTS_WIDGETDROPDOWN_H + +#include "../../../Include/RmlUi/Core/EventListener.h" +#include "../../../Include/RmlUi/Core/Elements/SelectOption.h" + +namespace Rml { + +class ElementFormControl; + +/** + Widget for drop-down functionality. + @author Lloyd Weehuizen + */ + +class WidgetDropDown : public EventListener +{ +public: + WidgetDropDown(ElementFormControl* element); + virtual ~WidgetDropDown(); + + /// Updates the selection box layout if necessary. + void OnRender(); + /// Positions the drop-down's internal elements. + void OnLayout(); + + /// Sets the value of the widget. + /// @param[in] value The new value to set. + void SetValue(const String& value); + /// Returns the current value of the widget. + /// @return The current value of the widget. + const String& GetValue() const; + + /// Sets the index of the selection. If the new index lies outside of the bounds, the selection index will be set to -1. + /// @param[in] selection The new selection index. + /// @param[in] force Forces the new selection, even if the widget believes the selection to not have changed. + void SetSelection(int selection, bool force = false); + /// Returns the index of the currently selected item. + /// @return The index of the currently selected item. + int GetSelection() const; + + /// Adds a new option to the select control. + /// @param[in] rml The RML content used to represent the option. + /// @param[in] value The value of the option. + /// @param[in] before The index of the element to insert the new option before. + /// @param[in] select True to select the new option. + /// @param[in] selectable If true this option can be selected. If false, this option is not selectable. + /// @return The index of the new option. + int AddOption(const String& rml, const String& value, int before, bool select, bool selectable = true); + /// Moves an option element to the select control. + /// @param[in] element Element to move. + /// @param[in] value The value of the option. + /// @param[in] before The index of the element to insert the new option before. + /// @param[in] select True to select the new option. + /// @param[in] selectable If true this option can be selected. If false, this option is not selectable. + /// @return The index of the new option, or -1 if invalid. + int AddOption(ElementPtr element, const String& value, int before, bool select, bool selectable); + /// Removes an option from the select control. + /// @param[in] index The index of the option to remove. + void RemoveOption(int index); + /// Removes all options from the list. + void ClearOptions(); + + /// Returns on of the widget's options. + /// @param[in] The index of the desired option. + /// @return The option. This may be nullptr if the index was out of bounds. + SelectOption* GetOption(int index); + /// Returns the number of options in the widget. + /// @return The number of options. + int GetNumOptions() const; + + /// Processes the incoming event. + void ProcessEvent(Event& event) override; + +private: + typedef Vector< SelectOption > OptionList; + + // Shows or hides the selection box. + void ShowSelectBox(bool show); + + void AttachScrollEvent(); + void DetachScrollEvent(); + + // Parent element that holds this widget + ElementFormControl* parent_element; + + // The elements making up the drop-down process. + Element* button_element; + Element* selection_element; + Element* value_element; + + // The options in the drop down. + OptionList options; + int selected_option; + + // The current value of the widget. + String value; + + bool box_layout_dirty; + bool value_layout_dirty; + bool box_visible; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetSlider.cpp b/thirdparty/RmlUi/Source/Core/Elements/WidgetSlider.cpp new file mode 100644 index 000000000..6d5bf8b1c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetSlider.cpp @@ -0,0 +1,660 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "WidgetSlider.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/Input.h" +#include "../../../Include/RmlUi/Core/Profiling.h" +#include "../Clock.h" + +namespace Rml { + +static const float DEFAULT_REPEAT_DELAY = 0.5f; +static const float DEFAULT_REPEAT_PERIOD = 0.1f; + +WidgetSlider::WidgetSlider(ElementFormControl* _parent) +{ + parent = _parent; + + orientation = HORIZONTAL; + + track = nullptr; + bar = nullptr; + arrows[0] = nullptr; + arrows[1] = nullptr; + + bar_position = 0; + bar_drag_anchor = 0; + + arrow_timers[0] = -1; + arrow_timers[1] = -1; + last_update_time = 0; + + value = 0; + min_value = 0; + max_value = 100; + step = 1; +} + +WidgetSlider::~WidgetSlider() +{ + if (bar != nullptr) + { + parent->RemoveChild(bar); + } + + if (track != nullptr) + { + parent->RemoveChild(track); + } + + parent->RemoveEventListener(EventId::Blur, this); + parent->RemoveEventListener(EventId::Focus, this); + parent->RemoveEventListener(EventId::Keydown, this, true); + parent->RemoveEventListener(EventId::Mousedown, this); + parent->RemoveEventListener(EventId::Mouseup, this); + parent->RemoveEventListener(EventId::Mouseout, this); + parent->RemoveEventListener(EventId::Drag, this); + parent->RemoveEventListener(EventId::Dragstart, this); + parent->RemoveEventListener(EventId::Dragend, this); + + for (int i = 0; i < 2; i++) + { + if (arrows[i] != nullptr) + { + parent->RemoveChild(arrows[i]); + } + } +} + +// Initialises the slider to a given orientation. +bool WidgetSlider::Initialise() +{ + Property drag_property = Property(Style::Drag::Drag); + parent->SetProperty(PropertyId::Drag, drag_property); + + // Create all of our child elements as standard elements, and abort if we can't create them. + ElementPtr track_element = Factory::InstanceElement(parent, "*", "slidertrack", XMLAttributes()); + ElementPtr bar_element = Factory::InstanceElement(parent, "*", "sliderbar", XMLAttributes()); + ElementPtr arrow0_element = Factory::InstanceElement(parent, "*", "sliderarrowdec", XMLAttributes()); + ElementPtr arrow1_element = Factory::InstanceElement(parent, "*", "sliderarrowinc", XMLAttributes()); + + if (!track_element || !bar_element || !arrow0_element || !arrow1_element) + { + return false; + } + + // Add them as non-DOM elements. + track = parent->AppendChild(std::move(track_element), false); + bar = parent->AppendChild(std::move(bar_element), false); + arrows[0] = parent->AppendChild(std::move(arrow0_element), false); + arrows[1] = parent->AppendChild(std::move(arrow1_element), false); + + arrows[0]->SetProperty(PropertyId::Drag, drag_property); + arrows[1]->SetProperty(PropertyId::Drag, drag_property); + + // Attach the listeners + // All listeners are attached to parent, ensuring that we don't get duplicate events when it bubbles from child to parent + parent->AddEventListener(EventId::Blur, this); + parent->AddEventListener(EventId::Focus, this); + parent->AddEventListener(EventId::Keydown, this, true); + parent->AddEventListener(EventId::Mousedown, this); + parent->AddEventListener(EventId::Mouseup, this); + parent->AddEventListener(EventId::Mouseout, this); + parent->AddEventListener(EventId::Drag, this); + parent->AddEventListener(EventId::Dragstart, this); + parent->AddEventListener(EventId::Dragend, this); + + return true; +} + +// Updates the key repeats for the increment / decrement arrows. +void WidgetSlider::Update() +{ + for (int i = 0; i < 2; i++) + { + bool updated_time = false; + float delta_time = 0; + + if (arrow_timers[i] > 0) + { + if (!updated_time) + { + double current_time = Clock::GetElapsedTime(); + delta_time = float(current_time - last_update_time); + last_update_time = current_time; + } + + arrow_timers[i] -= delta_time; + while (arrow_timers[i] <= 0) + { + arrow_timers[i] += DEFAULT_REPEAT_PERIOD; + SetBarPosition(i == 0 ? OnLineDecrement() : OnLineIncrement()); + } + } + } +} + +// Sets the position of the bar. +void WidgetSlider::SetBarPosition(float _bar_position) +{ + bar_position = Math::Clamp(_bar_position, 0.0f, 1.0f); + PositionBar(); +} + +// Returns the current position of the bar. +float WidgetSlider::GetBarPosition() +{ + return bar_position; +} + +// Sets the orientation of the slider. +void WidgetSlider::SetOrientation(Orientation _orientation) +{ + orientation = _orientation; +} + +// Returns the slider's orientation. +WidgetSlider::Orientation WidgetSlider::GetOrientation() const +{ + return orientation; +} + +// Sets the dimensions to the size of the slider. +void WidgetSlider::GetDimensions(Vector2f& dimensions) const +{ + switch (orientation) + { + case VERTICAL: dimensions.x = 16; dimensions.y = 256; break; + case HORIZONTAL: dimensions.x = 256; dimensions.y = 16; break; + } +} + + +void WidgetSlider::SetValue(float target_value) +{ + float num_steps = (target_value - min_value) / step; + float new_value = min_value + Math::RoundFloat(num_steps) * step; + + if (new_value != value) + SetBarPosition(SetValueInternal(new_value)); +} + +float WidgetSlider::GetValue() const +{ + return value; +} + +// Sets the minimum value of the slider. +void WidgetSlider::SetMinValue(float _min_value) +{ + min_value = _min_value; +} + +// Sets the maximum value of the slider. +void WidgetSlider::SetMaxValue(float _max_value) +{ + max_value = _max_value; +} + +// Sets the slider's value increment. +void WidgetSlider::SetStep(float _step) +{ + // Can't have a zero step! + if (_step == 0) + return; + + step = _step; +} + +// Formats the slider's elements. +void WidgetSlider::FormatElements() +{ + RMLUI_ZoneScopedNC("RangeOnResize", 0x228044); + + Vector2f box = GetParent()->GetBox().GetSize(); + WidgetSlider::FormatElements(box, GetOrientation() == VERTICAL ? box.y : box.x); +} + + +// Lays out and resizes the internal elements. +void WidgetSlider::FormatElements(const Vector2f& containing_block, float slider_length, float bar_length) +{ + int length_axis = orientation == VERTICAL ? 1 : 0; + + // Build the box for the containing slider element. As the containing block is not guaranteed to have a defined + // height, we must use the width for both axes. + Box parent_box; + ElementUtilities::BuildBox(parent_box, Vector2f(containing_block.x, containing_block.x), parent); + + // Set the length of the slider. + Vector2f content = parent_box.GetSize(); + content[length_axis] = slider_length; + parent_box.SetContent(content); + + // Generate the initial dimensions for the track. It'll need to be cut down to fit the arrows. + Box track_box; + ElementUtilities::BuildBox(track_box, parent_box.GetSize(), track); + content = track_box.GetSize(); + content[length_axis] = slider_length -= orientation == VERTICAL ? (track_box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + track_box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM)) : + (track_box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + track_box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT)); + // If no height has been explicitly specified for the track, it'll be initialised to -1 as per normal block + // elements. We'll fix that up here. + if (orientation == HORIZONTAL && + content.y < 0) + content.y = parent_box.GetSize().y; + + // Now we size the arrows. + for (int i = 0; i < 2; i++) + { + Box arrow_box; + ElementUtilities::BuildBox(arrow_box, parent_box.GetSize(), arrows[i]); + + // Clamp the size to (0, 0). + Vector2f arrow_size = arrow_box.GetSize(); + if (arrow_size.x < 0 || + arrow_size.y < 0) + arrow_box.SetContent(Vector2f(0, 0)); + + arrows[i]->SetBox(arrow_box); + + // Shrink the track length by the arrow size. + content[length_axis] -= arrow_box.GetSize(Box::MARGIN)[length_axis]; + } + + // Now the track has been sized, we can fix everything into position. + track_box.SetContent(content); + track->SetBox(track_box); + + if (orientation == VERTICAL) + { + Vector2f offset(arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::LEFT), arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::TOP)); + arrows[0]->SetOffset(offset, parent); + + offset.x = track->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y += arrows[0]->GetBox().GetSize(Box::BORDER).y + arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM) + track->GetBox().GetEdge(Box::MARGIN, Box::TOP); + track->SetOffset(offset, parent); + + offset.x = arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y += track->GetBox().GetSize(Box::BORDER).y + track->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM) + arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::TOP); + arrows[1]->SetOffset(offset, parent); + } + else + { + Vector2f offset(arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::LEFT), arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::TOP)); + arrows[0]->SetOffset(offset, parent); + + offset.x += arrows[0]->GetBox().GetSize(Box::BORDER).x + arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::RIGHT) + track->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y = track->GetBox().GetEdge(Box::MARGIN, Box::TOP); + track->SetOffset(offset, parent); + + offset.x += track->GetBox().GetSize(Box::BORDER).x + track->GetBox().GetEdge(Box::MARGIN, Box::RIGHT) + arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y = arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::TOP); + arrows[1]->SetOffset(offset, parent); + } + + FormatBar(bar_length); + + if (parent->IsDisabled()) + { + // Propagate disabled state to child elements + bar->SetPseudoClass("disabled", true); + track->SetPseudoClass("disabled", true); + arrows[0]->SetPseudoClass("disabled", true); + arrows[1]->SetPseudoClass("disabled", true); + } +} + +// Lays out and positions the bar element. +void WidgetSlider::FormatBar(float bar_length) +{ + Box bar_box; + ElementUtilities::BuildBox(bar_box, parent->GetBox().GetSize(), bar); + auto& computed = bar->GetComputedValues(); + + Vector2f bar_box_content = bar_box.GetSize(); + if (orientation == HORIZONTAL) + { + if (computed.height.type == Style::Height::Auto) + bar_box_content.y = parent->GetBox().GetSize().y; + } + + if (bar_length >= 0) + { + Vector2f track_size = track->GetBox().GetSize(); + + if (orientation == VERTICAL) + { + float track_length = track_size.y - (bar_box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + bar_box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM)); + + if (computed.height.type == Style::Height::Auto) + { + bar_box_content.y = track_length * bar_length; + + // Check for 'min-height' restrictions. + float min_track_length = ResolveValue(computed.min_height, track_length); + bar_box_content.y = Math::Max(min_track_length, bar_box_content.y); + + // Check for 'max-height' restrictions. + float max_track_length = ResolveValue(computed.max_height, track_length); + if (max_track_length > 0) + bar_box_content.y = Math::Min(max_track_length, bar_box_content.y); + } + + // Make sure we haven't gone further than we're allowed to (min-height may have made us too big). + bar_box_content.y = Math::Min(bar_box_content.y, track_length); + } + else + { + float track_length = track_size.x - (bar_box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + bar_box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT)); + + if (computed.width.type == Style::Width::Auto) + { + bar_box_content.x = track_length * bar_length; + + // Check for 'min-width' restrictions. + float min_track_length = ResolveValue(computed.min_width, track_length); + bar_box_content.x = Math::Max(min_track_length, bar_box_content.x); + + // Check for 'max-width' restrictions. + float max_track_length = ResolveValue(computed.max_width, track_length); + if (max_track_length > 0) + bar_box_content.x = Math::Min(max_track_length, bar_box_content.x); + } + + // Make sure we haven't gone further than we're allowed to (min-width may have made us too big). + bar_box_content.x = Math::Min(bar_box_content.x, track_length); + } + } + + // Set the new dimensions on the bar to re-decorate it. + bar_box.SetContent(bar_box_content); + bar->SetBox(bar_box); + + // Now that it's been resized, re-position it. + PositionBar(); +} + +// Returns the widget's parent element. +Element* WidgetSlider::GetParent() const +{ + return parent; +} + +// Handles events coming through from the slider's components. +void WidgetSlider::ProcessEvent(Event& event) +{ + if (parent->IsDisabled()) + return; + + switch (event.GetId()) + { + case EventId::Mousedown: + { + if (event.GetTargetElement() == parent || event.GetTargetElement() == track) + { + float mouse_position, bar_halfsize; + + if (orientation == HORIZONTAL) + { + mouse_position = event.GetParameter< float >("mouse_x", 0); + bar_halfsize = 0.5f * bar->GetBox().GetSize(Box::BORDER).x; + } + else + { + mouse_position = event.GetParameter< float >("mouse_y", 0); + bar_halfsize = 0.5f * bar->GetBox().GetSize(Box::BORDER).y; + } + + float new_bar_position = AbsolutePositionToBarPosition(mouse_position - bar_halfsize); + SetBarPosition(OnBarChange(new_bar_position)); + } + else if (event.GetTargetElement() == arrows[0]) + { + arrow_timers[0] = DEFAULT_REPEAT_DELAY; + last_update_time = Clock::GetElapsedTime(); + SetBarPosition(OnLineDecrement()); + } + else if (event.GetTargetElement() == arrows[1]) + { + arrow_timers[1] = DEFAULT_REPEAT_DELAY; + last_update_time = Clock::GetElapsedTime(); + SetBarPosition(OnLineIncrement()); + } + } + break; + + case EventId::Mouseup: + case EventId::Mouseout: + { + if (event.GetTargetElement() == arrows[0]) + arrow_timers[0] = -1; + else if (event.GetTargetElement() == arrows[1]) + arrow_timers[1] = -1; + } + break; + + case EventId::Dragstart: + { + if (event.GetTargetElement() == parent) + { + bar->SetPseudoClass("active", true); + + if (orientation == HORIZONTAL) + bar_drag_anchor = event.GetParameter< float >("mouse_x", 0) - bar->GetAbsoluteOffset().x; + else + bar_drag_anchor = event.GetParameter< float >("mouse_y", 0) - bar->GetAbsoluteOffset().y; + } + } + break; + case EventId::Drag: + { + if (event.GetTargetElement() == parent) + { + float new_bar_offset = event.GetParameter< float >((orientation == HORIZONTAL ? "mouse_x" : "mouse_y"), 0) - bar_drag_anchor; + float new_bar_position = AbsolutePositionToBarPosition(new_bar_offset); + + SetBarPosition(OnBarChange(new_bar_position)); + } + } + break; + case EventId::Dragend: + { + if (event.GetTargetElement() == parent) + { + bar->SetPseudoClass("active", false); + } + } + break; + + + case EventId::Keydown: + { + Input::KeyIdentifier key_identifier = (Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0); + + switch (key_identifier) + { + case Input::KI_LEFT: + if (orientation == HORIZONTAL) SetBarPosition(OnLineDecrement()); + break; + case Input::KI_UP: + if (orientation == VERTICAL) SetBarPosition(OnLineDecrement()); + break; + case Input::KI_RIGHT: + if (orientation == HORIZONTAL) SetBarPosition(OnLineIncrement()); + break; + case Input::KI_DOWN: + if (orientation == VERTICAL) SetBarPosition(OnLineIncrement()); + break; + default: + break; + } + } + break; + + case EventId::Focus: + { + if (event.GetTargetElement() == parent) + bar->SetPseudoClass("focus", true); + } + break; + case EventId::Blur: + { + if (event.GetTargetElement() == parent) + bar->SetPseudoClass("focus", false); + } + break; + + default: + break; + } +} + +// Called when the slider's bar position is set or dragged. +float WidgetSlider::OnBarChange(float bar_position) +{ + float new_value = min_value + bar_position * (max_value - min_value); + int num_steps = Math::RoundToInteger((new_value - value) / step); + + return SetValueInternal(value + num_steps * step); +} + +// Called when the slider is incremented by one 'line'. +float WidgetSlider::OnLineIncrement() +{ + return SetValueInternal(value + step); +} + +// Called when the slider is decremented by one 'line'. +float WidgetSlider::OnLineDecrement() +{ + return SetValueInternal(value - step); +} + +float WidgetSlider::AbsolutePositionToBarPosition(float absolute_position) const +{ + float new_bar_position = bar_position; + + if (orientation == HORIZONTAL) + { + const float edge_left = bar->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + const float edge_right = bar->GetBox().GetEdge(Box::MARGIN, Box::RIGHT); + + float traversable_track_length = track->GetBox().GetSize(Box::CONTENT).x - bar->GetBox().GetSize(Box::BORDER).x - edge_left - edge_right; + if (traversable_track_length > 0) + { + float traversable_track_origin = track->GetAbsoluteOffset().x + edge_left; + new_bar_position = (absolute_position - traversable_track_origin) / traversable_track_length; + new_bar_position = Math::Clamp(new_bar_position, 0.0f, 1.0f); + } + } + else + { + const float edge_top = bar->GetBox().GetEdge(Box::MARGIN, Box::TOP); + const float edge_bottom = bar->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM); + + float traversable_track_length = track->GetBox().GetSize(Box::CONTENT).y - bar->GetBox().GetSize(Box::BORDER).y - edge_top - edge_bottom; + if (traversable_track_length > 0) + { + float traversable_track_origin = track->GetAbsoluteOffset().y + edge_top; + new_bar_position = (absolute_position - traversable_track_origin) / traversable_track_length; + new_bar_position = Math::Clamp(new_bar_position, 0.0f, 1.0f); + } + } + + return new_bar_position; +} + + +void WidgetSlider::PositionBar() +{ + const Vector2f track_dimensions = track->GetBox().GetSize(); + const Vector2f bar_dimensions = bar->GetBox().GetSize(Box::BORDER); + + if (orientation == VERTICAL) + { + const float edge_top = bar->GetBox().GetEdge(Box::MARGIN, Box::TOP); + const float edge_bottom = bar->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM); + + float traversable_track_length = track_dimensions.y - bar_dimensions.y - edge_top - edge_bottom; + bar->SetOffset( + Vector2f( + bar->GetBox().GetEdge(Box::MARGIN, Box::LEFT), + track->GetRelativeOffset().y + edge_top + traversable_track_length * bar_position + ), + parent + ); + } + else + { + const float edge_left = bar->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + const float edge_right = bar->GetBox().GetEdge(Box::MARGIN, Box::RIGHT); + + float traversable_track_length = track_dimensions.x - bar_dimensions.x - edge_left - edge_right; + bar->SetOffset( + Vector2f( + track->GetRelativeOffset().x + edge_left + traversable_track_length * bar_position, + bar->GetBox().GetEdge(Box::MARGIN, Box::TOP) + ), + parent + ); + } +} + +// Clamps the new value, sets it on the slider. +float WidgetSlider::SetValueInternal(float new_value) +{ + if (min_value < max_value) + { + value = Math::Clamp(new_value, min_value, max_value); + } + else if (min_value > max_value) + { + value = Math::Clamp(new_value, max_value, min_value); + } + else + { + value = min_value; + return 0; + } + + Dictionary parameters; + parameters["value"] = value; + GetParent()->DispatchEvent(EventId::Change, parameters); + + + // TODO: This might not be the safest approach as this will call SetValue(), + // thus, a slight mismatch will result in infinite recursion. + GetParent()->SetAttribute("value", value); + + return (value - min_value) / (max_value - min_value); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetSlider.h b/thirdparty/RmlUi/Source/Core/Elements/WidgetSlider.h new file mode 100644 index 000000000..faf3904c1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetSlider.h @@ -0,0 +1,162 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_WIDGETSLIDER_H +#define RMLUI_CORE_ELEMENTS_WIDGETSLIDER_H + +#include "../../../Include/RmlUi/Core/EventListener.h" + +namespace Rml { + +class ElementFormControl; + +/** + A generic widget for incorporating sliding functionality into an element. + + @author Peter Curry + */ + +class WidgetSlider final : public EventListener +{ +public: + enum Orientation + { + VERTICAL, + HORIZONTAL + }; + + WidgetSlider(ElementFormControl* parent); + virtual ~WidgetSlider(); + + /// Initialises the slider's hidden elements. + bool Initialise(); + + /// Updates the key repeats for the increment / decrement arrows. + void Update(); + + /// Sets the position of the bar. + /// @param[in] bar_position The new position of the bar (0 representing the start of the track, 1 representing the end). + void SetBarPosition(float bar_position); + /// Returns the current position of the bar. + /// @return The current position of the bar (0 representing the start of the track, 1 representing the end). + float GetBarPosition(); + + /// Sets the orientation of the slider. + void SetOrientation(Orientation orientation); + /// Returns the slider's orientation. + Orientation GetOrientation() const; + + /// Sets the dimensions to the size of the slider. + void GetDimensions(Vector2f& dimensions) const; + + /// Sets a new value on the slider, clamped to the min and max values, and rounded to the nearest increment. + void SetValue(float value); + /// Returns the current value of the slider. + float GetValue() const; + + /// Sets the minimum value of the slider. + void SetMinValue(float min_value); + /// Sets the maximum value of the slider. + void SetMaxValue(float max_value); + /// Sets the slider's value increment. + void SetStep(float step); + + /// Formats the slider's elements. + void FormatElements(); + +private: + /// Lays out and resizes the slider's internal elements. + /// @param[in] containing_block The padded box containing the slider. This is used to resolve relative properties. + /// @param[in] slider_length The total length, in pixels, of the slider widget. + /// @param[in] bar_length The total length of the bar, as a proportion of the track length. If this is -1, the intrinsic length will be used. + void FormatElements(const Vector2f& containing_block, float slider_length, float bar_length = -1); + /// Lays out and positions the bar element. + /// @param[in] bar_length The total length of the bar, as a proportion of the track length. If this is -1, the intrinsic length will be used. + void FormatBar(float bar_length = -1); + + /// Returns the widget's parent element. + Element* GetParent() const; + + /// Handles events coming through from the slider's components. + void ProcessEvent(Event& event) override; + + /// Called when the slider's bar position is set or dragged. + /// @param[in] bar_position The new position of the bar (0 representing the start of the track, 1 representing the end). + /// @return The new position of the bar. + float OnBarChange(float bar_position); + /// Called when the slider is incremented by one 'line', either by the down / right key or a mouse-click on the + /// increment arrow. + /// @return The new position of the bar. + float OnLineIncrement(); + /// Called when the slider is decremented by one 'line', either by the up / left key or a mouse-click on the + /// decrement arrow. + /// @return The new position of the bar. + float OnLineDecrement(); + + /// Determine the normalized bar position given an absolute position coordinate. + /// @param[in] absolute_position Absolute position along the axis determined by 'orientation'. + /// @return The normalized bar position [0, 1] + float AbsolutePositionToBarPosition(float absolute_position) const; + + void PositionBar(); + + /// Clamps the new value, sets it on the slider and returns it as a number from 0 to 1, 0 being the minimum + /// value and 1 the maximum. + /// @param[in] new_value The new value to set on the slider. + /// @return The new parametric value of the slider. + float SetValueInternal(float new_value); + + ElementFormControl* parent; + + Orientation orientation; + + // The background track element, across which the bar slides. + Element* track; + // The bar element. This is the element that is dragged across the trough. + Element* bar; + // The two (optional) buttons for incrementing and decrementing the slider. + Element* arrows[2]; + + // A number from 0 to 1, indicating how far along the track the bar is. + float bar_position; + // If the bar is being dragged, this is the pixel offset from the start of the bar to where it was picked up. + float bar_drag_anchor; + + // Set to the auto-repeat timer if either of the arrow buttons have been pressed, -1 if they haven't. + float arrow_timers[2]; + double last_update_time; + + float value; + float min_value; + float max_value; + + float step; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInput.cpp b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInput.cpp new file mode 100644 index 000000000..662c4e677 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInput.cpp @@ -0,0 +1,1236 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "WidgetTextInput.h" +#include "ElementTextSelection.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControl.h" +#include "../../../Include/RmlUi/Core/Core.h" +#include "../../../Include/RmlUi/Core/ElementScroll.h" +#include "../../../Include/RmlUi/Core/ElementText.h" +#include "../../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../../Include/RmlUi/Core/Input.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/SystemInterface.h" +#include "../../../Include/RmlUi/Core/StringUtilities.h" +#include "../Clock.h" +#include +#include + +namespace Rml { + +static constexpr float CURSOR_BLINK_TIME = 0.7f; + +static bool IsWordCharacter(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || ((unsigned char)c >= 128); +} + +WidgetTextInput::WidgetTextInput(ElementFormControl* _parent) : internal_dimensions(0, 0), scroll_offset(0, 0), selection_geometry(_parent), cursor_position(0, 0), cursor_size(0, 0), cursor_geometry(_parent) +{ + keyboard_showed = false; + + parent = _parent; + parent->SetProperty(PropertyId::WhiteSpace, Property(Style::WhiteSpace::Pre)); + parent->SetProperty(PropertyId::OverflowX, Property(Style::Overflow::Hidden)); + parent->SetProperty(PropertyId::OverflowY, Property(Style::Overflow::Hidden)); + parent->SetProperty(PropertyId::Drag, Property(Style::Drag::Drag)); + parent->SetClientArea(Box::CONTENT); + + parent->AddEventListener(EventId::Keydown, this, true); + parent->AddEventListener(EventId::Textinput, this, true); + parent->AddEventListener(EventId::Focus, this, true); + parent->AddEventListener(EventId::Blur, this, true); + parent->AddEventListener(EventId::Mousedown, this, true); + parent->AddEventListener(EventId::Dblclick, this, true); + parent->AddEventListener(EventId::Drag, this, true); + + ElementPtr unique_text = Factory::InstanceElement(parent, "#text", "#text", XMLAttributes()); + text_element = rmlui_dynamic_cast< ElementText* >(unique_text.get()); + ElementPtr unique_selected_text = Factory::InstanceElement(parent, "#text", "#text", XMLAttributes()); + selected_text_element = rmlui_dynamic_cast< ElementText* >(unique_selected_text.get()); + if (text_element) + { + text_element->SuppressAutoLayout(); + parent->AppendChild(std::move(unique_text), false); + + selected_text_element->SuppressAutoLayout(); + parent->AppendChild(std::move(unique_selected_text), false); + } + + // Create the dummy selection element. + ElementPtr unique_selection = Factory::InstanceElement(parent, "#selection", "selection", XMLAttributes()); + if (ElementTextSelection* text_selection_element = rmlui_dynamic_cast(unique_selection.get())) + { + selection_element = text_selection_element; + text_selection_element->SetWidget(this); + parent->AppendChild(std::move(unique_selection), false); + } + + edit_index = 0; + absolute_cursor_index = 0; + cursor_line_index = 0; + cursor_character_index = 0; + cursor_on_right_side_of_character = true; + cancel_next_drag = false; + + ideal_cursor_position = 0; + + max_length = -1; + + selection_anchor_index = 0; + selection_begin_index = 0; + selection_length = 0; + + last_update_time = 0; + + ShowCursor(false); +} + +WidgetTextInput::~WidgetTextInput() +{ + parent->RemoveEventListener(EventId::Keydown, this, true); + parent->RemoveEventListener(EventId::Textinput, this, true); + parent->RemoveEventListener(EventId::Focus, this, true); + parent->RemoveEventListener(EventId::Blur, this, true); + parent->RemoveEventListener(EventId::Mousedown, this, true); + parent->RemoveEventListener(EventId::Dblclick, this, true); + parent->RemoveEventListener(EventId::Drag, this, true); + + // Remove all the children added by the text widget. + parent->RemoveChild(text_element); + parent->RemoveChild(selected_text_element); + parent->RemoveChild(selection_element); +} + +// Sets the value of the text field. +void WidgetTextInput::SetValue(const String& value) +{ + text_element->SetText(value); + FormatElement(); + + UpdateRelativeCursor(); +} + +// Sets the maximum length (in characters) of this text field. +void WidgetTextInput::SetMaxLength(int _max_length) +{ + if (max_length != _max_length) + { + max_length = _max_length; + if (max_length >= 0) + { + String value = GetElement()->GetAttribute< String >("value", ""); + + int num_characters = 0; + size_t i_erase = value.size(); + + for (auto it = StringIteratorU8(value); it; ++it) + { + num_characters += 1; + if (num_characters > max_length) + { + i_erase = size_t(it.offset()); + break; + } + } + + if(i_erase < value.size()) + { + value.erase(i_erase); + GetElement()->SetAttribute("value", value); + } + } + } +} + +// Returns the maximum length (in characters) of this text field. +int WidgetTextInput::GetMaxLength() const +{ + return max_length; +} + +int WidgetTextInput::GetLength() const +{ + String value = GetElement()->GetAttribute< String >("value", ""); + size_t result = StringUtilities::LengthUTF8(value); + return (int)result; +} + +// Update the colours of the selected text. +void WidgetTextInput::UpdateSelectionColours() +{ + // Determine what the colour of the selected text is. If our 'selection' element has the 'color' + // attribute set, then use that. Otherwise, use the inverse of our own text colour. + Colourb colour; + const Property* colour_property = selection_element->GetLocalProperty("color"); + if (colour_property != nullptr) + colour = colour_property->Get< Colourb >(); + else + { + colour = parent->GetComputedValues().color; + colour.red = 255 - colour.red; + colour.green = 255 - colour.green; + colour.blue = 255 - colour.blue; + } + + // Set the computed text colour on the element holding the selected text. + selected_text_element->SetProperty(PropertyId::Color, Property(colour, Property::COLOUR)); + + // If the 'background-color' property has been set on the 'selection' element, use that as the + // background colour for the selected text. Otherwise, use the inverse of the selected text + // colour. + colour_property = selection_element->GetLocalProperty("background-color"); + if (colour_property != nullptr) + selection_colour = colour_property->Get< Colourb >(); + else + selection_colour = Colourb(255 - colour.red, 255 - colour.green, 255 - colour.blue, colour.alpha); +} + +// Updates the cursor, if necessary. +void WidgetTextInput::OnUpdate() +{ + if (cursor_timer > 0) + { + double current_time = Clock::GetElapsedTime(); + cursor_timer -= float(current_time - last_update_time); + last_update_time = current_time; + + while (cursor_timer <= 0) + { + cursor_timer += CURSOR_BLINK_TIME; + cursor_visible = !cursor_visible; + } + } +} + +void WidgetTextInput::OnResize() +{ + GenerateCursor(); + + Vector2f text_position = parent->GetBox().GetPosition(Box::CONTENT); + text_element->SetOffset(text_position, parent); + selected_text_element->SetOffset(text_position, parent); + + Vector2f new_internal_dimensions = parent->GetBox().GetSize(Box::CONTENT); + if (new_internal_dimensions != internal_dimensions) + { + internal_dimensions = new_internal_dimensions; + + FormatElement(); + UpdateCursorPosition(); + } +} + +// Renders the cursor, if it is visible. +void WidgetTextInput::OnRender() +{ + ElementUtilities::SetClippingRegion(text_element); + + Vector2f text_translation = parent->GetAbsoluteOffset() - Vector2f(parent->GetScrollLeft(), parent->GetScrollTop()); + selection_geometry.Render(text_translation); + + if (cursor_visible && + !parent->IsDisabled()) + { + cursor_geometry.Render(text_translation + cursor_position); + } +} + +// Formats the widget's internal content. +void WidgetTextInput::OnLayout() +{ + FormatElement(); + parent->SetScrollLeft(scroll_offset.x); + parent->SetScrollTop(scroll_offset.y); +} + +// Returns the input element's underlying text element. +ElementText* WidgetTextInput::GetTextElement() +{ + return text_element; +} + +// Returns the input element's maximum allowed text dimensions. +const Vector2f& WidgetTextInput::GetTextDimensions() const +{ + return internal_dimensions; +} + +// Gets the parent element containing the widget. +Element* WidgetTextInput::GetElement() const +{ + return parent; +} + +// Dispatches a change event to the widget's element. +void WidgetTextInput::DispatchChangeEvent(bool linebreak) +{ + Dictionary parameters; + parameters["value"] = GetElement()->GetAttribute< String >("value", ""); + parameters["linebreak"] = Variant(linebreak); + GetElement()->DispatchEvent(EventId::Change, parameters); +} + +// Processes the "keydown" and "textinput" event to write to the input field, and the "focus" and "blur" to set +// the state of the cursor. +void WidgetTextInput::ProcessEvent(Event& event) +{ + if (parent->IsDisabled()) + return; + + switch (event.GetId()) + { + case EventId::Keydown: + { + Input::KeyIdentifier key_identifier = (Input::KeyIdentifier) event.GetParameter< int >("key_identifier", 0); + bool numlock = event.GetParameter< int >("num_lock_key", 0) > 0; + bool shift = event.GetParameter< int >("shift_key", 0) > 0; + bool ctrl = event.GetParameter< int >("ctrl_key", 0) > 0; + + switch (key_identifier) + { + case Input::KI_NUMPAD4: if (numlock) break; //-fallthrough + case Input::KI_LEFT: MoveCursorHorizontal(ctrl ? CursorMovement::PreviousWord : CursorMovement::Left, shift); break; + + case Input::KI_NUMPAD6: if (numlock) break; //-fallthrough + case Input::KI_RIGHT: MoveCursorHorizontal(ctrl ? CursorMovement::NextWord : CursorMovement::Right, shift); break; + + case Input::KI_NUMPAD8: if (numlock) break; //-fallthrough + case Input::KI_UP: MoveCursorVertical(-1, shift); break; + + case Input::KI_NUMPAD2: if (numlock) break; //-fallthrough + case Input::KI_DOWN: MoveCursorVertical(1, shift); break; + + case Input::KI_NUMPAD7: if (numlock) break; //-fallthrough + case Input::KI_HOME: MoveCursorHorizontal(ctrl ? CursorMovement::Begin : CursorMovement::BeginLine, shift); break; + + case Input::KI_NUMPAD1: if (numlock) break; //-fallthrough + case Input::KI_END: MoveCursorHorizontal(ctrl ? CursorMovement::End : CursorMovement::EndLine, shift); break; + + case Input::KI_NUMPAD3: if (numlock) break; //-fallthrough + case Input::KI_PRIOR: MoveCursorVertical(-int(internal_dimensions.y / parent->GetLineHeight()) + 1, shift); break; + + case Input::KI_NUMPAD9: if (numlock) break; //-fallthrough + case Input::KI_NEXT: MoveCursorVertical(int(internal_dimensions.y / parent->GetLineHeight()) - 1, shift); break; + + case Input::KI_BACK: + { + CursorMovement direction = (ctrl ? CursorMovement::PreviousWord : CursorMovement::Left); + if (DeleteCharacters(direction)) + { + FormatElement(); + UpdateRelativeCursor(); + } + + ShowCursor(true); + } + break; + + case Input::KI_DECIMAL: if (numlock) break; //-fallthrough + case Input::KI_DELETE: + { + CursorMovement direction = (ctrl ? CursorMovement::NextWord : CursorMovement::Right); + if (DeleteCharacters(direction)) + { + FormatElement(); + UpdateRelativeCursor(); + } + + ShowCursor(true); + } + break; + + case Input::KI_NUMPADENTER: + case Input::KI_RETURN: + { + LineBreak(); + } + break; + + case Input::KI_A: + { + if (ctrl) + { + MoveCursorHorizontal(CursorMovement::Begin, false); + MoveCursorHorizontal(CursorMovement::End, true); + } + } + break; + + case Input::KI_C: + { + if (ctrl) + CopySelection(); + } + break; + + case Input::KI_X: + { + if (ctrl) + { + CopySelection(); + DeleteSelection(); + } + } + break; + + case Input::KI_V: + { + if (ctrl) + { + String clipboard_text; + GetSystemInterface()->GetClipboardText(clipboard_text); + + AddCharacters(clipboard_text); + } + } + break; + + // Ignore tabs so input fields can be navigated through with keys. + case Input::KI_TAB: + return; + + default: + break; + } + + event.StopPropagation(); + } + break; + + case EventId::Textinput: + { + // Only process the text if no modifier keys are pressed. + if (event.GetParameter< int >("ctrl_key", 0) == 0 && + event.GetParameter< int >("alt_key", 0) == 0 && + event.GetParameter< int >("meta_key", 0) == 0) + { + String text = event.GetParameter("text", String{}); + AddCharacters(text); + } + + ShowCursor(true); + event.StopPropagation(); + } + break; + case EventId::Focus: + { + if (event.GetTargetElement() == parent) + { + UpdateSelection(false); + ShowCursor(true, false); + } + } + break; + case EventId::Blur: + { + if (event.GetTargetElement() == parent) + { + ClearSelection(); + ShowCursor(false, false); + } + } + break; + case EventId::Drag: + if (cancel_next_drag) + { + // We currently ignore drag events right after a double click. They would need to be handled + // specially by selecting whole words at a time, which is not yet implemented. + break; + } + //-fallthrough + case EventId::Mousedown: + { + if (event.GetTargetElement() == parent) + { + Vector2f mouse_position = Vector2f(event.GetParameter< float >("mouse_x", 0), event.GetParameter< float >("mouse_y", 0)); + mouse_position -= text_element->GetAbsoluteOffset(); + + cursor_line_index = CalculateLineIndex(mouse_position.y); + cursor_character_index = CalculateCharacterIndex(cursor_line_index, mouse_position.x); + + UpdateAbsoluteCursor(); + MoveCursorToCharacterBoundaries(false); + + UpdateCursorPosition(); + ideal_cursor_position = cursor_position.x; + + UpdateSelection(event == EventId::Drag || event.GetParameter< int >("shift_key", 0) > 0); + + ShowCursor(true); + cancel_next_drag = false; + } + } + break; + case EventId::Dblclick: + { + if (event.GetTargetElement() == parent) + { + ExpandSelection(); + cancel_next_drag = true; + } + } + break; + + default: + break; + } + +} + +// Adds a new character to the string at the cursor position. +bool WidgetTextInput::AddCharacters(String string) +{ + // Erase invalid characters from string + auto invalid_character = [this](char c) { + return ((unsigned char)c <= 127 && !IsCharacterValid(c)); + }; + string.erase( + std::remove_if(string.begin(), string.end(), invalid_character), + string.end() + ); + + if (string.empty()) + return false; + + if (selection_length > 0) + DeleteSelection(); + + if (max_length >= 0 && GetLength() >= max_length) + return false; + + String value = GetElement()->GetAttribute< String >("value", ""); + + value.insert(std::min(GetCursorIndex(), value.size()), string); + + edit_index += (int)string.size(); + + GetElement()->SetAttribute("value", value); + DispatchChangeEvent(); + + UpdateSelection(false); + + return true; +} + +// Deletes a character from the string. +bool WidgetTextInput::DeleteCharacters(CursorMovement direction) +{ + // We set a selection of characters according to direction, and then delete it. + // If we already have a selection, we delete that first. + if (selection_length <= 0) + MoveCursorHorizontal(direction, true); + + if (selection_length > 0) + { + DeleteSelection(); + DispatchChangeEvent(); + + UpdateSelection(false); + + return true; + } + + return false; +} + +// Copies the selection (if any) to the clipboard. +void WidgetTextInput::CopySelection() +{ + const String& value = GetElement()->GetAttribute< String >("value", ""); + const String snippet = value.substr(std::min(size_t(selection_begin_index), size_t(value.size())), selection_length); + GetSystemInterface()->SetClipboardText(snippet); +} + +// Returns the absolute index of the cursor. +int WidgetTextInput::GetCursorIndex() const +{ + return edit_index; +} + +// Moves the cursor along the current line. +void WidgetTextInput::MoveCursorHorizontal(CursorMovement movement, bool select) +{ + // Whether to seek forward or back to align to utf8 boundaries later. + bool seek_forward = false; + + switch (movement) + { + case CursorMovement::Begin: + absolute_cursor_index = 0; + break; + case CursorMovement::BeginLine: + absolute_cursor_index -= cursor_character_index; + break; + case CursorMovement::PreviousWord: + if (cursor_character_index <= 1) + { + absolute_cursor_index -= 1; + } + else + { + bool word_character_found = false; + const char* p_rend = lines[cursor_line_index].content.data(); + const char* p_rbegin = p_rend + cursor_character_index; + const char* p = p_rbegin - 1; + for (; p > p_rend; --p) + { + bool is_word_character = IsWordCharacter(*p); + if(word_character_found && !is_word_character) + break; + else if(is_word_character) + word_character_found = true; + } + if (p != p_rend) ++p; + absolute_cursor_index += int(p - p_rbegin); + } + break; + case CursorMovement::Left: + if (!select && selection_length > 0) + absolute_cursor_index = selection_begin_index; + else + absolute_cursor_index -= 1; + break; + case CursorMovement::Right: + seek_forward = true; + if (!select && selection_length > 0) + absolute_cursor_index = selection_begin_index + selection_length; + else + absolute_cursor_index += 1; + break; + case CursorMovement::NextWord: + if (cursor_character_index >= lines[cursor_line_index].content_length) + { + absolute_cursor_index += 1; + } + else + { + bool whitespace_found = false; + const char* p_begin = lines[cursor_line_index].content.data() + cursor_character_index; + const char* p_end = lines[cursor_line_index].content.data() + lines[cursor_line_index].content_length; + const char* p = p_begin; + for (; p < p_end; ++p) + { + bool is_whitespace = !IsWordCharacter(*p); + if (whitespace_found && !is_whitespace) + break; + else if (is_whitespace) + whitespace_found = true; + } + absolute_cursor_index += int(p - p_begin); + } + break; + case CursorMovement::EndLine: + absolute_cursor_index += lines[cursor_line_index].content_length - cursor_character_index; + break; + case CursorMovement::End: + absolute_cursor_index = INT_MAX; + break; + default: + break; + } + + absolute_cursor_index = Math::Max(0, absolute_cursor_index); + + UpdateRelativeCursor(); + MoveCursorToCharacterBoundaries(seek_forward); + + ideal_cursor_position = cursor_position.x; + UpdateSelection(select); + ShowCursor(true); +} + +// Moves the cursor up and down the text field. +void WidgetTextInput::MoveCursorVertical(int distance, bool select) +{ + bool update_ideal_cursor_position = false; + cursor_line_index += distance; + + if (cursor_line_index < 0) + { + cursor_line_index = 0; + cursor_character_index = 0; + + update_ideal_cursor_position = true; + } + else if (cursor_line_index >= (int) lines.size()) + { + cursor_line_index = (int) lines.size() - 1; + cursor_character_index = (int) lines[cursor_line_index].content_length; + + update_ideal_cursor_position = true; + } + else + cursor_character_index = CalculateCharacterIndex(cursor_line_index, ideal_cursor_position); + + UpdateAbsoluteCursor(); + + MoveCursorToCharacterBoundaries(false); + + UpdateCursorPosition(); + + if (update_ideal_cursor_position) + ideal_cursor_position = cursor_position.x; + + UpdateSelection(select); + + ShowCursor(true); +} + +void WidgetTextInput::MoveCursorToCharacterBoundaries(bool forward) +{ + const char* p_line_begin = lines[cursor_line_index].content.data(); + const char* p_line_end = p_line_begin + lines[cursor_line_index].content_length; + const char* p_cursor = p_line_begin + cursor_character_index; + const char* p = p_cursor; + + if (forward) + p = StringUtilities::SeekForwardUTF8(p_cursor, p_line_end); + else + p = StringUtilities::SeekBackwardUTF8(p_cursor, p_line_begin); + + if (p != p_cursor) + { + absolute_cursor_index += int(p - p_cursor); + UpdateRelativeCursor(); + } +} + +void WidgetTextInput::ExpandSelection() +{ + const char* const p_begin = lines[cursor_line_index].content.data(); + const char* const p_end = p_begin + lines[cursor_line_index].content_length; + const char* const p_index = p_begin + cursor_character_index; + + // If true, we are expanding word characters, if false, whitespace characters. + // The first character encountered defines the bool. + bool expanding_word = false; + bool expanding_word_set = false; + + auto character_is_wrong_type = [&expanding_word_set, &expanding_word](const char* p) -> bool { + bool is_word_character = IsWordCharacter(*p); + if (expanding_word_set && (expanding_word != is_word_character)) + return true; + if (!expanding_word_set) + { + expanding_word = is_word_character; + expanding_word_set = true; + } + return false; + }; + + auto search_left = [&]() -> const char* { + const char* p = p_index; + for (; p > p_begin; p--) + if (character_is_wrong_type(p - 1)) + break; + return p; + }; + auto search_right = [&]() -> const char* { + const char* p = p_index; + for (; p < p_end; p++) + if (character_is_wrong_type(p)) + break; + return p; + }; + + const char* p_left = p_index; + const char* p_right = p_index; + + if (cursor_on_right_side_of_character) + { + p_right = search_right(); + p_left = search_left(); + } + else + { + p_left = search_left(); + p_right = search_right(); + } + + absolute_cursor_index -= int(p_index - p_left); + UpdateRelativeCursor(); + MoveCursorToCharacterBoundaries(false); + UpdateSelection(false); + + absolute_cursor_index += int(p_right - p_left); + UpdateRelativeCursor(); + MoveCursorToCharacterBoundaries(true); + UpdateSelection(true); +} + +// Updates the absolute cursor index from the relative cursor indices. +void WidgetTextInput::UpdateAbsoluteCursor() +{ + RMLUI_ASSERT(cursor_line_index < (int) lines.size()) + + absolute_cursor_index = cursor_character_index; + edit_index = cursor_character_index; + + for (int i = 0; i < cursor_line_index; i++) + { + absolute_cursor_index += (int)lines[i].content.size(); + edit_index += (int)lines[i].content.size() + lines[i].extra_characters; + } +} + +// Updates the relative cursor indices from the absolute cursor index. +void WidgetTextInput::UpdateRelativeCursor() +{ + int num_characters = 0; + edit_index = absolute_cursor_index; + + for (size_t i = 0; i < lines.size(); i++) + { + if (num_characters + lines[i].content_length >= absolute_cursor_index) + { + cursor_line_index = (int) i; + cursor_character_index = absolute_cursor_index - num_characters; + + UpdateCursorPosition(); + + return; + } + + num_characters += (int) lines[i].content.size(); + edit_index += lines[i].extra_characters; + } + + // We shouldn't ever get here; this means we actually couldn't find where the absolute cursor said it was. So we'll + // just set the relative cursors to the very end of the text field, and update the absolute cursor to point here. + cursor_line_index = (int) lines.size() - 1; + cursor_character_index = lines[cursor_line_index].content_length; + absolute_cursor_index = num_characters; + edit_index = num_characters; + + UpdateCursorPosition(); +} + +// Calculates the line index under a specific vertical position. +int WidgetTextInput::CalculateLineIndex(float position) +{ + float line_height = parent->GetLineHeight(); + int line_index = Math::RealToInteger(position / line_height); + return Math::Clamp(line_index, 0, (int) (lines.size() - 1)); +} + +// Calculates the character index along a line under a specific horizontal position. +int WidgetTextInput::CalculateCharacterIndex(int line_index, float position) +{ + int prev_offset = 0; + float prev_line_width = 0; + + cursor_on_right_side_of_character = true; + + for(auto it = StringIteratorU8(lines[line_index].content, 0, lines[line_index].content_length); it; ) + { + ++it; + int offset = (int)it.offset(); + + float line_width = (float) ElementUtilities::GetStringWidth(text_element, lines[line_index].content.substr(0, offset)); + if (line_width > position) + { + if (position - prev_line_width < line_width - position) + { + return prev_offset; + } + else + { + cursor_on_right_side_of_character = false; + return offset; + } + } + + prev_line_width = line_width; + prev_offset = offset; + } + + return prev_offset; +} + +// Shows or hides the cursor. +void WidgetTextInput::ShowCursor(bool show, bool move_to_cursor) +{ + if (show) + { + cursor_visible = true; + SetKeyboardActive(true); + keyboard_showed = true; + + cursor_timer = CURSOR_BLINK_TIME; + last_update_time = GetSystemInterface()->GetElapsedTime(); + + // Shift the cursor into view. + if (move_to_cursor) + { + float minimum_scroll_top = (cursor_position.y + cursor_size.y) - parent->GetClientHeight(); + if (parent->GetScrollTop() < minimum_scroll_top) + parent->SetScrollTop(minimum_scroll_top); + else if (parent->GetScrollTop() > cursor_position.y) + parent->SetScrollTop(cursor_position.y); + + float minimum_scroll_left = (cursor_position.x + cursor_size.x) - parent->GetClientWidth(); + if (parent->GetScrollLeft() < minimum_scroll_left) + parent->SetScrollLeft(minimum_scroll_left); + else if (parent->GetScrollLeft() > cursor_position.x) + parent->SetScrollLeft(cursor_position.x); + + scroll_offset.x = parent->GetScrollLeft(); + scroll_offset.y = parent->GetScrollTop(); + } + } + else + { + cursor_visible = false; + cursor_timer = -1; + last_update_time = 0; + if (keyboard_showed) + { + SetKeyboardActive(false); + keyboard_showed = false; + } + } +} + +// Formats the element, laying out the text and inserting scrollbars as appropriate. +void WidgetTextInput::FormatElement() +{ + using namespace Style; + ElementScroll* scroll = parent->GetElementScroll(); + float width = parent->GetBox().GetSize(Box::PADDING).x; + + Overflow x_overflow_property = parent->GetComputedValues().overflow_x; + Overflow y_overflow_property = parent->GetComputedValues().overflow_y; + + if (x_overflow_property == Overflow::Scroll) + scroll->EnableScrollbar(ElementScroll::HORIZONTAL, width); + else + scroll->DisableScrollbar(ElementScroll::HORIZONTAL); + + if (y_overflow_property == Overflow::Scroll) + scroll->EnableScrollbar(ElementScroll::VERTICAL, width); + else + scroll->DisableScrollbar(ElementScroll::VERTICAL); + + // Format the text and determine its total area. + Vector2f content_area = FormatText(); + + // If we're set to automatically generate horizontal scrollbars, check for that now. + if (x_overflow_property == Overflow::Auto) + { + if (parent->GetClientWidth() < content_area.x) + scroll->EnableScrollbar(ElementScroll::HORIZONTAL, width); + } + + // Now check for vertical overflow. If we do turn on the scrollbar, this will cause a reflow. + if (y_overflow_property == Overflow::Auto) + { + if (parent->GetClientHeight() < content_area.y) + { + scroll->EnableScrollbar(ElementScroll::VERTICAL, width); + content_area = FormatText(); + + if (x_overflow_property == Overflow::Auto && + parent->GetClientWidth() < content_area.y) + { + scroll->EnableScrollbar(ElementScroll::HORIZONTAL, width); + } + } + } + + parent->SetContentBox(Vector2f(0, 0), content_area); + scroll->FormatScrollbars(); +} + +// Formats the input element's text field. +Vector2f WidgetTextInput::FormatText() +{ + absolute_cursor_index = edit_index; + + Vector2f content_area(0, 0); + + // Clear the old lines, and all the lines in the text elements. + lines.clear(); + text_element->ClearLines(); + selected_text_element->ClearLines(); + + // Clear the selection background geometry, and get the vertices and indices so the new geo can + // be generated. + selection_geometry.Release(true); + Vector< Vertex >& selection_vertices = selection_geometry.GetVertices(); + Vector< int >& selection_indices = selection_geometry.GetIndices(); + + // Determine the line-height of the text element. + float line_height = parent->GetLineHeight(); + + int line_begin = 0; + Vector2f line_position(0, 0); + bool last_line = false; + + // Keep generating lines until all the text content is placed. + do + { + Line line; + line.extra_characters = 0; + float line_width; + + // Generate the next line. + last_line = text_element->GenerateLine(line.content, line.content_length, line_width, line_begin, parent->GetClientWidth() - cursor_size.x, 0, false, false); + + // If this line terminates in a soft-return, then the line may be leaving a space or two behind as an orphan. + // If so, we must append the orphan onto the line even though it will push the line outside of the input + // field's bounds. + bool soft_return = false; + if (!last_line && + (line.content.empty() || + line.content[line.content.size() - 1] != '\n')) + { + soft_return = true; + + const String& text = text_element->GetText(); + String orphan; + for (int i = 1; i >= 0; --i) + { + int index = line_begin + line.content_length + i; + if (index >= (int) text.size()) + continue; + + if (text[index] != ' ') + { + orphan.clear(); + continue; + } + + int next_index = index + 1; + if (!orphan.empty() || + next_index >= (int) text.size() || + text[next_index] != ' ') + orphan += ' '; + } + + if (!orphan.empty()) + { + line.content += orphan; + line.content_length += (int) orphan.size(); + line_width += ElementUtilities::GetStringWidth(text_element, orphan); + } + } + + + // Now that we have the string of characters appearing on the new line, we split it into + // three parts; the unselected text appearing before any selected text on the line, the + // selected text on the line, and any unselected text after the selection. + String pre_selection, selection, post_selection; + GetLineSelection(pre_selection, selection, post_selection, line.content, line_begin); + + // The pre-selected text is placed, if there is any (if the selection starts on or before + // the beginning of this line, then this will be empty). + if (!pre_selection.empty()) + { + text_element->AddLine(line_position, pre_selection); + line_position.x += ElementUtilities::GetStringWidth(text_element, pre_selection); + } + + // If there is any selected text on this line, place it in the selected text element and + // generate the geometry for its background. + if (!selection.empty()) + { + selected_text_element->AddLine(line_position, selection); + int selection_width = ElementUtilities::GetStringWidth(selected_text_element, selection); + + selection_vertices.resize(selection_vertices.size() + 4); + selection_indices.resize(selection_indices.size() + 6); + GeometryUtilities::GenerateQuad(&selection_vertices[selection_vertices.size() - 4], &selection_indices[selection_indices.size() - 6], line_position, Vector2f((float)selection_width, line_height), selection_colour, (int)selection_vertices.size() - 4); + + line_position.x += selection_width; + } + + // If there is any unselected text after the selection on this line, place it in the + // standard text element after the selected text. + if (!post_selection.empty()) + text_element->AddLine(line_position, post_selection); + + + // Update variables for the next line. + line_begin += line.content_length; + line_position.x = 0; + line_position.y += line_height; + + // Grow the content area width-wise if this line is the longest so far, and push the + // height out. + content_area.x = Math::Max(content_area.x, line_width + cursor_size.x); + content_area.y = line_position.y; + + // Push a trailing '\r' token onto the back to indicate a soft return if necessary. + if (soft_return) + { + line.content += '\r'; + line.extra_characters -= 1; + + if (edit_index >= line_begin) + absolute_cursor_index += 1; + } + + // Push the new line into our array of lines, but first check if its content length needs to be truncated to + // dodge a trailing endline. + if (!line.content.empty() && + line.content[line.content.size() - 1] == '\n') + line.content_length -= 1; + lines.push_back(line); + } + while (!last_line); + + return content_area; +} + +// Generates the text cursor. +void WidgetTextInput::GenerateCursor() +{ + // Generates the cursor. + cursor_geometry.Release(); + + Vector< Vertex >& vertices = cursor_geometry.GetVertices(); + vertices.resize(4); + + Vector< int >& indices = cursor_geometry.GetIndices(); + indices.resize(6); + + cursor_size.x = ElementUtilities::GetDensityIndependentPixelRatio(text_element); + cursor_size.y = text_element->GetLineHeight() + 2.0f; + GeometryUtilities::GenerateQuad(&vertices[0], &indices[0], Vector2f(0, 0), cursor_size, parent->GetProperty< Colourb >("color")); +} + +void WidgetTextInput::UpdateCursorPosition() +{ + if (text_element->GetFontFaceHandle() == 0) + return; + + cursor_position.x = (float) ElementUtilities::GetStringWidth(text_element, lines[cursor_line_index].content.substr(0, cursor_character_index)); + cursor_position.y = -1.f + (float)cursor_line_index * text_element->GetLineHeight(); +} + +// Expand the text selection to the position of the cursor. +void WidgetTextInput::UpdateSelection(bool selecting) +{ + if (!selecting) + { + selection_anchor_index = edit_index; + ClearSelection(); + } + else + { + int new_begin_index; + int new_end_index; + + if (edit_index > selection_anchor_index) + { + new_begin_index = selection_anchor_index; + new_end_index = edit_index; + } + else + { + new_begin_index = edit_index; + new_end_index = selection_anchor_index; + } + + if (new_begin_index != selection_begin_index || + new_end_index - new_begin_index != selection_length) + { + selection_begin_index = new_begin_index; + selection_length = new_end_index - new_begin_index; + + FormatText(); + } + } +} + +// Removes the selection of text. +void WidgetTextInput::ClearSelection() +{ + if (selection_length > 0) + { + selection_length = 0; + FormatElement(); + } +} + +// Deletes all selected text and removes the selection. +void WidgetTextInput::DeleteSelection() +{ + if (selection_length > 0) + { + const String& value = GetElement()->GetAttribute< String >("value", ""); + + String new_value = value.substr(0, selection_begin_index) + value.substr(std::min(size_t(selection_begin_index + selection_length), size_t(value.size()))); + GetElement()->SetAttribute("value", new_value); + + // Move the cursor to the beginning of the old selection. + absolute_cursor_index = selection_begin_index; + UpdateRelativeCursor(); + + // Erase our record of the selection. + ClearSelection(); + } +} + +// Split one line of text into three parts, based on the current selection. +void WidgetTextInput::GetLineSelection(String& pre_selection, String& selection, String& post_selection, const String& line, int line_begin) +{ + // Check if we have any selection at all, and if so if the selection is on this line. + if (selection_length <= 0 || + selection_begin_index + selection_length < line_begin || + selection_begin_index > line_begin + (int) line.size()) + { + pre_selection = line; + return; + } + + int line_length = (int)line.size(); + using namespace Math; + + // Split the line up into its three parts, depending on the size and placement of the selection. + pre_selection = line.substr(0, Max(0, selection_begin_index - line_begin)); + selection = line.substr(Clamp(selection_begin_index - line_begin, 0, line_length), Max(0, selection_length + Min(0, selection_begin_index - line_begin))); + post_selection = line.substr(Clamp(selection_begin_index + selection_length - line_begin, 0, line_length)); +} + +void WidgetTextInput::SetKeyboardActive(bool active) +{ + SystemInterface* system = GetSystemInterface(); + if (system) { + if (active) + { + system->ActivateKeyboard(); + } else + { + system->DeactivateKeyboard(); + } + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInput.h b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInput.h new file mode 100644 index 000000000..a70e338d7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInput.h @@ -0,0 +1,244 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUT_H +#define RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUT_H + +#include "../../../Include/RmlUi/Core/EventListener.h" +#include "../../../Include/RmlUi/Core/Geometry.h" +#include "../../../Include/RmlUi/Core/Vertex.h" + +namespace Rml { + +class ElementText; +class ElementFormControl; + +/** + An abstract widget for editing and navigating around a text field. + + @author Peter Curry + */ + +class WidgetTextInput : public EventListener +{ +public: + WidgetTextInput(ElementFormControl* parent); + virtual ~WidgetTextInput(); + + /// Sets the value of the text field. + /// @param[in] value The new value to set on the text field. + virtual void SetValue(const String& value); + + /// Sets the maximum length (in characters) of this text field. + /// @param[in] max_length The new maximum length of the text field. A number lower than zero will mean infinite characters. + void SetMaxLength(int max_length); + /// Returns the maximum length (in characters) of this text field. + /// @return The maximum number of characters allowed in this text field. + int GetMaxLength() const; + /// Returns the current length (in characters) of this text field. + int GetLength() const; + + /// Update the colours of the selected text. + void UpdateSelectionColours(); + + /// Updates the cursor, if necessary. + void OnUpdate(); + /// Renders the cursor, if it is visible. + void OnRender(); + /// Formats the widget's internal content. + void OnLayout(); + /// Called when the parent element's size changes. + void OnResize(); + + /// Returns the input element's underlying text element. + ElementText* GetTextElement(); + /// Returns the input element's maximum allowed text dimensions. + const Vector2f& GetTextDimensions() const; + +protected: + enum class CursorMovement { Begin = -4, BeginLine = -3, PreviousWord = -2, Left = -1, Right = 1, NextWord = 2, EndLine = 3, End = 4 }; + + /// Processes the "keydown" and "textinput" event to write to the input field, and the "focus" and + /// "blur" to set the state of the cursor. + void ProcessEvent(Event& event) override; + + /// Adds new characters to the string at the cursor position. + /// @param[in] string The characters to add. + /// @return True if at least one character was successfully added, false otherwise. + bool AddCharacters(String string); + /// Deletes characters from the string. + /// @param[in] direction Movement of cursor for deletion. + /// @return True if a character was deleted, false otherwise. + bool DeleteCharacters(CursorMovement direction); + /// Returns true if the given character is permitted in the input field, false if not. + /// @param[in] character The character to validate. + /// @return True if the character is allowed, false if not. + virtual bool IsCharacterValid(char character) = 0; + /// Called when the user pressed enter. + virtual void LineBreak() = 0; + + /// Returns the absolute index of the cursor. + int GetCursorIndex() const; + + /// Gets the parent element containing the widget. + Element* GetElement() const; + + /// Dispatches a change event to the widget's element. + void DispatchChangeEvent(bool linebreak = false); + +private: + + /// Moves the cursor along the current line. + /// @param[in] movement Cursor movement operation. + /// @param[in] select True if the movement will also move the selection cursor, false if not. + void MoveCursorHorizontal(CursorMovement movement, bool select); + /// Moves the cursor up and down the text field. + /// @param[in] x How far to move the cursor. + /// @param[in] select True if the movement will also move the selection cursor, false if not. + void MoveCursorVertical(int distance, bool select); + // Move the cursor to utf-8 boundaries, in case it was moved into the middle of a multibyte character. + /// @param[in] forward True to seek forward, else back. + void MoveCursorToCharacterBoundaries(bool forward); + // Expands the cursor, selecting the current word or nearby whitespace. + void ExpandSelection(); + + /// Updates the absolute cursor index from the relative cursor indices. + void UpdateAbsoluteCursor(); + /// Updates the relative cursor indices from the absolute cursor index. + void UpdateRelativeCursor(); + + /// Calculates the line index under a specific vertical position. + /// @param[in] position The position to query. + /// @return The index of the line under the mouse cursor. + int CalculateLineIndex(float position); + /// Calculates the character index along a line under a specific horizontal position. + /// @param[in] line_index The line to query. + /// @param[in] position The position to query. + /// @param[out] on_right_side True if position is on the right side of the returned character, else left side. + /// @return The index of the character under the mouse cursor. + int CalculateCharacterIndex(int line_index, float position); + + /// Shows or hides the cursor. + /// @param[in] show True to show the cursor, false to hide it. + /// @param[in] move_to_cursor True to force the cursor to be visible, false to not scroll the widget. + void ShowCursor(bool show, bool move_to_cursor = true); + + /// Formats the element, laying out the text and inserting scrollbars as appropriate. + void FormatElement(); + /// Formats the input element's text field. + /// @return The content area of the element. + Vector2f FormatText(); + + /// Generates the text cursor. + void GenerateCursor(); + /// Updates the position to render the cursor. + void UpdateCursorPosition(); + + /// Expand or shrink the text selection to the position of the cursor. + /// @param[in] selecting True if the new position of the cursor should expand / contract the selection area, false if it should only set the anchor for future selections. + void UpdateSelection(bool selecting); + /// Removes the selection of text. + void ClearSelection(); + /// Deletes all selected text and removes the selection. + void DeleteSelection(); + /// Copies the selection (if any) to the clipboard. + void CopySelection(); + + /// Split one line of text into three parts, based on the current selection. + /// @param[out] pre_selection The section of unselected text before any selected text on the line. + /// @param[out] selection The section of selected text on the line. + /// @param[out] post_selection The section of unselected text after any selected text on the line. If there is no selection on the line, then this will be empty. + /// @param[in] line The text making up the line. + /// @param[in] line_begin The absolute index at the beginning of the line. + void GetLineSelection(String& pre_selection, String& selection, String& post_selection, const String& line, int line_begin); + + struct Line + { + // The contents of the line (including the trailing endline, if that terminated the line). + String content; + // The length of the editable characters on the line (excluding any trailing endline). + int content_length; + + // The number of extra characters at the end of the content that are not present in the actual value; in the + // case of a soft return, this may be negative. + int extra_characters; + }; + + ElementFormControl* parent; + + ElementText* text_element; + ElementText* selected_text_element; + Vector2f internal_dimensions; + Vector2f scroll_offset; + + typedef Vector< Line > LineList; + LineList lines; + + // Length in number of characters. + int max_length; + + // Indices in bytes: Should always be moved along UTF-8 start bytes. + int edit_index; + + int absolute_cursor_index; + int cursor_line_index; + int cursor_character_index; + + bool cursor_on_right_side_of_character; + bool cancel_next_drag; + + // Selection. The start and end indices of the selection are in absolute coordinates. + Element* selection_element; + int selection_anchor_index; + int selection_begin_index; + int selection_length; + + // The colour of the background of selected text. + Colourb selection_colour; + // The selection background. + Geometry selection_geometry; + + // Cursor visibility and timings. + float cursor_timer; + bool cursor_visible; + bool keyboard_showed; + /// Activate or deactivate keyboard (for touchscreen devices) + /// @param[in] active True if need activate keyboard, false if need deactivate. + void SetKeyboardActive(bool active); + + double last_update_time; + + // The cursor geometry. + float ideal_cursor_position; + Vector2f cursor_position; + Vector2f cursor_size; + Geometry cursor_geometry; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputMultiLine.cpp b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputMultiLine.cpp new file mode 100644 index 000000000..ca1c583be --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputMultiLine.cpp @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "WidgetTextInputMultiLine.h" +#include "../../../Include/RmlUi/Core/Dictionary.h" +#include "../../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +WidgetTextInputMultiLine::WidgetTextInputMultiLine(ElementFormControl* parent) : WidgetTextInput(parent) +{ +} + +WidgetTextInputMultiLine::~WidgetTextInputMultiLine() +{ +} + +// Returns true if the given character is permitted in the input field, false if not. +bool WidgetTextInputMultiLine::IsCharacterValid(char character) +{ + return character != '\t'; +} + +// Called when the user pressed enter. +void WidgetTextInputMultiLine::LineBreak() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputMultiLine.h b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputMultiLine.h new file mode 100644 index 000000000..c5c9069b2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputMultiLine.h @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUTMULTILINE_H +#define RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUTMULTILINE_H + +#include "WidgetTextInput.h" + +namespace Rml { + +/** + A specialisation of the text input widget for multi-line text fields. + + @author Peter Curry + */ + +class WidgetTextInputMultiLine : public WidgetTextInput +{ +public: + WidgetTextInputMultiLine(ElementFormControl* parent); + virtual ~WidgetTextInputMultiLine(); + +protected: + /// Returns true if the given character is permitted in the input field, false if not. + /// @param[in] character The character to validate. + /// @return True if the character is allowed, false if not. + bool IsCharacterValid(char character) override; + /// Called when the user pressed enter. + void LineBreak() override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLine.cpp b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLine.cpp new file mode 100644 index 000000000..a0f67ee2c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLine.cpp @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Dictionary.h" +#include "../../../Include/RmlUi/Core/ElementText.h" +#include "WidgetTextInputSingleLine.h" + +namespace Rml { + +WidgetTextInputSingleLine::WidgetTextInputSingleLine(ElementFormControl* parent) : WidgetTextInput(parent) +{ +} + +WidgetTextInputSingleLine::~WidgetTextInputSingleLine() +{ +} + +// Sets the value of the text field. The value will be stripped of end-lines. +void WidgetTextInputSingleLine::SetValue(const String& value) +{ + String new_value = value; + SanitiseValue(new_value); + + WidgetTextInput::SetValue(new_value); +} + +// Returns true if the given character is permitted in the input field, false if not. +bool WidgetTextInputSingleLine::IsCharacterValid(char character) +{ + return character != '\t' && character != '\n' && character != '\r'; +} + +// Called when the user pressed enter. +void WidgetTextInputSingleLine::LineBreak() +{ + DispatchChangeEvent(true); +} + +// Strips all \n and \r characters from the string. +void WidgetTextInputSingleLine::SanitiseValue(String& value) +{ + String new_value; + for (String::size_type i = 0; i < value.size(); ++i) + { + switch (value[i]) + { + case '\n': + case '\r': + case '\t': + break; + + default: + new_value += value[i]; + } + } + + value = new_value; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLine.h b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLine.h new file mode 100644 index 000000000..6b74c0668 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLine.h @@ -0,0 +1,65 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUTSINGLELINE_H +#define RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUTSINGLELINE_H + +#include "WidgetTextInput.h" + +namespace Rml { + +/** + A specialisation of the text input widget for single-line input fields. + + @author Peter Curry + */ + +class WidgetTextInputSingleLine : public WidgetTextInput +{ +public: + WidgetTextInputSingleLine(ElementFormControl* parent); + virtual ~WidgetTextInputSingleLine(); + + /// Sets the value of the text field. The value will be stripped of end-lines. + /// @param value[in] The new value to set on the text field. + void SetValue(const String& value) override; + +protected: + /// Returns true if the given character is permitted in the input field, false if not. + /// @param[in] character The character to validate. + /// @return True if the character is allowed, false if not. + bool IsCharacterValid(char character) override; + /// Called when the user pressed enter. + void LineBreak() override; + + /// Strips all \n and \r characters from the string. + void SanitiseValue(String& value); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLinePassword.cpp b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLinePassword.cpp new file mode 100644 index 000000000..727a33db0 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLinePassword.cpp @@ -0,0 +1,50 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/ElementText.h" +#include "WidgetTextInputSingleLinePassword.h" + +namespace Rml { + +WidgetTextInputSingleLinePassword::WidgetTextInputSingleLinePassword(ElementFormControl* parent) : WidgetTextInputSingleLine(parent) +{ +} + +WidgetTextInputSingleLinePassword::~WidgetTextInputSingleLinePassword() +{ +} + +// Sets the value of the password field. +void WidgetTextInputSingleLinePassword::SetValue(const String& value) +{ + String sanitised_value(value); + SanitiseValue(sanitised_value); + WidgetTextInput::SetValue(String(sanitised_value.size(), '*')); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLinePassword.h b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLinePassword.h new file mode 100644 index 000000000..13c050754 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/WidgetTextInputSingleLinePassword.h @@ -0,0 +1,52 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUTSINGLELINEPASSWORD_H +#define RMLUI_CORE_ELEMENTS_WIDGETTEXTINPUTSINGLELINEPASSWORD_H + +#include "WidgetTextInputSingleLine.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class WidgetTextInputSingleLinePassword : public WidgetTextInputSingleLine +{ +public: + WidgetTextInputSingleLinePassword(ElementFormControl* parent); + virtual ~WidgetTextInputSingleLinePassword(); + + /// Sets the value of the password field. + /// @param value[in] The new password to set on the field. + void SetValue(const String& value) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerDataGrid.cpp b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerDataGrid.cpp new file mode 100644 index 000000000..f05f2bc8e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerDataGrid.cpp @@ -0,0 +1,115 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerDataGrid.h" +#include "../../../Include/RmlUi/Core/StreamMemory.h" +#include "../../../Include/RmlUi/Core/Log.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/XMLParser.h" +#include "../../../Include/RmlUi/Core/Elements/ElementDataGrid.h" + +namespace Rml { + +XMLNodeHandlerDataGrid::XMLNodeHandlerDataGrid() +{ +} + +XMLNodeHandlerDataGrid::~XMLNodeHandlerDataGrid() +{ +} + +Element* XMLNodeHandlerDataGrid::ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) +{ + Element* result = nullptr; + Element* parent = parser->GetParseFrame()->element; + + RMLUI_ASSERT(name == "datagrid" || name == "col"); + + if (name == "datagrid") + { + // Attempt to instance the grid. + ElementPtr element = Factory::InstanceElement(parent, name, name, attributes); + ElementDataGrid* grid = rmlui_dynamic_cast< ElementDataGrid* >(element.get()); + if (!grid) + { + element.reset(); + Log::Message(Log::LT_ERROR, "Instancer failed to create data grid for tag %s.", name.c_str()); + return nullptr; + } + + // Set the data source and table on the data grid. + String data_source = Get(attributes, "source", ""); + grid->SetDataSource(data_source); + + result = parent->AppendChild(std::move(element)); + + // Switch to this handler for all columns. + parser->PushHandler("datagrid"); + } + else if (name == "col") + { + // Make a new node handler to handle the header elements. + ElementPtr element = Factory::InstanceElement(parent, "datagridcolumn", "datagridcolumn", attributes); + if (!element) + return nullptr; + + result = element.get(); + + ElementDataGrid* grid = rmlui_dynamic_cast< ElementDataGrid* >(parent); + if (grid) + grid->AddColumn(Get(attributes, "fields", ""), Get(attributes, "formatter", ""), Get(attributes, "width", 0.0f), std::move(element)); + + // Switch to element handler for all children. + parser->PushDefaultHandler(); + } + else + { + RMLUI_ERROR; + } + + return result; +} + +bool XMLNodeHandlerDataGrid::ElementEnd(XMLParser* RMLUI_UNUSED_PARAMETER(parser), const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(parser); + RMLUI_UNUSED(name); + + return true; +} + +bool XMLNodeHandlerDataGrid::ElementData(XMLParser* parser, const String& data, XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(type); + Element* parent = parser->GetParseFrame()->element; + + // Parse the text into the parent element. + return Factory::InstanceElementText(parent, data); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerDataGrid.h b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerDataGrid.h new file mode 100644 index 000000000..82de3dca4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerDataGrid.h @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_XMLNODEHANDLERDATAGRID_H +#define RMLUI_CORE_ELEMENTS_XMLNODEHANDLERDATAGRID_H + +#include "../../../Include/RmlUi/Core/Types.h" +#include "../../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + Node handler for the construction of a data grid. + + @author Robert Curry + */ + +class XMLNodeHandlerDataGrid : public XMLNodeHandler +{ +public: + XMLNodeHandlerDataGrid(); + virtual ~XMLNodeHandlerDataGrid(); + + /// Called when a new element is opened. + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed. + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data. + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTabSet.cpp b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTabSet.cpp new file mode 100644 index 000000000..1c67d391e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTabSet.cpp @@ -0,0 +1,144 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerTabSet.h" +#include "../../../Include/RmlUi/Core/Log.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/XMLParser.h" +#include "../../../Include/RmlUi/Core/Elements/ElementTabSet.h" + +namespace Rml { + +XMLNodeHandlerTabSet::XMLNodeHandlerTabSet() +{ +} + +XMLNodeHandlerTabSet::~XMLNodeHandlerTabSet() +{ +} + +Element* XMLNodeHandlerTabSet::ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) +{ + RMLUI_ASSERT(name == "tabset" || + name == "tabs" || + name == "tab" || + name == "panels" || + name == "panel"); + + if (name == "tabset") + { + // Call this node handler for all children + parser->PushHandler("tabset"); + + // Attempt to instance the tabset + ElementPtr element = Factory::InstanceElement(parser->GetParseFrame()->element, name, name, attributes); + ElementTabSet* tabset = rmlui_dynamic_cast< ElementTabSet* >(element.get()); + if (!tabset) + { + Log::Message(Log::LT_ERROR, "Instancer failed to create element for tag %s.", name.c_str()); + return nullptr; + } + + // Add the TabSet into the document + Element* result = parser->GetParseFrame()->element->AppendChild(std::move(element)); + + return result; + } + else if (name == "tab") + { + // Call default element handler for all children. + parser->PushDefaultHandler(); + + ElementPtr tab_element = Factory::InstanceElement(parser->GetParseFrame()->element, "*", "tab", attributes); + Element* result = nullptr; + + ElementTabSet* tabset = rmlui_dynamic_cast< ElementTabSet* >(parser->GetParseFrame()->element); + if (tabset) + { + result = tab_element.get(); + tabset->SetTab(-1, std::move(tab_element)); + } + + return result; + + } + else if (name == "panel") + { + // Call default element handler for all children. + parser->PushDefaultHandler(); + + ElementPtr panel_element = Factory::InstanceElement(parser->GetParseFrame()->element, "*", "panel", attributes); + Element* result = nullptr; + + ElementTabSet* tabset = rmlui_dynamic_cast< ElementTabSet* >(parser->GetParseFrame()->element); + if (tabset) + { + result = panel_element.get(); + tabset->SetPanel(-1, std::move(panel_element)); + } + + return result; + } + else if (name == "tabs" || name == "panels") + { + // Use the element handler to add the tabs and panels elements to the the tabset (this allows users to + // style them nicely), but don't return the new element, as we still want the tabset to be the top of the + // parser's node stack. + + Element* parent = parser->GetParseFrame()->element; + + ElementPtr element = Factory::InstanceElement(parent, name, name, attributes); + if (!element) + { + Log::Message(Log::LT_ERROR, "Instancer failed to create element for tag %s.", name.c_str()); + return nullptr; + } + + parent->AppendChild(std::move(element)); + + return nullptr; + } + + return nullptr; +} + +bool XMLNodeHandlerTabSet::ElementEnd(XMLParser* RMLUI_UNUSED_PARAMETER(parser), const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(parser); + RMLUI_UNUSED(name); + + return true; +} + +bool XMLNodeHandlerTabSet::ElementData(XMLParser* parser, const String& data, XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(type); + return Factory::InstanceElementText(parser->GetParseFrame()->element, data); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTabSet.h b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTabSet.h new file mode 100644 index 000000000..dd6c7a324 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTabSet.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_XMLNODEHANDLERTABSET_H +#define RMLUI_CORE_ELEMENTS_XMLNODEHANDLERTABSET_H + +#include "../../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + XML node handler for processing the tabset tags. + + @author Lloyd Weehuizen + */ + +class XMLNodeHandlerTabSet : public XMLNodeHandler +{ +public: + XMLNodeHandlerTabSet(); + virtual ~XMLNodeHandlerTabSet(); + + /// Called when a new element start is opened + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTextArea.cpp b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTextArea.cpp new file mode 100644 index 000000000..45cd7a7a5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTextArea.cpp @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerTextArea.h" +#include "../../../Include/RmlUi/Core/Elements/ElementFormControlTextArea.h" +#include "../../../Include/RmlUi/Core/Core.h" +#include "../../../Include/RmlUi/Core/Factory.h" +#include "../../../Include/RmlUi/Core/SystemInterface.h" +#include "../../../Include/RmlUi/Core/XMLParser.h" + +namespace Rml { + +XMLNodeHandlerTextArea::XMLNodeHandlerTextArea() +{ +} + +XMLNodeHandlerTextArea::~XMLNodeHandlerTextArea() +{ +} + +Element* XMLNodeHandlerTextArea::ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) +{ + ElementFormControlTextArea* text_area = rmlui_dynamic_cast< ElementFormControlTextArea* >(parser->GetParseFrame()->element); + if (!text_area) + { + ElementPtr new_element = Factory::InstanceElement(parser->GetParseFrame()->element, name, name, attributes); + if (!new_element) + return nullptr; + + Element* result = parser->GetParseFrame()->element->AppendChild(std::move(new_element)); + + return result; + } + + return nullptr; +} + +bool XMLNodeHandlerTextArea::ElementEnd(XMLParser* RMLUI_UNUSED_PARAMETER(parser), const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(parser); + RMLUI_UNUSED(name); + + return true; +} + +bool XMLNodeHandlerTextArea::ElementData(XMLParser* parser, const String& data, XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(type); + + ElementFormControlTextArea* text_area = rmlui_dynamic_cast< ElementFormControlTextArea* >(parser->GetParseFrame()->element); + if (text_area != nullptr) + { + // Do any necessary translation. + String translated_data; + GetSystemInterface()->TranslateString(translated_data, data); + + text_area->SetValue(translated_data); + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTextArea.h b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTextArea.h new file mode 100644 index 000000000..daaedb395 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Elements/XMLNodeHandlerTextArea.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_ELEMENTS_XMLNODEHANDLERTEXTAREA_H +#define RMLUI_CORE_ELEMENTS_XMLNODEHANDLERTEXTAREA_H + +#include "../../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + Node handler that processes the contents of the textarea tag. + + @author Peter Curry + */ + +class XMLNodeHandlerTextArea : public XMLNodeHandler +{ +public: + XMLNodeHandlerTextArea(); + virtual ~XMLNodeHandlerTextArea(); + + /// Called when a new element is opened. + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed. + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data. + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Event.cpp b/thirdparty/RmlUi/Source/Core/Event.cpp new file mode 100644 index 000000000..610e53de3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Event.cpp @@ -0,0 +1,189 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/EventInstancer.h" +#include "../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +Event::Event() +{ +} + +Event::Event(Element* _target_element, EventId id, const String& type, const Dictionary& _parameters, bool interruptible) + : parameters(_parameters), target_element(_target_element), type(type), id(id), interruptible(interruptible) +{ + const Variant* mouse_x = GetIf(parameters, "mouse_x"); + const Variant* mouse_y = GetIf(parameters, "mouse_y"); + if (mouse_x && mouse_y) + { + has_mouse_position = true; + mouse_x->GetInto(mouse_screen_position.x); + mouse_y->GetInto(mouse_screen_position.y); + } +} + +Event::~Event() +{ +} + +void Event::SetCurrentElement(Element* element) +{ + current_element = element; + if(has_mouse_position) + { + ProjectMouse(element); + } +} + +Element* Event::GetCurrentElement() const +{ + return current_element; +} + +Element* Event::GetTargetElement() const +{ + return target_element; +} + +const String& Event::GetType() const +{ + return type; +} + +bool Event::operator==(const String& _type) const +{ + return type == _type; +} + +bool Event::operator==(EventId _id) const +{ + return id == _id; +} + +void Event::SetPhase(EventPhase _phase) +{ + phase = _phase; +} + +EventPhase Event::GetPhase() const +{ + return phase; +} + +bool Event::IsPropagating() const +{ + return !interrupted; +} + +void Event::StopPropagation() +{ + if (interruptible) + { + interrupted = true; + } +} + +bool Event::IsImmediatePropagating() const +{ + return !interrupted_immediate; +} + +bool Event::IsInterruptible() const +{ + return interruptible; +} + +void Event::StopImmediatePropagation() +{ + if(interruptible) + { + interrupted_immediate = true; + interrupted = true; + } +} + +const Dictionary& Event::GetParameters() const +{ + return parameters; +} + +const Vector2f& Event::GetUnprojectedMouseScreenPos() const +{ + return mouse_screen_position; +} + +void Event::Release() +{ + if (instancer) + instancer->ReleaseEvent(this); + else + Log::Message(Log::LT_WARNING, "Leak detected: Event %s not instanced via RmlUi Factory. Unable to release.", type.c_str()); +} + +EventId Event::GetId() const +{ + return id; +} + +void Event::ProjectMouse(Element* element) +{ + if(!element) + { + parameters["mouse_x"] = mouse_screen_position.x; + parameters["mouse_y"] = mouse_screen_position.y; + return; + } + + // Only need to project mouse position if element has a transform state + if (element->GetTransformState()) + { + // Project mouse from parent (previous 'mouse_x/y' property) to child (element) + Variant *mouse_x = GetIf(parameters, "mouse_x"); + Variant *mouse_y = GetIf(parameters, "mouse_y"); + if (!mouse_x || !mouse_y) + { + RMLUI_ERROR; + return; + } + + Vector2f projected_position = mouse_screen_position; + + // Not sure how best to handle the case where the projection fails. + if (element->Project(projected_position)) + { + *mouse_x = projected_position.x; + *mouse_y = projected_position.y; + } + else + StopPropagation(); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/EventDispatcher.cpp b/thirdparty/RmlUi/Source/Core/EventDispatcher.cpp new file mode 100644 index 000000000..a3df6bdbf --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventDispatcher.cpp @@ -0,0 +1,295 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "EventDispatcher.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/EventListener.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "EventSpecification.h" +#include +#include + +namespace Rml { + +bool operator==(EventListenerEntry a, EventListenerEntry b) { return a.id == b.id && a.in_capture_phase == b.in_capture_phase && a.listener == b.listener; } +bool operator!=(EventListenerEntry a, EventListenerEntry b) { return !(a == b); } + +struct CompareId { + bool operator()(EventListenerEntry a, EventListenerEntry b) const { return a.id < b.id; } +}; +struct CompareIdPhase { + bool operator()(EventListenerEntry a, EventListenerEntry b) const { return std::tie(a.id, a.in_capture_phase) < std::tie(b.id, b.in_capture_phase); } +}; + + + +EventDispatcher::EventDispatcher(Element* _element) +{ + element = _element; +} + +EventDispatcher::~EventDispatcher() +{ + // Detach from all event dispatchers + for (const auto& event : listeners) + event.listener->OnDetach(element); +} + +void EventDispatcher::AttachEvent(EventId id, EventListener* listener, bool in_capture_phase) +{ + EventListenerEntry entry(id, listener, in_capture_phase); + + // The entries are sorted by (id,phase). Find the bounds of this sort, then find the entry. + auto range = std::equal_range(listeners.begin(), listeners.end(), entry, CompareIdPhase()); + auto it = std::find(range.first, range.second, entry); + + if(it == range.second) + { + // No existing entry found, add it to the end of the (id, phase) range + listeners.emplace(it, entry); + listener->OnAttach(element); + } +} + + +void EventDispatcher::DetachEvent(EventId id, EventListener* listener, bool in_capture_phase) +{ + EventListenerEntry entry(id, listener, in_capture_phase); + + // The entries are sorted by (id,phase). Find the bounds of this sort, then find the entry. + // We could also just do a linear search over all the entries, which might be faster for low number of entries. + auto range = std::equal_range(listeners.begin(), listeners.end(), entry, CompareIdPhase()); + auto it = std::find(range.first, range.second, entry); + + if (it != range.second) + { + // We found our listener, remove it + listeners.erase(it); + listener->OnDetach(element); + } +} + +// Detaches all events from this dispatcher and all child dispatchers. +void EventDispatcher::DetachAllEvents() +{ + for (const auto& event : listeners) + event.listener->OnDetach(element); + + listeners.clear(); + + for (int i = 0; i < element->GetNumChildren(true); ++i) + element->GetChild(i)->GetEventDispatcher()->DetachAllEvents(); +} + +/* + CollectedListener + + When dispatching an event we collect all possible event listeners to execute. + They are stored in observer pointers, so that we can safely check if they have been destroyed since the previous listener execution. +*/ +struct CollectedListener { + + CollectedListener(Element* _element, EventListener* _listener, int dom_distance_from_target, bool in_capture_phase) : element(_element->GetObserverPtr()), listener(_listener->GetObserverPtr()) + { + sort = dom_distance_from_target * (in_capture_phase ? -1 : 1); + } + + // The sort value is determined by the distance of the element to the target element in the DOM. + // Capture phase is given negative values. + int sort = 0; + + ObserverPtr element; + ObserverPtr listener; + + // Default actions are returned by EventPhase::None. + EventPhase GetPhase() const { return sort < 0 ? EventPhase::Capture : (sort == 0 ? EventPhase::Target : EventPhase::Bubble); } + + bool operator<(const CollectedListener& other) const { + return sort < other.sort; + } +}; + + +bool EventDispatcher::DispatchEvent(Element* target_element, const EventId id, const String& type, const Dictionary& parameters, const bool interruptible, const bool bubbles, const DefaultActionPhase default_action_phase) +{ + RMLUI_ASSERTMSG(!((int)default_action_phase & (int)EventPhase::Capture), "We assume here that the default action phases cannot include capture phase."); + + Vector listeners; + Vector> default_action_elements; + + const EventPhase phases_to_execute = EventPhase((int)EventPhase::Capture | (int)EventPhase::Target | (bubbles ? (int)EventPhase::Bubble : 0)); + + // Walk the DOM tree from target to root, collecting all possible listeners and elements with default actions in the process. + int dom_distance_from_target = 0; + Element* walk_element = target_element; + while (walk_element) + { + EventDispatcher* dispatcher = walk_element->GetEventDispatcher(); + dispatcher->CollectListeners(dom_distance_from_target, id, phases_to_execute, listeners); + + if(dom_distance_from_target == 0) + { + if ((int)default_action_phase & (int)EventPhase::Target) + default_action_elements.push_back(walk_element->GetObserverPtr()); + } + else if((int)default_action_phase & (int)EventPhase::Bubble) + { + default_action_elements.push_back(walk_element->GetObserverPtr()); + } + + walk_element = walk_element->GetParentNode(); + dom_distance_from_target += 1; + } + + if (listeners.empty() && default_action_elements.empty()) + return true; + + // Use stable_sort so that the order of the listeners in a given element is maintained. + std::stable_sort(listeners.begin(), listeners.end()); + + // Instance event + EventPtr event = Factory::InstanceEvent(target_element, id, type, parameters, interruptible); + if (!event) + return false; + + int previous_sort_value = INT_MAX; + + // Process the event in each listener. + for (const auto& listener_desc : listeners) + { + Element* element = listener_desc.element.get(); + EventListener* listener = listener_desc.listener.get(); + + if (listener_desc.sort != previous_sort_value) + { + // New sort values represent a new level in the DOM, thus, set the new element and possibly new phase. + if (!event->IsPropagating()) + break; + event->SetCurrentElement(element); + event->SetPhase(listener_desc.GetPhase()); + previous_sort_value = listener_desc.sort; + } + + // We only submit the event if both the current element and listener are still alive. + if (element && listener) + { + listener->ProcessEvent(*event); + } + + if (!event->IsImmediatePropagating()) + break; + } + + // Process the default actions. + for (auto& element_ptr : default_action_elements) + { + if (!event->IsPropagating()) + break; + + if (Element* element = element_ptr.get()) + { + event->SetCurrentElement(element); + event->SetPhase(element == target_element ? EventPhase::Target : EventPhase::Bubble); + element->ProcessDefaultAction(*event); + } + } + + bool propagating = event->IsPropagating(); + + return propagating; +} + + +void EventDispatcher::CollectListeners(int dom_distance_from_target, const EventId event_id, const EventPhase event_executes_in_phases, Vector& collect_listeners) +{ + // Find all the entries with a matching id, given that listeners are sorted by id first. + Listeners::iterator begin, end; + std::tie(begin, end) = std::equal_range(listeners.begin(), listeners.end(), EventListenerEntry(event_id, nullptr, false), CompareId()); + + const bool in_target_phase = (dom_distance_from_target == 0); + + if (in_target_phase) + { + // Listeners always attach to target phase, but make sure the event can actually execute in target phase. + if ((int)event_executes_in_phases & (int)EventPhase::Target) + { + for (auto it = begin; it != end; ++it) + collect_listeners.emplace_back(element, it->listener, dom_distance_from_target, false); + } + } + else + { + // Iterate through all the listeners and collect those matching the event execution phase. + for (auto it = begin; it != end; ++it) + { + // Listeners will either attach to capture or bubble phase, make sure the event can execute in the same phase. + const EventPhase listener_executes_in_phase = (it->in_capture_phase ? EventPhase::Capture : EventPhase::Bubble); + if ((int)event_executes_in_phases & (int)listener_executes_in_phase) + collect_listeners.emplace_back(element, it->listener, dom_distance_from_target, it->in_capture_phase); + } + } +} + + +String EventDispatcher::ToString() const +{ + String result; + + if (listeners.empty()) + return result; + + auto add_to_result = [&result](EventId id, int count) { + const EventSpecification& specification = EventSpecificationInterface::Get(id); + result += CreateString(specification.type.size() + 32, "%s (%d), ", specification.type.c_str(), count); + }; + + EventId previous_id = listeners[0].id; + int count = 0; + for (const auto& listener : listeners) + { + if (listener.id != previous_id) + { + add_to_result(previous_id, count); + previous_id = listener.id; + count = 0; + } + count++; + } + + if (count > 0) + add_to_result(previous_id, count); + + if (result.size() > 2) + result.resize(result.size() - 2); + + return result; +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/EventDispatcher.h b/thirdparty/RmlUi/Source/Core/EventDispatcher.h new file mode 100644 index 000000000..aa2d261fe --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventDispatcher.h @@ -0,0 +1,111 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTDISPATCHER_H +#define RMLUI_CORE_EVENTDISPATCHER_H + +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/Event.h" + +namespace Rml { + +class Element; +class EventListener; +struct CollectedListener; + +struct EventListenerEntry { + EventListenerEntry(EventId id, EventListener* listener, bool in_capture_phase) : id(id), in_capture_phase(in_capture_phase), listener(listener) {} + EventId id; + bool in_capture_phase; + EventListener* listener; +}; + + +/** + The Event Dispatcher manages a list of event listeners and triggers the events via EventHandlers + whenever requested. + + @author Lloyd Weehuizen +*/ + +class EventDispatcher +{ +public: + /// Constructor + /// @param element Element this dispatcher acts on + EventDispatcher(Element* element); + + /// Destructor + ~EventDispatcher(); + + /// Attaches a new listener to the specified event name + /// @param[in] type Type of the event to attach to + /// @param[in] event_listener The event listener to be notified when the event fires + /// @param[in] in_capture_phase Should the listener be notified in the capture phase + void AttachEvent(EventId id, EventListener* event_listener, bool in_capture_phase); + + /// Detaches a listener from the specified event name + /// @param[in] type Type of the event to attach to + /// @para[in]m event_listener The event listener to be notified when the event fires + /// @param[in] in_capture_phase Should the listener be notified in the capture phase + void DetachEvent(EventId id, EventListener* listener, bool in_capture_phase); + + /// Detaches all events from this dispatcher and all child dispatchers. + void DetachAllEvents(); + + /// Dispatches the specified event. + /// @param[in] target_element The element to target + /// @param[in] id The id of the event + /// @param[in] type The type of the event + /// @param[in] parameters The event parameters + /// @param[in] interruptible Can the event propagation be stopped + /// @param[in] bubbles True if the event should execute the bubble phase + /// @param[in] default_action_phase The phases to execute default actions in + /// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was. + static bool DispatchEvent(Element* target_element, EventId id, const String& type, const Dictionary& parameters, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase); + + /// Returns event types with number of listeners for debugging. + /// @return Summary of attached listeners. + String ToString() const; + +private: + Element* element; + + // Listeners are sorted first by (id, phase) and then by the order in which the listener was inserted. + // All listeners added are unique. + typedef Vector< EventListenerEntry > Listeners; + Listeners listeners; + + // Collect all the listeners from this dispatcher that are allowed to execute given the input arguments. + void CollectListeners(int dom_distance_from_target, EventId event_id, EventPhase phases_to_execute, Vector& collect_listeners); +}; + + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/EventInstancer.cpp b/thirdparty/RmlUi/Source/Core/EventInstancer.cpp new file mode 100644 index 000000000..2a97fedbb --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventInstancer.cpp @@ -0,0 +1,37 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/EventInstancer.h" + +namespace Rml { + +EventInstancer::~EventInstancer() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/EventInstancerDefault.cpp b/thirdparty/RmlUi/Source/Core/EventInstancerDefault.cpp new file mode 100644 index 000000000..dd3a345fd --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventInstancerDefault.cpp @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "EventInstancerDefault.h" +#include "../../Include/RmlUi/Core/Event.h" + +namespace Rml { + +EventInstancerDefault::EventInstancerDefault() +{ +} + +EventInstancerDefault::~EventInstancerDefault() +{ +} + +EventPtr EventInstancerDefault::InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible) +{ + return EventPtr(new Event(target, id, type, parameters, interruptible)); +} + +// Releases an event instanced by this instancer. +void EventInstancerDefault::ReleaseEvent(Event* event) +{ + delete event; +} + +void EventInstancerDefault::Release() +{ + delete this; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/EventInstancerDefault.h b/thirdparty/RmlUi/Source/Core/EventInstancerDefault.h new file mode 100644 index 000000000..4d6fd3284 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventInstancerDefault.h @@ -0,0 +1,65 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTINSTANCERDEFAULT_H +#define RMLUI_CORE_EVENTINSTANCERDEFAULT_H + +#include "../../Include/RmlUi/Core/EventInstancer.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +/** + Default instancer for instancing events. + + @author Lloyd Weehuizen + */ + +class EventInstancerDefault : public EventInstancer +{ +public: + EventInstancerDefault(); + virtual ~EventInstancerDefault(); + + /// Instance and event object + /// @param[in] target Target element of this event. + /// @param[in] name Name of this event. + /// @param[in] parameters Additional parameters for this event. + /// @param[in] interruptible If the event propagation can be stopped. + EventPtr InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible) override; + + /// Releases an event instanced by this instancer. + /// @param[in] event The event to release. + void ReleaseEvent(Event* event) override; + + /// Releases this event instancer. + void Release() override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/EventIterators.h b/thirdparty/RmlUi/Source/Core/EventIterators.h new file mode 100644 index 000000000..5c61a3775 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventIterators.h @@ -0,0 +1,82 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTITERATORS_H +#define RMLUI_CORE_EVENTITERATORS_H + +#include "../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +/** + An STL unary functor for dispatching an event to a Element. + + @author Peter Curry + */ + +class RmlEventFunctor +{ +public: + RmlEventFunctor(EventId id, const Dictionary& parameters) : id(id), parameters(¶meters) {} + + void operator()(Element* element) + { + element->DispatchEvent(id, *parameters); + } + +private: + EventId id; + const Dictionary* parameters; +}; + +/** + An STL unary functor for setting or clearing a pseudo-class on a Element. + + @author Pete + */ + +class PseudoClassFunctor +{ + public: + PseudoClassFunctor(const String& pseudo_class, bool set) : pseudo_class(pseudo_class) + { + this->set = set; + } + + void operator()(Element* element) + { + element->SetPseudoClass(pseudo_class, set); + } + + private: + String pseudo_class; + bool set; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/EventListenerInstancer.cpp b/thirdparty/RmlUi/Source/Core/EventListenerInstancer.cpp new file mode 100644 index 000000000..0875f3f9d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventListenerInstancer.cpp @@ -0,0 +1,37 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/EventListenerInstancer.h" + +namespace Rml { + +EventListenerInstancer::~EventListenerInstancer() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/EventSpecification.cpp b/thirdparty/RmlUi/Source/Core/EventSpecification.cpp new file mode 100644 index 000000000..f02ca8474 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventSpecification.cpp @@ -0,0 +1,182 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "EventSpecification.h" +#include "../../Include/RmlUi/Core/ID.h" + + +namespace Rml { + +// An EventId is an index into the specifications vector. +static Vector specifications = { { EventId::Invalid, "invalid", false, false, DefaultActionPhase::None } }; + +// Reverse lookup map from event type to id. +static UnorderedMap type_lookup; + + +namespace EventSpecificationInterface { + +void Initialize() +{ + // Must be specified in the same order as in EventId + specifications = { + // id type interruptible bubbles default_action + {EventId::Invalid , "invalid" , false , false , DefaultActionPhase::None}, + {EventId::Mousedown , "mousedown" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Mousescroll , "mousescroll" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Mouseover , "mouseover" , true , true , DefaultActionPhase::Target}, + {EventId::Mouseout , "mouseout" , true , true , DefaultActionPhase::Target}, + {EventId::Focus , "focus" , false , false , DefaultActionPhase::Target}, + {EventId::Blur , "blur" , false , false , DefaultActionPhase::Target}, + {EventId::Keydown , "keydown" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Keyup , "keyup" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Textinput , "textinput" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Mouseup , "mouseup" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Click , "click" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Dblclick , "dblclick" , true , true , DefaultActionPhase::TargetAndBubble}, + {EventId::Load , "load" , false , false , DefaultActionPhase::None}, + {EventId::Unload , "unload" , false , false , DefaultActionPhase::None}, + {EventId::Show , "show" , false , false , DefaultActionPhase::None}, + {EventId::Hide , "hide" , false , false , DefaultActionPhase::None}, + {EventId::Mousemove , "mousemove" , true , true , DefaultActionPhase::None}, + {EventId::Dragmove , "dragmove" , true , true , DefaultActionPhase::None}, + {EventId::Drag , "drag" , false , true , DefaultActionPhase::Target}, + {EventId::Dragstart , "dragstart" , false , true , DefaultActionPhase::Target}, + {EventId::Dragover , "dragover" , true , true , DefaultActionPhase::None}, + {EventId::Dragdrop , "dragdrop" , true , true , DefaultActionPhase::None}, + {EventId::Dragout , "dragout" , true , true , DefaultActionPhase::None}, + {EventId::Dragend , "dragend" , true , true , DefaultActionPhase::None}, + {EventId::Handledrag , "handledrag" , false , true , DefaultActionPhase::None}, + {EventId::Resize , "resize" , false , false , DefaultActionPhase::None}, + {EventId::Scroll , "scroll" , false , true , DefaultActionPhase::None}, + {EventId::Animationend , "animationend" , false , true , DefaultActionPhase::None}, + {EventId::Transitionend , "transitionend" , false , true , DefaultActionPhase::None}, + + {EventId::Change , "change" , false , true , DefaultActionPhase::None}, + {EventId::Submit , "submit" , true , true , DefaultActionPhase::None}, + {EventId::Tabchange , "tabchange" , false , true , DefaultActionPhase::None}, + {EventId::Columnadd , "columnadd" , false , true , DefaultActionPhase::None}, + {EventId::Rowadd , "rowadd" , false , true , DefaultActionPhase::None}, + {EventId::Rowchange , "rowchange" , false , true , DefaultActionPhase::None}, + {EventId::Rowremove , "rowremove" , false , true , DefaultActionPhase::None}, + {EventId::Rowupdate , "rowupdate" , false , true , DefaultActionPhase::None}, + }; + + type_lookup.clear(); + type_lookup.reserve(specifications.size()); + for (auto& specification : specifications) + type_lookup.emplace(specification.type, specification.id); + +#ifdef RMLUI_DEBUG + // Verify that all event ids are specified + RMLUI_ASSERT((int)specifications.size() == (int)EventId::NumDefinedIds); + + for (int i = 0; i < (int)specifications.size(); i++) + { + // Verify correct order + RMLUI_ASSERT(i == (int)specifications[i].id); + } +#endif +} + +static EventSpecification& GetMutable(EventId id) +{ + size_t i = static_cast(id); + if (i < specifications.size()) + return specifications[i]; + return specifications[0]; +} + +// Get event specification for the given type. +// If not found: Inserts a new entry with given values. +static EventSpecification& GetOrInsert(const String& event_type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase) +{ + auto it = type_lookup.find(event_type); + + if (it != type_lookup.end()) + return GetMutable(it->second); + + const size_t new_id_num = specifications.size(); + if (new_id_num >= size_t(EventId::MaxNumIds)) + { + Log::Message(Log::LT_ERROR, "Error while registering event type '%s': Maximum number of allowed events exceeded.", event_type.c_str()); + RMLUI_ERROR; + return specifications.front(); + } + + // No specification found for this name, insert a new entry with default values + EventId new_id = static_cast(new_id_num); + specifications.push_back(EventSpecification{ new_id, event_type, interruptible, bubbles, default_action_phase }); + type_lookup.emplace(event_type, new_id); + return specifications.back(); +} + +const EventSpecification& Get(EventId id) +{ + return GetMutable(id); +} + +const EventSpecification& GetOrInsert(const String& event_type) +{ + // Default values for new event types defined as follows: + constexpr bool interruptible = true; + constexpr bool bubbles = true; + constexpr DefaultActionPhase default_action_phase = DefaultActionPhase::None; + + return GetOrInsert(event_type, interruptible, bubbles, default_action_phase); +} + +EventId GetIdOrInsert(const String& event_type) +{ + auto it = type_lookup.find(event_type); + if (it != type_lookup.end()) + return it->second; + + return GetOrInsert(event_type).id; +} + +EventId InsertOrReplaceCustom(const String& event_type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase) +{ + const size_t size_before = specifications.size(); + EventSpecification& specification = GetOrInsert(event_type, interruptible, bubbles, default_action_phase); + bool got_existing_entry = (size_before == specifications.size()); + + // If we found an existing entry of same type, replace it, but only if it is a custom event id. + if (got_existing_entry && (int)specification.id >= (int)EventId::FirstCustomId) + { + specification.interruptible = interruptible; + specification.bubbles = bubbles; + specification.default_action_phase = default_action_phase; + } + + return specification.id; +} + + +} +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/EventSpecification.h b/thirdparty/RmlUi/Source/Core/EventSpecification.h new file mode 100644 index 000000000..061d23409 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/EventSpecification.h @@ -0,0 +1,68 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_EVENTSPECIFICATION_H +#define RMLUI_CORE_EVENTSPECIFICATION_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/ID.h" + +namespace Rml { + +struct EventSpecification { + EventId id; + String type; + bool interruptible; + bool bubbles; + DefaultActionPhase default_action_phase; +}; + +namespace EventSpecificationInterface { + + void Initialize(); + + // Get event specification for the given id. + // Returns the 'invalid' event type if no specification exists for id. + const EventSpecification& Get(EventId id); + + // Get event specification for the given type. + // If not found: Inserts a new entry with default values. + const EventSpecification& GetOrInsert(const String& event_type); + + // Get event id for the given name. + // If not found: Inserts a new entry with default values. + EventId GetIdOrInsert(const String& event_type); + + // Insert a new specification for the given event_type. + // If the type already exists, it will be replaced if and only if the event type is not an internal type. + EventId InsertOrReplaceCustom(const String& event_type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase); +} + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Factory.cpp b/thirdparty/RmlUi/Source/Core/Factory.cpp new file mode 100644 index 000000000..3fdcc8a37 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Factory.cpp @@ -0,0 +1,655 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/ContextInstancer.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/ElementInstancer.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/EventListenerInstancer.h" +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" + +#include "../../Include/RmlUi/Core/Elements/ElementForm.h" +#include "../../Include/RmlUi/Core/Elements/ElementFormControlInput.h" +#include "../../Include/RmlUi/Core/Elements/ElementFormControlDataSelect.h" +#include "../../Include/RmlUi/Core/Elements/ElementFormControlSelect.h" +#include "../../Include/RmlUi/Core/Elements/ElementFormControlSelect.h" +#include "../../Include/RmlUi/Core/Elements/ElementFormControlTextArea.h" +#include "../../Include/RmlUi/Core/Elements/ElementTabSet.h" +#include "../../Include/RmlUi/Core/Elements/ElementProgressBar.h" +#include "../../Include/RmlUi/Core/Elements/ElementDataGrid.h" +#include "../../Include/RmlUi/Core/Elements/ElementDataGridExpandButton.h" +#include "../../Include/RmlUi/Core/Elements/ElementDataGridCell.h" +#include "../../Include/RmlUi/Core/Elements/ElementDataGridRow.h" + +#include "ContextInstancerDefault.h" +#include "DataControllerDefault.h" +#include "DataViewDefault.h" +#include "DecoratorTiledBoxInstancer.h" +#include "DecoratorTiledHorizontalInstancer.h" +#include "DecoratorTiledImageInstancer.h" +#include "DecoratorTiledVerticalInstancer.h" +#include "DecoratorNinePatch.h" +#include "DecoratorGradient.h" +#include "ElementHandle.h" +#include "ElementTextDefault.h" +#include "EventInstancerDefault.h" +#include "FontEffectBlur.h" +#include "FontEffectGlow.h" +#include "FontEffectOutline.h" +#include "FontEffectShadow.h" +#include "PluginRegistry.h" +#include "PropertyParserColour.h" +#include "StreamFile.h" +#include "StyleSheetFactory.h" +#include "TemplateCache.h" +#include "XMLNodeHandlerBody.h" +#include "XMLNodeHandlerDefault.h" +#include "XMLNodeHandlerHead.h" +#include "XMLNodeHandlerTemplate.h" +#include "XMLParseTools.h" + +#include "Elements/ElementImage.h" +#include "Elements/ElementTextSelection.h" +#include "Elements/XMLNodeHandlerDataGrid.h" +#include "Elements/XMLNodeHandlerTabSet.h" +#include "Elements/XMLNodeHandlerTextArea.h" + +#include + +namespace Rml { + +// Element instancers. +using ElementInstancerMap = UnorderedMap< String, ElementInstancer* >; +static ElementInstancerMap element_instancers; + +// Decorator instancers. +using DecoratorInstancerMap = UnorderedMap< String, DecoratorInstancer* >; +static DecoratorInstancerMap decorator_instancers; + +// Font effect instancers. +using FontEffectInstancerMap = UnorderedMap< String, FontEffectInstancer* >; +static FontEffectInstancerMap font_effect_instancers; + +// Data view instancers. +using DataViewInstancerMap = UnorderedMap< String, DataViewInstancer* >; +static DataViewInstancerMap data_view_instancers; + +// Data controller instancers. +using DataControllerInstancerMap = UnorderedMap< String, DataControllerInstancer* >; +static DataControllerInstancerMap data_controller_instancers; + +// Structural data view instancers. +using StructuralDataViewInstancerMap = SmallUnorderedMap< String, DataViewInstancer* >; +static StructuralDataViewInstancerMap structural_data_view_instancers; + +// Structural data view names. +static StringList structural_data_view_attribute_names; + +// The context instancer. +static ContextInstancer* context_instancer = nullptr; + +// The event instancer +static EventInstancer* event_instancer = nullptr; + +// Event listener instancer. +static EventListenerInstancer* event_listener_instancer = nullptr; + +// Default instancers are constructed and destroyed on Initialise and Shutdown, respectively. +struct DefaultInstancers { + + UniquePtr context_default; + UniquePtr event_default; + + // Basic elements + ElementInstancerElement element_default; + ElementInstancerTextDefault element_text_default; + ElementInstancerGeneric element_img; + ElementInstancerGeneric element_handle; + ElementInstancerGeneric element_body; + + // Control elements + ElementInstancerGeneric form; + ElementInstancerGeneric input; + ElementInstancerGeneric dataselect; + ElementInstancerGeneric select; + + ElementInstancerGeneric textarea; + ElementInstancerGeneric selection; + ElementInstancerGeneric tabset; + + ElementInstancerGeneric progressbar; + + ElementInstancerGeneric datagrid; + ElementInstancerGeneric datagrid_expand; + ElementInstancerGeneric datagrid_cell; + ElementInstancerGeneric datagrid_row; + + // Decorators + DecoratorTiledHorizontalInstancer decorator_tiled_horizontal; + DecoratorTiledVerticalInstancer decorator_tiled_vertical; + DecoratorTiledBoxInstancer decorator_tiled_box; + DecoratorTiledImageInstancer decorator_image; + DecoratorNinePatchInstancer decorator_ninepatch; + DecoratorGradientInstancer decorator_gradient; + + // Font effects + FontEffectBlurInstancer font_effect_blur; + FontEffectGlowInstancer font_effect_glow; + FontEffectOutlineInstancer font_effect_outline; + FontEffectShadowInstancer font_effect_shadow; + + // Data binding views + DataViewInstancerDefault data_view_attribute; + DataViewInstancerDefault data_view_class; + DataViewInstancerDefault data_view_if; + DataViewInstancerDefault data_view_visible; + DataViewInstancerDefault data_view_rml; + DataViewInstancerDefault data_view_style; + DataViewInstancerDefault data_view_text; + DataViewInstancerDefault data_view_value; + + DataViewInstancerDefault structural_data_view_for; + + // Data binding controllers + DataControllerInstancerDefault data_controller_value; + DataControllerInstancerDefault data_controller_event; +}; + +static UniquePtr default_instancers; + + +Factory::Factory() +{ +} + +Factory::~Factory() +{ +} + + +bool Factory::Initialise() +{ + default_instancers = MakeUnique(); + + // Default context instancer + if (!context_instancer) + { + default_instancers->context_default = MakeUnique(); + context_instancer = default_instancers->context_default.get(); + } + + // Default event instancer + if (!event_instancer) + { + default_instancers->event_default = MakeUnique(); + event_instancer = default_instancers->event_default.get(); + } + + // No default event listener instancer + if (!event_listener_instancer) + event_listener_instancer = nullptr; + + // Basic element instancers + RegisterElementInstancer("*", &default_instancers->element_default); + RegisterElementInstancer("img", &default_instancers->element_img); + RegisterElementInstancer("#text", &default_instancers->element_text_default); + RegisterElementInstancer("handle", &default_instancers->element_handle); + RegisterElementInstancer("body", &default_instancers->element_body); + + // Control element instancers + RegisterElementInstancer("form", &default_instancers->form); + RegisterElementInstancer("input", &default_instancers->input); + RegisterElementInstancer("dataselect", &default_instancers->dataselect); + RegisterElementInstancer("select", &default_instancers->select); + + RegisterElementInstancer("textarea", &default_instancers->textarea); + RegisterElementInstancer("#selection", &default_instancers->selection); + RegisterElementInstancer("tabset", &default_instancers->tabset); + + RegisterElementInstancer("progressbar", &default_instancers->progressbar); + + RegisterElementInstancer("datagrid", &default_instancers->datagrid); + RegisterElementInstancer("datagridexpand", &default_instancers->datagrid_expand); + RegisterElementInstancer("#rmlctl_datagridcell", &default_instancers->datagrid_cell); + RegisterElementInstancer("#rmlctl_datagridrow", &default_instancers->datagrid_row); + + // Decorator instancers + RegisterDecoratorInstancer("tiled-horizontal", &default_instancers->decorator_tiled_horizontal); + RegisterDecoratorInstancer("tiled-vertical", &default_instancers->decorator_tiled_vertical); + RegisterDecoratorInstancer("tiled-box", &default_instancers->decorator_tiled_box); + RegisterDecoratorInstancer("image", &default_instancers->decorator_image); + RegisterDecoratorInstancer("ninepatch", &default_instancers->decorator_ninepatch); + RegisterDecoratorInstancer("gradient", &default_instancers->decorator_gradient); + + // Font effect instancers + RegisterFontEffectInstancer("blur", &default_instancers->font_effect_blur); + RegisterFontEffectInstancer("glow", &default_instancers->font_effect_glow); + RegisterFontEffectInstancer("outline", &default_instancers->font_effect_outline); + RegisterFontEffectInstancer("shadow", &default_instancers->font_effect_shadow); + + // Data binding views + RegisterDataViewInstancer(&default_instancers->data_view_attribute, "attr", false); + RegisterDataViewInstancer(&default_instancers->data_view_class, "class", false); + RegisterDataViewInstancer(&default_instancers->data_view_if, "if", false); + RegisterDataViewInstancer(&default_instancers->data_view_visible, "visible", false); + RegisterDataViewInstancer(&default_instancers->data_view_rml, "rml", false); + RegisterDataViewInstancer(&default_instancers->data_view_style, "style", false); + RegisterDataViewInstancer(&default_instancers->data_view_text, "text", false); + RegisterDataViewInstancer(&default_instancers->data_view_value, "value", false); + RegisterDataViewInstancer(&default_instancers->structural_data_view_for, "for", true ); + + // Data binding controllers + RegisterDataControllerInstancer(&default_instancers->data_controller_value, "value"); + RegisterDataControllerInstancer(&default_instancers->data_controller_event, "event"); + + // XML node handlers + XMLParser::RegisterNodeHandler("", MakeShared()); + XMLParser::RegisterNodeHandler("body", MakeShared()); + XMLParser::RegisterNodeHandler("head", MakeShared()); + XMLParser::RegisterNodeHandler("template", MakeShared()); + + // XML node handlers for control elements + XMLParser::RegisterNodeHandler("datagrid", MakeShared()); + XMLParser::RegisterNodeHandler("tabset", MakeShared()); + XMLParser::RegisterNodeHandler("textarea", MakeShared()); + + return true; +} + +void Factory::Shutdown() +{ + element_instancers.clear(); + + decorator_instancers.clear(); + + font_effect_instancers.clear(); + + data_view_instancers.clear(); + structural_data_view_instancers.clear(); + structural_data_view_attribute_names.clear(); + + context_instancer = nullptr; + + event_listener_instancer = nullptr; + + event_instancer = nullptr; + + XMLParser::ReleaseHandlers(); + + default_instancers.reset(); +} + +// Registers the instancer to use when instancing contexts. +void Factory::RegisterContextInstancer(ContextInstancer* instancer) +{ + context_instancer = instancer; +} + +// Instances a new context. +ContextPtr Factory::InstanceContext(const String& name) +{ + ContextPtr new_context = context_instancer->InstanceContext(name); + if (new_context) + new_context->SetInstancer(context_instancer); + return new_context; +} + +void Factory::RegisterElementInstancer(const String& name, ElementInstancer* instancer) +{ + element_instancers[StringUtilities::ToLower(name)] = instancer; +} + +// Looks up the instancer for the given element +ElementInstancer* Factory::GetElementInstancer(const String& tag) +{ + ElementInstancerMap::iterator instancer_iterator = element_instancers.find(tag); + if (instancer_iterator == element_instancers.end()) + { + instancer_iterator = element_instancers.find("*"); + if (instancer_iterator == element_instancers.end()) + return nullptr; + } + + return instancer_iterator->second; +} + +// Instances a single element. +ElementPtr Factory::InstanceElement(Element* parent, const String& instancer_name, const String& tag, const XMLAttributes& attributes) +{ + ElementInstancer* instancer = GetElementInstancer(instancer_name); + + if (instancer) + { + ElementPtr element = instancer->InstanceElement(parent, tag, attributes); + + // Process the generic attributes and bind any events + if (element) + { + element->SetInstancer(instancer); + element->SetAttributes(attributes); + ElementUtilities::BindEventAttributes(element.get()); + + PluginRegistry::NotifyElementCreate(element.get()); + } + + return element; + } + + return nullptr; +} + +// Instances a single text element containing a string. +bool Factory::InstanceElementText(Element* parent, const String& in_text) +{ + RMLUI_ASSERT(parent); + + String text; + if (SystemInterface* system_interface = GetSystemInterface()) + system_interface->TranslateString(text, in_text); + + // If this text node only contains white-space we don't want to construct it. + const bool only_white_space = std::all_of(text.begin(), text.end(), &StringUtilities::IsWhitespace); + if (only_white_space) + return true; + + // See if we need to parse it as RML, and whether the text contains data expressions (curly brackets). + bool parse_as_rml = false; + bool has_data_expression = false; + + bool inside_brackets = false; + char previous = 0; + for (const char c : text) + { + const char* error_str = XMLParseTools::ParseDataBrackets(inside_brackets, c, previous); + if (error_str) + { + Log::Message(Log::LT_WARNING, "Failed to instance text element '%s'. %s", text.c_str(), error_str); + return false; + } + + if (inside_brackets) + has_data_expression = true; + else if (c == '<') + parse_as_rml = true; + + previous = c; + } + + // If the text contains RML elements then run it through the XML parser again. + if (parse_as_rml) + { + RMLUI_ZoneScopedNC("InstanceStream", 0xDC143C); + auto stream = MakeUnique(text.size() + 32); + String tag = parent->GetContext()->GetDocumentsBaseTag(); + String open_tag = "<" + tag + ">"; + String close_tag = ""; + stream->Write(open_tag.c_str(), open_tag.size()); + stream->Write(text); + stream->Write(close_tag.c_str(), close_tag.size()); + stream->Seek(0, SEEK_SET); + + InstanceElementStream(parent, stream.get()); + } + else + { + RMLUI_ZoneScopedNC("InstanceText", 0x8FBC8F); + + // Attempt to instance the element. + XMLAttributes attributes; + + // If we have curly brackets in the text, we tag the element so that the appropriate data view (DataViewText) is constructed. + if (has_data_expression) + attributes.emplace("data-text", Variant()); + + ElementPtr element = Factory::InstanceElement(parent, "#text", "#text", attributes); + if (!element) + { + Log::Message(Log::LT_ERROR, "Failed to instance text element '%s', instancer returned nullptr.", text.c_str()); + return false; + } + + // Assign the element its text value. + ElementText* text_element = rmlui_dynamic_cast< ElementText* >(element.get()); + if (!text_element) + { + Log::Message(Log::LT_ERROR, "Failed to instance text element '%s'. Found type '%s', was expecting a derivative of ElementText.", text.c_str(), rmlui_type_name(*element)); + return false; + } + + text_element->SetText(text); + + // Add to active node. + parent->AppendChild(std::move(element)); + } + + return true; +} + +// Instances a element tree based on the stream +bool Factory::InstanceElementStream(Element* parent, Stream* stream) +{ + XMLParser parser(parent); + parser.Parse(stream); + return true; +} + +// Instances a element tree based on the stream +ElementPtr Factory::InstanceDocumentStream(Context* context, Stream* stream) +{ + RMLUI_ZoneScoped; + RMLUI_ASSERT(context); + + ElementPtr element = Factory::InstanceElement(nullptr, context->GetDocumentsBaseTag(), context->GetDocumentsBaseTag(), XMLAttributes()); + if (!element) + { + Log::Message(Log::LT_ERROR, "Failed to instance document, instancer returned nullptr."); + return nullptr; + } + + ElementDocument* document = rmlui_dynamic_cast< ElementDocument* >(element.get()); + if (!document) + { + Log::Message(Log::LT_ERROR, "Failed to instance document element. Found type '%s', was expecting derivative of ElementDocument.", rmlui_type_name(*element)); + return nullptr; + } + + document->context = context; + + XMLParser parser(element.get()); + parser.Parse(stream); + + return element; +} + + +// Registers an instancer that will be used to instance decorators. +void Factory::RegisterDecoratorInstancer(const String& name, DecoratorInstancer* instancer) +{ + RMLUI_ASSERT(instancer); + decorator_instancers[StringUtilities::ToLower(name)] = instancer; +} + +// Retrieves a decorator instancer registered with the factory. +DecoratorInstancer* Factory::GetDecoratorInstancer(const String& name) +{ + auto iterator = decorator_instancers.find(name); + if (iterator == decorator_instancers.end()) + return nullptr; + + return iterator->second; +} + +// Registers an instancer that will be used to instance font effects. +void Factory::RegisterFontEffectInstancer(const String& name, FontEffectInstancer* instancer) +{ + RMLUI_ASSERT(instancer); + font_effect_instancers[StringUtilities::ToLower(name)] = instancer; +} + +FontEffectInstancer* Factory::GetFontEffectInstancer(const String& name) +{ + auto iterator = font_effect_instancers.find(name); + if (iterator == font_effect_instancers.end()) + return nullptr; + + return iterator->second; +} + + +// Creates a style sheet containing the passed in styles. +SharedPtr Factory::InstanceStyleSheetString(const String& string) +{ + auto memory_stream = MakeUnique((const byte*) string.c_str(), string.size()); + return InstanceStyleSheetStream(memory_stream.get()); +} + +// Creates a style sheet from a file. +SharedPtr Factory::InstanceStyleSheetFile(const String& file_name) +{ + auto file_stream = MakeUnique(); + file_stream->Open(file_name); + return InstanceStyleSheetStream(file_stream.get()); +} + +// Creates a style sheet from an Stream. +SharedPtr Factory::InstanceStyleSheetStream(Stream* stream) +{ + SharedPtr style_sheet = MakeShared(); + if (style_sheet->LoadStyleSheet(stream)) + { + return style_sheet; + } + return nullptr; +} + +// Clears the style sheet cache. This will force style sheets to be reloaded. +void Factory::ClearStyleSheetCache() +{ + StyleSheetFactory::ClearStyleSheetCache(); +} + +/// Clears the template cache. This will force templates to be reloaded. +void Factory::ClearTemplateCache() +{ + TemplateCache::Clear(); +} + +// Registers an instancer for all RmlEvents +void Factory::RegisterEventInstancer(EventInstancer* instancer) +{ + event_instancer = instancer; +} + +// Instance an event object. +EventPtr Factory::InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible) +{ + EventPtr event = event_instancer->InstanceEvent(target, id, type, parameters, interruptible); + if (event) + event->instancer = event_instancer; + return event; +} + +// Register an instancer for all event listeners +void Factory::RegisterEventListenerInstancer(EventListenerInstancer* instancer) +{ + event_listener_instancer = instancer; +} + +// Instance an event listener with the given string +EventListener* Factory::InstanceEventListener(const String& value, Element* element) +{ + // If we have an event listener instancer, use it + if (event_listener_instancer) + return event_listener_instancer->InstanceEventListener(value, element); + + return nullptr; +} + +void Factory::RegisterDataViewInstancer(DataViewInstancer* instancer, const String& name, bool is_structural_view) +{ + bool inserted = false; + if (is_structural_view) + { + inserted = structural_data_view_instancers.emplace(name, instancer).second; + if (inserted) + structural_data_view_attribute_names.push_back(String("data-") + name); + } + else + { + inserted = data_view_instancers.emplace(name, instancer).second; + } + + if (!inserted) + Log::Message(Log::LT_WARNING, "Could not register data view instancer '%s'. The given name is already registered.", name.c_str()); +} + +void Factory::RegisterDataControllerInstancer(DataControllerInstancer* instancer, const String& name) +{ + bool inserted = data_controller_instancers.emplace(name, instancer).second; + if (!inserted) + Log::Message(Log::LT_WARNING, "Could not register data controller instancer '%s'. The given name is already registered.", name.c_str()); +} + +DataViewPtr Factory::InstanceDataView(const String& type_name, Element* element, bool is_structural_view) +{ + RMLUI_ASSERT(element); + + if (is_structural_view) + { + auto it = structural_data_view_instancers.find(type_name); + if (it != structural_data_view_instancers.end()) + return it->second->InstanceView(element); + } + else + { + auto it = data_view_instancers.find(type_name); + if (it != data_view_instancers.end()) + return it->second->InstanceView(element); + } + return nullptr; +} + +DataControllerPtr Factory::InstanceDataController(const String& type_name, Element* element) +{ + auto it = data_controller_instancers.find(type_name); + if (it != data_controller_instancers.end()) + return it->second->InstanceController(element); + return DataControllerPtr(); +} + +const StringList& Factory::GetStructuralDataViewAttributeNames() +{ + return structural_data_view_attribute_names; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FileInterface.cpp b/thirdparty/RmlUi/Source/Core/FileInterface.cpp new file mode 100644 index 000000000..80b61262e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FileInterface.cpp @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/FileInterface.h" + +namespace Rml { + +FileInterface::FileInterface() +{ +} + +FileInterface::~FileInterface() +{ +} + +// Returns the length of the file. +size_t FileInterface::Length(FileHandle file) +{ + size_t current_position = Tell(file); + Seek( file, 0, SEEK_END); + size_t length = Tell( file); + Seek( file, (long)current_position, SEEK_SET); + return length; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FileInterfaceDefault.cpp b/thirdparty/RmlUi/Source/Core/FileInterfaceDefault.cpp new file mode 100644 index 000000000..c29f2d60e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FileInterfaceDefault.cpp @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FileInterfaceDefault.h" + +#ifndef RMLUI_NO_FILE_INTERFACE_DEFAULT + +namespace Rml { + +FileInterfaceDefault::~FileInterfaceDefault() +{ +} + +// Opens a file. +FileHandle FileInterfaceDefault::Open(const String& path) +{ + return (FileHandle)fopen(path.c_str(), "rb"); +} + +// Closes a previously opened file. +void FileInterfaceDefault::Close(FileHandle file) +{ + fclose((FILE*) file); +} + +// Reads data from a previously opened file. +size_t FileInterfaceDefault::Read(void* buffer, size_t size, FileHandle file) +{ + return fread(buffer, 1, size, (FILE*) file); +} + +// Seeks to a point in a previously opened file. +bool FileInterfaceDefault::Seek(FileHandle file, long offset, int origin) +{ + return fseek((FILE*) file, offset, origin) == 0; +} + +// Returns the current position of the file pointer. +size_t FileInterfaceDefault::Tell(FileHandle file) +{ + return ftell((FILE*) file); +} + +} // namespace Rml +#endif /*RMLUI_NO_FILE_INTERFACE_DEFAULT*/ diff --git a/thirdparty/RmlUi/Source/Core/FileInterfaceDefault.h b/thirdparty/RmlUi/Source/Core/FileInterfaceDefault.h new file mode 100644 index 000000000..4e38ab2f3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FileInterfaceDefault.h @@ -0,0 +1,78 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FILEINTERFACEDEFAULT_H +#define RMLUI_CORE_FILEINTERFACEDEFAULT_H + +#include "../../Include/RmlUi/Core/FileInterface.h" + +#ifndef RMLUI_NO_FILE_INTERFACE_DEFAULT + +namespace Rml { + +/** + Implementation of the RmlUi file interface using the Standard C file functions. + + @author Peter Curry + */ + +class FileInterfaceDefault : public FileInterface +{ +public: + virtual ~FileInterfaceDefault(); + + /// Opens a file. + /// @param path The path of the file to open. + /// @return A valid file handle, or nullptr on failure + FileHandle Open(const String& path) override; + /// Closes a previously opened file. + /// @param file The file handle previously opened through Open(). + void Close(FileHandle file) override; + + /// Reads data from a previously opened file. + /// @param buffer The buffer to be read into. + /// @param size The number of bytes to read into the buffer. + /// @param file The handle of the file. + /// @return The total number of bytes read into the buffer. + size_t Read(void* buffer, size_t size, FileHandle file) override; + /// Seeks to a point in a previously opened file. + /// @param file The handle of the file to seek. + /// @param offset The number of bytes to seek. + /// @param origin One of either SEEK_SET (seek from the beginning of the file), SEEK_END (seek from the end of the file) or SEEK_CUR (seek from the current file position). + /// @return True if the operation completed successfully, false otherwise. + bool Seek(FileHandle file, long offset, int origin) override; + /// Returns the current position of the file pointer. + /// @param file The handle of the file to be queried. + /// @return The number of bytes from the origin of the file. + size_t Tell(FileHandle file) override; +}; + +} // namespace Rml +#endif /*RMLUI_NO_FILE_INTERFACE_DEFAULT*/ + +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEffect.cpp b/thirdparty/RmlUi/Source/Core/FontEffect.cpp new file mode 100644 index 000000000..799a17d01 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffect.cpp @@ -0,0 +1,95 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/FontEffect.h" +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" + +namespace Rml { + +FontEffect::FontEffect() : colour(255, 255, 255) +{ + layer = Layer::Back; +} + +FontEffect::~FontEffect() +{ +} + +bool FontEffect::HasUniqueTexture() const +{ + return false; +} + +bool FontEffect::GetGlyphMetrics(Vector2i& RMLUI_UNUSED_PARAMETER(origin), Vector2i& RMLUI_UNUSED_PARAMETER(dimensions), const FontGlyph& RMLUI_UNUSED_PARAMETER(glyph)) const +{ + RMLUI_UNUSED(origin); + RMLUI_UNUSED(dimensions); + RMLUI_UNUSED(glyph); + + return false; +} + +void FontEffect::GenerateGlyphTexture(byte* RMLUI_UNUSED_PARAMETER(destination_data), Vector2i RMLUI_UNUSED_PARAMETER(destination_dimensions), int RMLUI_UNUSED_PARAMETER(destination_stride), const FontGlyph& RMLUI_UNUSED_PARAMETER(glyph)) const +{ + RMLUI_UNUSED(destination_data); + RMLUI_UNUSED(destination_dimensions); + RMLUI_UNUSED(destination_stride); + RMLUI_UNUSED(glyph); +} + +void FontEffect::SetColour(const Colourb& _colour) +{ + colour = _colour; +} + +const Colourb& FontEffect::GetColour() const +{ + return colour; +} + +FontEffect::Layer FontEffect::GetLayer() const +{ + return layer; +} + +void FontEffect::SetLayer(Layer _layer) +{ + layer = _layer; +} + +size_t FontEffect::GetFingerprint() const +{ + return fingerprint; +} + +void FontEffect::SetFingerprint(size_t _fingerprint) +{ + fingerprint = _fingerprint; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEffectBlur.cpp b/thirdparty/RmlUi/Source/Core/FontEffectBlur.cpp new file mode 100644 index 000000000..880cd4625 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectBlur.cpp @@ -0,0 +1,148 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontEffectBlur.h" +#include "Memory.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +FontEffectBlur::FontEffectBlur() +{ + width = 0; + SetLayer(Layer::Back); +} + +FontEffectBlur::~FontEffectBlur() +{ +} + +bool FontEffectBlur::HasUniqueTexture() const +{ + return true; +} + +bool FontEffectBlur::Initialise(int _width) +{ + if (_width <= 0) + return false; + + width = _width; + + const float std_dev = .4f * float(width); + const float two_variance = 2.f * std_dev * std_dev; + const float gain = 1.f / Math::SquareRoot(Math::RMLUI_PI * two_variance); + + float sum_weight = 0.f; + + // We separate the blur filter into two passes, horizontal and vertical, for performance reasons. + filter_x.Initialise(Vector2i(width, 0), FilterOperation::Sum); + filter_y.Initialise(Vector2i(0, width), FilterOperation::Sum); + + for (int x = -width; x <= width; ++x) + { + float weight = gain * Math::Exp(-Math::SquareRoot(float(x * x) / two_variance)); + + filter_x[0][x + width] = weight; + filter_y[x + width][0] = weight; + sum_weight += weight; + } + + // Normalize the kernels + for (int x = -width; x <= width; ++x) + { + filter_x[0][x + width] /= sum_weight; + filter_y[x + width][0] /= sum_weight; + } + + return true; +} + +bool FontEffectBlur::GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& RMLUI_UNUSED_PARAMETER(glyph)) const +{ + RMLUI_UNUSED(glyph); + + if (dimensions.x * dimensions.y > 0) + { + origin.x -= width; + origin.y -= width; + + dimensions.y += 2 * width; + dimensions.x += 2 * width; + + return true; + } + + return false; +} + +void FontEffectBlur::GenerateGlyphTexture(byte* destination_data, const Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const +{ + const Vector2i buf_dimensions = destination_dimensions; + const int buf_stride = buf_dimensions.x; + const int buf_size = buf_dimensions.x * buf_dimensions.y; + DynamicArray> x_output(buf_size); + + filter_x.Run(x_output.data(), buf_dimensions, buf_stride, ColorFormat::A8, glyph.bitmap_data, glyph.bitmap_dimensions, Vector2i(width)); + + filter_y.Run(destination_data, destination_dimensions, destination_stride, ColorFormat::RGBA8, x_output.data(), buf_dimensions, Vector2i(0)); +} + + + + + +FontEffectBlurInstancer::FontEffectBlurInstancer() : id_width(PropertyId::Invalid), id_color(PropertyId::Invalid) +{ + id_width = RegisterProperty("width", "1px", true).AddParser("length").GetId(); + id_color = RegisterProperty("color", "white", false).AddParser("color").GetId(); + RegisterShorthand("font-effect", "width, color", ShorthandType::FallThrough); +} + +FontEffectBlurInstancer::~FontEffectBlurInstancer() +{ +} + +SharedPtr FontEffectBlurInstancer::InstanceFontEffect(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties) +{ + RMLUI_UNUSED(name); + + float width = properties.GetProperty(id_width)->Get< float >(); + Colourb color = properties.GetProperty(id_color)->Get< Colourb >(); + + auto font_effect = MakeShared(); + if (font_effect->Initialise(Math::RealToInteger(width))) + { + font_effect->SetColour(color); + return font_effect; + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEffectBlur.h b/thirdparty/RmlUi/Source/Core/FontEffectBlur.h new file mode 100644 index 000000000..eee351a06 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectBlur.h @@ -0,0 +1,81 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTEFFECTBLUR_H +#define RMLUI_CORE_FONTEFFECTBLUR_H + +#include "../../Include/RmlUi/Core/ConvolutionFilter.h" +#include "../../Include/RmlUi/Core/FontEffect.h" +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" + +namespace Rml { + +/** + A concrete font effect for rendering Gaussian blurred text. + */ + +class FontEffectBlur : public FontEffect +{ +public: + FontEffectBlur(); + virtual ~FontEffectBlur(); + + bool Initialise(int width); + + bool HasUniqueTexture() const override; + + bool GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& glyph) const override; + + void GenerateGlyphTexture(byte* destination_data, Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const override; + +private: + int width; + ConvolutionFilter filter_x, filter_y; +}; + + + +/** + A concrete font effect instancer for the blur effect. + */ + +class FontEffectBlurInstancer : public FontEffectInstancer +{ +public: + FontEffectBlurInstancer(); + virtual ~FontEffectBlurInstancer(); + + SharedPtr InstanceFontEffect(const String& name, const PropertyDictionary& properties) override; + +private: + PropertyId id_width, id_color; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEffectGlow.cpp b/thirdparty/RmlUi/Source/Core/FontEffectGlow.cpp new file mode 100644 index 000000000..992be0ea3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectGlow.cpp @@ -0,0 +1,186 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontEffectGlow.h" +#include "Memory.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +FontEffectGlow::FontEffectGlow() +{ + width_blur = 0; + width_outline = 0; + combined_width = 0; + SetLayer(Layer::Back); +} + +FontEffectGlow::~FontEffectGlow() +{ +} + +bool FontEffectGlow::HasUniqueTexture() const +{ + return true; +} + +bool FontEffectGlow::Initialise(int _width_outline, int _width_blur, Vector2i _offset) +{ + if (_width_outline < 0 || _width_blur < 0) + return false; + + width_outline = _width_outline; + width_blur = _width_blur; + combined_width = width_blur + width_outline; + offset = _offset; + + // Outline filter. + filter_outline.Initialise(width_outline, FilterOperation::Dilation); + for (int x = -width_outline; x <= width_outline; ++x) + { + for (int y = -width_outline; y <= width_outline; ++y) + { + float weight = 1; + + float distance = Math::SquareRoot(float(x * x + y * y)); + if (distance > width_outline) + { + weight = (width_outline + 1) - distance; + weight = Math::Max(weight, 0.0f); + } + + filter_outline[x + width_outline][y + width_outline] = weight; + } + } + + + // Gaussian blur filter + const float std_dev = (width_blur == 0 ? 1.f : .4f * float(width_blur)); + const float two_variance = 2.f * std_dev * std_dev; + const float gain = 1.f / Math::SquareRoot(Math::RMLUI_PI * two_variance); + + float sum_weight = 0.f; + + // We separate the blur filter into two passes, horizontal and vertical, for performance reasons. + filter_blur_x.Initialise(Vector2i(width_blur, 0), FilterOperation::Sum); + filter_blur_y.Initialise(Vector2i(0, width_blur), FilterOperation::Sum); + + for (int x = -width_blur; x <= width_blur; ++x) + { + float weight = gain * Math::Exp(-Math::SquareRoot(float(x * x) / two_variance)); + + filter_blur_x[0][x + width_blur] = weight; + filter_blur_y[x + width_blur][0] = weight; + sum_weight += weight; + } + + // Normalize the kernels + for (int x = -width_blur; x <= width_blur; ++x) + { + filter_blur_x[0][x + width_blur] /= sum_weight; + filter_blur_y[x + width_blur][0] /= sum_weight; + } + + return true; +} + +bool FontEffectGlow::GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& RMLUI_UNUSED_PARAMETER(glyph)) const +{ + RMLUI_UNUSED(glyph); + + if (dimensions.x * dimensions.y > 0) + { + origin.x += offset.x - combined_width; + origin.y += offset.y - combined_width; + + dimensions.x += 2 * combined_width; + dimensions.y += 2 * combined_width; + + return true; + } + + return false; +} + +void FontEffectGlow::GenerateGlyphTexture(byte* destination_data, const Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const +{ + const Vector2i buf_dimensions = destination_dimensions; + const int buf_stride = buf_dimensions.x; + const int buf_size = buf_dimensions.x * buf_dimensions.y; + + DynamicArray> outline_output(buf_size); + DynamicArray> blur_x_output(buf_size); + + filter_outline.Run(outline_output.data(), buf_dimensions, buf_stride, ColorFormat::A8, glyph.bitmap_data, glyph.bitmap_dimensions, Vector2i(combined_width)); + + filter_blur_x.Run(blur_x_output.data(), buf_dimensions, buf_stride, ColorFormat::A8, outline_output.data(), buf_dimensions, Vector2i(0)); + + filter_blur_y.Run(destination_data, destination_dimensions, destination_stride, ColorFormat::RGBA8, blur_x_output.data(), buf_dimensions, Vector2i(0)); +} + + + +FontEffectGlowInstancer::FontEffectGlowInstancer() : id_width_outline(PropertyId::Invalid), id_width_blur(PropertyId::Invalid),id_color(PropertyId::Invalid) +{ + id_width_outline = RegisterProperty("width-outline", "1px", true).AddParser("length").GetId(); + id_width_blur = RegisterProperty("width-blur", "-1px", true).AddParser("length").GetId(); + id_offset_x = RegisterProperty("offset-x", "0px", true).AddParser("length").GetId(); + id_offset_y = RegisterProperty("offset-y", "0px", true).AddParser("length").GetId(); + id_color = RegisterProperty("color", "white", false).AddParser("color").GetId(); + RegisterShorthand("font-effect", "width-outline, width-blur, offset-x, offset-y, color", ShorthandType::FallThrough); +} + +FontEffectGlowInstancer::~FontEffectGlowInstancer() +{ +} + +SharedPtr FontEffectGlowInstancer::InstanceFontEffect(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties) +{ + RMLUI_UNUSED(name); + + Vector2i offset; + int width_outline = properties.GetProperty(id_width_outline)->Get< int >(); + int width_blur = properties.GetProperty(id_width_blur)->Get< int >(); + offset.x = properties.GetProperty(id_offset_x)->Get< int >(); + offset.y = properties.GetProperty(id_offset_y)->Get< int >(); + Colourb color = properties.GetProperty(id_color)->Get< Colourb >(); + + if (width_blur < 0) + width_blur = width_outline; + + auto font_effect = MakeShared(); + if (font_effect->Initialise(width_outline, width_blur, offset)) + { + font_effect->SetColour(color); + return font_effect; + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEffectGlow.h b/thirdparty/RmlUi/Source/Core/FontEffectGlow.h new file mode 100644 index 000000000..dea66212e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectGlow.h @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTEFFECTGLOW_H +#define RMLUI_CORE_FONTEFFECTGLOW_H + +#include "../../Include/RmlUi/Core/ConvolutionFilter.h" +#include "../../Include/RmlUi/Core/FontEffect.h" +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" + +namespace Rml { + +/** + A font effect for rendering glow around text. + + Glow consists of an outline pass followed by a Gaussian blur pass. + + */ + +class FontEffectGlow : public FontEffect +{ +public: + FontEffectGlow(); + virtual ~FontEffectGlow(); + + bool Initialise(int width_outline, int width_blur, Vector2i offset); + + bool HasUniqueTexture() const override; + + bool GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& glyph) const override; + + void GenerateGlyphTexture(byte* destination_data, Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const override; + +private: + int width_outline, width_blur, combined_width; + Vector2i offset; + ConvolutionFilter filter_outline, filter_blur_x, filter_blur_y; +}; + + + +/** + A concrete font effect instancer for the glow effect. + */ + +class FontEffectGlowInstancer : public FontEffectInstancer +{ +public: + FontEffectGlowInstancer(); + virtual ~FontEffectGlowInstancer(); + + SharedPtr InstanceFontEffect(const String& name, const PropertyDictionary& properties) override; + +private: + PropertyId id_width_outline, id_width_blur, id_offset_x, id_offset_y, id_color; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEffectInstancer.cpp b/thirdparty/RmlUi/Source/Core/FontEffectInstancer.cpp new file mode 100644 index 000000000..6cfbfef46 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectInstancer.cpp @@ -0,0 +1,64 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +FontEffectInstancer::FontEffectInstancer() : properties(10, 10) +{ +} + +FontEffectInstancer::~FontEffectInstancer() +{ +} + +// Returns the property specification associated with the instancer. +const PropertySpecification& FontEffectInstancer::GetPropertySpecification() const +{ + return properties; +} + +// Registers a property for the font effect. +PropertyDefinition& FontEffectInstancer::RegisterProperty(const String& property_name, const String& default_value, bool affects_generation) +{ + PropertyDefinition& definition = properties.RegisterProperty(property_name, default_value, false, false); + if (affects_generation) + volatile_properties.insert(definition.GetId()); + + return definition; +} + +// Registers a shorthand property definition. +ShorthandId FontEffectInstancer::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type) +{ + return properties.RegisterShorthand(shorthand_name, property_names, type); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEffectOutline.cpp b/thirdparty/RmlUi/Source/Core/FontEffectOutline.cpp new file mode 100644 index 000000000..f7841cb8e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectOutline.cpp @@ -0,0 +1,130 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontEffectOutline.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +FontEffectOutline::FontEffectOutline() +{ + width = 0; + SetLayer(Layer::Back); +} + +FontEffectOutline::~FontEffectOutline() +{ +} + +bool FontEffectOutline::HasUniqueTexture() const +{ + return true; +} + +bool FontEffectOutline::Initialise(int _width) +{ + if (_width <= 0) + return false; + + width = _width; + + filter.Initialise(width, FilterOperation::Dilation); + for (int x = -width; x <= width; ++x) + { + for (int y = -width; y <= width; ++y) + { + float weight = 1; + + float distance = Math::SquareRoot(float(x * x + y * y)); + if (distance > width) + { + weight = (width + 1) - distance; + weight = Math::Max(weight, 0.0f); + } + + filter[x + width][y + width] = weight; + } + } + + return true; +} + +bool FontEffectOutline::GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& RMLUI_UNUSED_PARAMETER(glyph)) const +{ + RMLUI_UNUSED(glyph); + + if (dimensions.x * dimensions.y > 0) + { + origin.x -= width; + origin.y -= width; + + dimensions.x += 2 * width; + dimensions.y += 2 * width; + + return true; + } + + return false; +} + +void FontEffectOutline::GenerateGlyphTexture(byte* destination_data, const Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const +{ + filter.Run(destination_data, destination_dimensions, destination_stride, ColorFormat::RGBA8, glyph.bitmap_data, glyph.bitmap_dimensions, Vector2i(width)); +} + + + +FontEffectOutlineInstancer::FontEffectOutlineInstancer() : id_width(PropertyId::Invalid), id_color(PropertyId::Invalid) +{ + id_width = RegisterProperty("width", "1px", true).AddParser("length").GetId(); + id_color = RegisterProperty("color", "white", false).AddParser("color").GetId(); + RegisterShorthand("font-effect", "width, color", ShorthandType::FallThrough); +} + +FontEffectOutlineInstancer::~FontEffectOutlineInstancer() +{ +} + +SharedPtr FontEffectOutlineInstancer::InstanceFontEffect(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties) +{ + RMLUI_UNUSED(name); + + float width = properties.GetProperty(id_width)->Get< float >(); + Colourb color = properties.GetProperty(id_color)->Get< Colourb >(); + + auto font_effect = MakeShared(); + if (font_effect->Initialise(Math::RealToInteger(width))) + { + font_effect->SetColour(color); + return font_effect; + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEffectOutline.h b/thirdparty/RmlUi/Source/Core/FontEffectOutline.h new file mode 100644 index 000000000..dfd9c122d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectOutline.h @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTEFFECTOUTLINE_H +#define RMLUI_CORE_FONTEFFECTOUTLINE_H + +#include "../../Include/RmlUi/Core/ConvolutionFilter.h" +#include "../../Include/RmlUi/Core/FontEffect.h" +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" + +namespace Rml { + +/** + A concrete font effect for rendering outlines around text. + + @author Peter Curry + */ + +class FontEffectOutline : public FontEffect +{ +public: + FontEffectOutline(); + virtual ~FontEffectOutline(); + + bool Initialise(int width); + + bool HasUniqueTexture() const override; + + bool GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& glyph) const override; + + void GenerateGlyphTexture(byte* destination_data, Vector2i destination_dimensions, int destination_stride, const FontGlyph& glyph) const override; + +private: + int width; + ConvolutionFilter filter; +}; + + + +/** + A concrete font effect instancer for the outline effect. + + @author Peter Curry + */ + +class FontEffectOutlineInstancer : public FontEffectInstancer +{ +public: + FontEffectOutlineInstancer(); + virtual ~FontEffectOutlineInstancer(); + + SharedPtr InstanceFontEffect(const String& name, const PropertyDictionary& properties) override; + +private: + PropertyId id_width, id_color; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEffectShadow.cpp b/thirdparty/RmlUi/Source/Core/FontEffectShadow.cpp new file mode 100644 index 000000000..c3f71930c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectShadow.cpp @@ -0,0 +1,97 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontEffectShadow.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +FontEffectShadow::FontEffectShadow() : offset(0, 0) +{ + SetLayer(Layer::Back); +} + +FontEffectShadow::~FontEffectShadow() +{ +} + +bool FontEffectShadow::Initialise(const Vector2i& _offset) +{ + offset = _offset; + return true; +} + +bool FontEffectShadow::HasUniqueTexture() const +{ + return false; +} + +bool FontEffectShadow::GetGlyphMetrics(Vector2i& origin, Vector2i& RMLUI_UNUSED_PARAMETER(dimensions), const FontGlyph& RMLUI_UNUSED_PARAMETER(glyph)) const +{ + RMLUI_UNUSED(dimensions); + RMLUI_UNUSED(glyph); + + origin += offset; + return true; +} + + + +FontEffectShadowInstancer::FontEffectShadowInstancer() : id_offset_x(PropertyId::Invalid), id_offset_y(PropertyId::Invalid), id_color(PropertyId::Invalid) +{ + id_offset_x = RegisterProperty("offset-x", "0px", true).AddParser("length").GetId(); + id_offset_y = RegisterProperty("offset-y", "0px", true).AddParser("length").GetId(); + id_color = RegisterProperty("color", "white", false).AddParser("color").GetId(); + RegisterShorthand("offset", "offset-x, offset-y", ShorthandType::FallThrough); + RegisterShorthand("font-effect", "offset-x, offset-y, color", ShorthandType::FallThrough); +} + +FontEffectShadowInstancer::~FontEffectShadowInstancer() +{ +} + +SharedPtr FontEffectShadowInstancer::InstanceFontEffect(const String& RMLUI_UNUSED_PARAMETER(name), const PropertyDictionary& properties) +{ + RMLUI_UNUSED(name); + + Vector2i offset; + offset.x = Math::RealToInteger(properties.GetProperty(id_offset_x)->Get< float >()); + offset.y = Math::RealToInteger(properties.GetProperty(id_offset_y)->Get< float >()); + Colourb color = properties.GetProperty(id_color)->Get< Colourb >(); + + auto font_effect = MakeShared(); + if (font_effect->Initialise(offset)) + { + font_effect->SetColour(color); + return font_effect; + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEffectShadow.h b/thirdparty/RmlUi/Source/Core/FontEffectShadow.h new file mode 100644 index 000000000..48126d76b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEffectShadow.h @@ -0,0 +1,81 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTEFFECTSHADOW_H +#define RMLUI_CORE_FONTEFFECTSHADOW_H + +#include "../../Include/RmlUi/Core/FontEffect.h" +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" + +namespace Rml { + +/** + A concrete font effect for rendering text shadows. + + @author Peter Curry + */ + +class FontEffectShadow : public FontEffect +{ +public: + FontEffectShadow(); + virtual ~FontEffectShadow(); + + bool Initialise(const Vector2i& offset); + + bool HasUniqueTexture() const override; + + bool GetGlyphMetrics(Vector2i& origin, Vector2i& dimensions, const FontGlyph& glyph) const override; + +private: + Vector2i offset; +}; + + + +/** + A concrete font effect instancer for the shadow effect. + + @author Peter Curry + */ + +class FontEffectShadowInstancer : public FontEffectInstancer +{ +public: + FontEffectShadowInstancer(); + virtual ~FontEffectShadowInstancer(); + + SharedPtr InstanceFontEffect(const String& name, const PropertyDictionary& properties) override; + +private: + PropertyId id_offset_x, id_offset_y, id_color; +}; + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp new file mode 100644 index 000000000..23969dd0a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp @@ -0,0 +1,116 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontProvider.h" +#include "FontFaceHandleDefault.h" +#include "FontEngineInterfaceDefault.h" + +namespace Rml { + +FontEngineInterfaceDefault::FontEngineInterfaceDefault() +{ + FontProvider::Initialise(); +} + +FontEngineInterfaceDefault::~FontEngineInterfaceDefault() +{ + FontProvider::Shutdown(); +} + +bool FontEngineInterfaceDefault::LoadFontFace(const String& file_name, bool fallback_face) +{ + return FontProvider::LoadFontFace(file_name, fallback_face); +} + +bool FontEngineInterfaceDefault::LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face) +{ + return FontProvider::LoadFontFace(data, data_size, font_family, style, weight, fallback_face); +} + +FontFaceHandle FontEngineInterfaceDefault::GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size) +{ + auto handle = FontProvider::GetFontFaceHandle(family, style, weight, size); + return reinterpret_cast(handle); +} + +FontEffectsHandle FontEngineInterfaceDefault::PrepareFontEffects(FontFaceHandle handle, const FontEffectList& font_effects) +{ + auto handle_default = reinterpret_cast(handle); + return (FontEffectsHandle)handle_default->GenerateLayerConfiguration(font_effects); +} + +int FontEngineInterfaceDefault::GetSize(FontFaceHandle handle) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetSize(); +} + +int FontEngineInterfaceDefault::GetXHeight(FontFaceHandle handle) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetXHeight(); +} + +int FontEngineInterfaceDefault::GetLineHeight(FontFaceHandle handle) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetLineHeight(); +} + +int FontEngineInterfaceDefault::GetBaseline(FontFaceHandle handle) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetBaseline(); +} + +float FontEngineInterfaceDefault::GetUnderline(FontFaceHandle handle, float& thickness) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetUnderline(thickness); +} + +int FontEngineInterfaceDefault::GetStringWidth(FontFaceHandle handle, const String& string, Character prior_character) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetStringWidth(string, prior_character); +} + +int FontEngineInterfaceDefault::GenerateString(FontFaceHandle handle, FontEffectsHandle font_effects_handle, const String& string, + const Vector2f& position, const Colourb& colour, GeometryList& geometry) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GenerateString(geometry, string, position, colour, (int)font_effects_handle); +} + +int FontEngineInterfaceDefault::GetVersion(FontFaceHandle handle) +{ + auto handle_default = reinterpret_cast(handle); + return handle_default->GetVersion(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h new file mode 100644 index 000000000..ca25023d2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h @@ -0,0 +1,79 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTENGINEINTERFACEDEFAULT_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTENGINEINTERFACEDEFAULT_H + +#include "../../../Include/RmlUi/Core/FontEngineInterface.h" + +namespace Rml { + +class RMLUICORE_API FontEngineInterfaceDefault : public FontEngineInterface +{ +public: + FontEngineInterfaceDefault(); + virtual ~FontEngineInterfaceDefault(); + + /// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself. + bool LoadFontFace(const String& file_name, bool fallback_face) override; + + /// Adds a new font face to the database using the provided family, style and weight. + bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face) override; + + /// Returns a handle to a font face that can be used to position and render text. This will return the closest match + /// it can find, but in the event a font family is requested that does not exist, NULL will be returned instead of a + /// valid handle. + FontFaceHandle GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size) override; + + /// Prepares for font effects by configuring a new, or returning an existing, layer configuration. + FontEffectsHandle PrepareFontEffects(FontFaceHandle, const FontEffectList& font_effects) override; + + /// Returns the point size of this font face. + int GetSize(FontFaceHandle) override; + /// Returns the pixel height of a lower-case x in this font face. + int GetXHeight(FontFaceHandle) override; + /// Returns the default height between this font face's baselines. + int GetLineHeight(FontFaceHandle) override; + + /// Returns the font's baseline, as a pixel offset from the bottom of the font. + int GetBaseline(FontFaceHandle) override; + + /// Returns the font's underline, as a pixel offset from the bottom of the font. + float GetUnderline(FontFaceHandle, float& thickness) override; + + /// Returns the width a string will take up if rendered with this handle. + int GetStringWidth(FontFaceHandle, const String& string, Character prior_character) override; + + /// Generates the geometry required to render a single line of text. + int GenerateString(FontFaceHandle, FontEffectsHandle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry) override; + + /// Returns the current version of the font face. + int GetVersion(FontFaceHandle handle) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFace.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFace.cpp new file mode 100644 index 000000000..0be207573 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFace.cpp @@ -0,0 +1,96 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../../Include/RmlUi/Core/Log.h" +#include "FontFace.h" +#include "FontFaceHandleDefault.h" +#include "FreeTypeInterface.h" + +namespace Rml { + +FontFace::FontFace(FontFaceHandleFreetype _face, Style::FontStyle _style, Style::FontWeight _weight, bool _release_stream) +{ + style = _style; + weight = _weight; + face = _face; + + release_stream = _release_stream; +} + +FontFace::~FontFace() +{ + if (face) + { + FreeType::ReleaseFace(face, release_stream); + face = 0; + } + handles.clear(); +} + +// Returns the style of the font face. +Style::FontStyle FontFace::GetStyle() const +{ + return style; +} + +// Returns the weight of the font face. +Style::FontWeight FontFace::GetWeight() const +{ + return weight; +} + +FontFaceHandleDefault* FontFace::GetHandle(int size) { + auto it = handles.find(size); + if (it != handles.end()) + return it->second.get(); + + // See if this face has been released. + if (!face) + { + Log::Message(Log::LT_WARNING, "Font face has been released, unable to generate new handle."); + return nullptr; + } + + // Construct and initialise the new handle. + auto handle = MakeUnique(); + if (!handle->Initialize(face, size)) + { + handles[size] = nullptr; + return nullptr; + } + + FontFaceHandleDefault* result = handle.get(); + + // Save the new handle to the font face + handles[size] = std::move(handle); + + return result; +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFace.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFace.h new file mode 100644 index 000000000..ddf27cd86 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFace.h @@ -0,0 +1,71 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTFACE_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTFACE_H + +#include "../../../Include/RmlUi/Core/ComputedValues.h" +#include "FontTypes.h" + +namespace Rml { + +class FontFaceHandleDefault; + +/** + @author Peter Curry + */ + +class FontFace +{ +public: + FontFace(FontFaceHandleFreetype face, Style::FontStyle style, Style::FontWeight weight, bool release_stream); + ~FontFace(); + + Style::FontStyle GetStyle() const; + Style::FontWeight GetWeight() const; + + /// Returns a handle for positioning and rendering this face at the given size. + /// @param[in] size The size of the desired handle, in points. + /// @return The font handle. + FontFaceHandleDefault* GetHandle(int size); + +private: + Style::FontStyle style; + Style::FontWeight weight; + + bool release_stream; + + // Key is font size + using HandleMap = UnorderedMap< int, UniquePtr >; + HandleMap handles; + + FontFaceHandleFreetype face; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp new file mode 100644 index 000000000..ce492effc --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp @@ -0,0 +1,453 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontFaceHandleDefault.h" +#include "../../../Include/RmlUi/Core/StringUtilities.h" +#include "../TextureLayout.h" +#include "FontProvider.h" +#include "FontFaceLayer.h" +#include "FreeTypeInterface.h" +#include + +namespace Rml { + +FontFaceHandleDefault::FontFaceHandleDefault() +{ + base_layer = nullptr; + metrics = {}; + ft_face = 0; +} + +FontFaceHandleDefault::~FontFaceHandleDefault() +{ + glyphs.clear(); + layers.clear(); +} + +bool FontFaceHandleDefault::Initialize(FontFaceHandleFreetype face, int font_size) +{ + ft_face = face; + + RMLUI_ASSERTMSG(layer_configurations.empty(), "Initialize must only be called once."); + + if (!FreeType::InitialiseFaceHandle(ft_face, font_size, glyphs, metrics)) + { + return false; + } + + // Generate the default layer and layer configuration. + base_layer = GetOrCreateLayer(nullptr); + layer_configurations.push_back(LayerConfiguration{ base_layer }); + + return true; +} + +// Returns the point size of this font face. +int FontFaceHandleDefault::GetSize() const +{ + return metrics.size; +} + +// Returns the pixel height of a lower-case x in this font face. +int FontFaceHandleDefault::GetXHeight() const +{ + return metrics.x_height; +} + +// Returns the default height between this font face's baselines. +int FontFaceHandleDefault::GetLineHeight() const +{ + return metrics.line_height; +} + +// Returns the font's baseline. +int FontFaceHandleDefault::GetBaseline() const +{ + return metrics.baseline; +} + +// Returns the font's glyphs. +const FontGlyphMap& FontFaceHandleDefault::GetGlyphs() const +{ + return glyphs; +} + +float FontFaceHandleDefault::GetUnderline(float& thickness) const +{ + thickness = metrics.underline_thickness; + return metrics.underline_position; +} + +// Returns the width a string will take up if rendered with this handle. +int FontFaceHandleDefault::GetStringWidth(const String& string, Character prior_character) +{ + int width = 0; + for (auto it_string = StringIteratorU8(string); it_string; ++it_string) + { + Character character = *it_string; + + const FontGlyph* glyph = GetOrAppendGlyph(character); + if (!glyph) + continue; + + // Adjust the cursor for the kerning between this character and the previous one. + if (prior_character != Character::Null) + width += GetKerning(prior_character, character); + // Adjust the cursor for this character's advance. + width += glyph->advance; + + prior_character = character; + } + + return width; +} + +// Generates, if required, the layer configuration for a given array of font effects. +int FontFaceHandleDefault::GenerateLayerConfiguration(const FontEffectList& font_effects) +{ + if (font_effects.empty()) + return 0; + + // Check each existing configuration for a match with this arrangement of effects. + int configuration_index = 1; + for (; configuration_index < (int) layer_configurations.size(); ++configuration_index) + { + const LayerConfiguration& configuration = layer_configurations[configuration_index]; + + // Check the size is correct. For a match, there should be one layer in the configuration + // plus an extra for the base layer. + if (configuration.size() != font_effects.size() + 1) + continue; + + // Check through each layer, checking it was created by the same effect as the one we're + // checking. + size_t effect_index = 0; + for (size_t i = 0; i < configuration.size(); ++i) + { + // Skip the base layer ... + if (configuration[i]->GetFontEffect() == nullptr) + continue; + + // If the ith layer's effect doesn't match the equivalent effect, then this + // configuration can't match. + if (configuration[i]->GetFontEffect() != font_effects[effect_index].get()) + break; + + // Check the next one ... + ++effect_index; + } + + if (effect_index == font_effects.size()) + return configuration_index; + } + + // No match, so we have to generate a new layer configuration. + layer_configurations.push_back(LayerConfiguration()); + LayerConfiguration& layer_configuration = layer_configurations.back(); + + bool added_base_layer = false; + + for (size_t i = 0; i < font_effects.size(); ++i) + { + if (!added_base_layer && font_effects[i]->GetLayer() == FontEffect::Layer::Front) + { + layer_configuration.push_back(base_layer); + added_base_layer = true; + } + + FontFaceLayer* new_layer = GetOrCreateLayer(font_effects[i]); + layer_configuration.push_back(new_layer); + } + + // Add the base layer now if we still haven't added it. + if (!added_base_layer) + layer_configuration.push_back(base_layer); + + return (int) (layer_configurations.size() - 1); +} + +// Generates the texture data for a layer (for the texture database). +bool FontFaceHandleDefault::GenerateLayerTexture(UniquePtr& texture_data, Vector2i& texture_dimensions, const FontEffect* font_effect, int texture_id, int handle_version) const +{ + if (handle_version != version) + { + RMLUI_ERRORMSG("While generating font layer texture: Handle version mismatch in texture vs font-face."); + return false; + } + + auto it = std::find_if(layers.begin(), layers.end(), [font_effect](const EffectLayerPair& pair) { return pair.font_effect == font_effect; }); + + if (it == layers.end()) + { + RMLUI_ERRORMSG("While generating font layer texture: Layer id not found."); + return false; + } + + return it->layer->GenerateTexture(texture_data, texture_dimensions, texture_id, glyphs); +} + +// Generates the geometry required to render a single line of text. +int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const String& string, const Vector2f& position, const Colourb& colour, int layer_configuration_index) +{ + int geometry_index = 0; + int line_width = 0; + + RMLUI_ASSERT(layer_configuration_index >= 0); + RMLUI_ASSERT(layer_configuration_index < (int) layer_configurations.size()); + + UpdateLayersOnDirty(); + + // Fetch the requested configuration and generate the geometry for each one. + const LayerConfiguration& layer_configuration = layer_configurations[layer_configuration_index]; + + // Reserve for the common case of one texture per layer. + geometry.reserve(layer_configuration.size()); + + for (size_t i = 0; i < layer_configuration.size(); ++i) + { + FontFaceLayer* layer = layer_configuration[i]; + + Colourb layer_colour; + if (layer == base_layer) + layer_colour = colour; + else + layer_colour = layer->GetColour(); + + const int num_textures = layer->GetNumTextures(); + + if (num_textures == 0) + continue; + + // Resize the geometry list if required. + if ((int)geometry.size() < geometry_index + num_textures) + geometry.resize(geometry_index + num_textures); + + RMLUI_ASSERT(geometry_index < (int)geometry.size()); + + // Bind the textures to the geometries. + for (int tex_index = 0; tex_index < num_textures; ++tex_index) + geometry[geometry_index + tex_index].SetTexture(layer->GetTexture(tex_index)); + + line_width = 0; + Character prior_character = Character::Null; + + geometry[geometry_index].GetIndices().reserve(string.size() * 6); + geometry[geometry_index].GetVertices().reserve(string.size() * 4); + + for (auto it_string = StringIteratorU8(string); it_string; ++it_string) + { + Character character = *it_string; + + const FontGlyph* glyph = GetOrAppendGlyph(character); + if (!glyph) + continue; + + // Adjust the cursor for the kerning between this character and the previous one. + if (prior_character != Character::Null) + line_width += GetKerning(prior_character, character); + + layer->GenerateGeometry(&geometry[geometry_index], character, Vector2f(position.x + line_width, position.y), layer_colour); + + line_width += glyph->advance; + prior_character = character; + } + + geometry_index += num_textures; + } + + // Cull any excess geometry from a previous generation. + geometry.resize(geometry_index); + + return line_width; +} + +bool FontFaceHandleDefault::UpdateLayersOnDirty() +{ + bool result = false; + + // If we are dirty, regenerate all the layers and increment the version + if(is_layers_dirty && base_layer) + { + is_layers_dirty = false; + ++version; + + // Regenerate all the layers. + // Note: The layer regeneration needs to happen in the order in which the layers were created, + // otherwise we may end up cloning a layer which has not yet been regenerated. This means trouble! + for (auto& pair : layers) + { + GenerateLayer(pair.layer.get()); + } + + result = true; + } + + return result; +} + +int FontFaceHandleDefault::GetVersion() const +{ + return version; +} + +bool FontFaceHandleDefault::AppendGlyph(Character character) +{ + bool result = FreeType::AppendGlyph(ft_face, metrics.size, character, glyphs); + return result; +} + +int FontFaceHandleDefault::GetKerning(Character lhs, Character rhs) const +{ + int result = FreeType::GetKerning(ft_face, metrics.size, lhs, rhs); + return result; +} + +const FontGlyph* FontFaceHandleDefault::GetOrAppendGlyph(Character& character, bool look_in_fallback_fonts) +{ + // Don't try to render control characters + if ((char32_t)character < (char32_t)' ') + return nullptr; + + auto it_glyph = glyphs.find(character); + if (it_glyph == glyphs.end()) + { + bool result = AppendGlyph(character); + + if (result) + { + it_glyph = glyphs.find(character); + if (it_glyph == glyphs.end()) + { + RMLUI_ERROR; + return nullptr; + } + + is_layers_dirty = true; + } + else if (look_in_fallback_fonts) + { + const int num_fallback_faces = FontProvider::CountFallbackFontFaces(); + for (int i = 0; i < num_fallback_faces; i++) + { + FontFaceHandleDefault* fallback_face = FontProvider::GetFallbackFontFace(i, metrics.size); + if (!fallback_face || fallback_face == this) + continue; + + const FontGlyph* glyph = fallback_face->GetOrAppendGlyph(character, false); + if (glyph) + { + // Insert the new glyph into our own set of glyphs + auto pair = glyphs.emplace(character, glyph->WeakCopy()); + it_glyph = pair.first; + if(pair.second) + is_layers_dirty = true; + break; + } + } + + // If we still have not found a glyph, use the replacement character. + if(it_glyph == glyphs.end()) + { + character = Character::Replacement; + it_glyph = glyphs.find(character); + if (it_glyph == glyphs.end()) + return nullptr; + } + } + else + { + return nullptr; + } + } + + const FontGlyph* glyph = &it_glyph->second; + return glyph; +} + +// Generates (or shares) a layer derived from a font effect. +FontFaceLayer* FontFaceHandleDefault::GetOrCreateLayer(const SharedPtr& font_effect) +{ + // Search for the font effect layer first, it may have been instanced before as part of a different configuration. + const FontEffect* font_effect_ptr = font_effect.get(); + auto it = std::find_if(layers.begin(), layers.end(), [font_effect_ptr](const EffectLayerPair& pair) { return pair.font_effect == font_effect_ptr; }); + + if (it != layers.end()) + return it->layer.get(); + + // No existing effect matches, generate a new layer for the effect. + layers.push_back(EffectLayerPair{ font_effect_ptr, nullptr }); + auto& layer = layers.back().layer; + + layer = MakeUnique(font_effect); + GenerateLayer(layer.get()); + + return layer.get(); +} + +bool FontFaceHandleDefault::GenerateLayer(FontFaceLayer* layer) +{ + RMLUI_ASSERT(layer); + const FontEffect* font_effect = layer->GetFontEffect(); + bool result = false; + + if (!font_effect) + { + result = layer->Generate(this); + } + else + { + // Determine which, if any, layer the new layer should copy its geometry and textures from. + FontFaceLayer* clone = nullptr; + bool clone_glyph_origins = true; + String generation_key; + size_t fingerprint = font_effect->GetFingerprint(); + + if (!font_effect->HasUniqueTexture()) + { + clone = base_layer; + clone_glyph_origins = false; + } + else + { + auto cache_iterator = layer_cache.find(fingerprint); + if (cache_iterator != layer_cache.end() && cache_iterator->second != layer) + clone = cache_iterator->second; + } + + // Create a new layer. + result = layer->Generate(this, clone, clone_glyph_origins); + + // Cache the layer in the layer cache if it generated its own textures (ie, didn't clone). + if (!clone) + layer_cache[fingerprint] = layer; + } + + return result; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceHandleDefault.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceHandleDefault.h new file mode 100644 index 000000000..e67799da9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceHandleDefault.h @@ -0,0 +1,152 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTFACEHANDLE_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTFACEHANDLE_H + +#include "../../../Include/RmlUi/Core/Traits.h" +#include "../../../Include/RmlUi/Core/FontEffect.h" +#include "../../../Include/RmlUi/Core/FontGlyph.h" +#include "../../../Include/RmlUi/Core/Geometry.h" +#include "../../../Include/RmlUi/Core/Texture.h" +#include "FontTypes.h" + +namespace Rml { + +class FontFaceLayer; + + +/** + @author Peter Curry + */ + +class FontFaceHandleDefault final : public NonCopyMoveable +{ +public: + FontFaceHandleDefault(); + ~FontFaceHandleDefault(); + + bool Initialize(FontFaceHandleFreetype face, int font_size); + + /// Returns the point size of this font face. + int GetSize() const; + /// Returns the pixel height of a lower-case x in this font face. + int GetXHeight() const; + /// Returns the default height between this font face's baselines. + int GetLineHeight() const; + + /// Returns the font's baseline, as a pixel offset from the bottom of the font. + int GetBaseline() const; + + /// Returns the font's underline, as a pixel offset from the bottom of the font. + float GetUnderline(float& thickness) const; + + /// Returns the font's glyphs. + const FontGlyphMap& GetGlyphs() const; + + /// Returns the width a string will take up if rendered with this handle. + /// @param[in] string The string to measure. + /// @param[in] prior_character The optionally-specified character that immediately precedes the string. This may have an impact on the string width due to kerning. + /// @return The width, in pixels, this string will occupy if rendered with this handle. + int GetStringWidth(const String& string, Character prior_character = Character::Null); + + /// Generates, if required, the layer configuration for a given list of font effects. + /// @param[in] font_effects The list of font effects to generate the configuration for. + /// @return The index to use when generating geometry using this configuration. + int GenerateLayerConfiguration(const FontEffectList& font_effects); + /// Generates the texture data for a layer (for the texture database). + /// @param[out] texture_data The pointer to be set to the generated texture data. + /// @param[out] texture_dimensions The dimensions of the texture. + /// @param[in] font_effect The font effect used for the layer. + /// @param[in] texture_id The index of the texture within the layer to generate. + /// @param[in] handle_version The version of the handle data. Function returns false if out of date. + bool GenerateLayerTexture(UniquePtr& texture_data, Vector2i& texture_dimensions, const FontEffect* font_effect, int texture_id, int handle_version) const; + + /// Generates the geometry required to render a single line of text. + /// @param[out] geometry An array of geometries to generate the geometry into. + /// @param[in] string The string to render. + /// @param[in] position The position of the baseline of the first character to render. + /// @param[in] colour The colour to render the text. + /// @return The width, in pixels, of the string geometry. + int GenerateString(GeometryList& geometry, const String& string, const Vector2f& position, const Colourb& colour, int layer_configuration = 0); + + /// Version is changed whenever the layers are dirtied, requiring regeneration of string geometry. + int GetVersion() const; + + +private: + // Build and append glyph to 'glyphs' + bool AppendGlyph(Character character); + + int GetKerning(Character lhs, Character rhs) const; + + /// Retrieve a glyph from the given code point, building and appending a new glyph if not already built. + /// @param[in-out] character The character, can be changed e.g. to the replacement character if no glyph is found. + /// @param[in] look_in_fallback_fonts Look for the glyph in fallback fonts if not found locally, adding it to our glyphs. + /// @return The font glyph for the returned code point. + const FontGlyph* GetOrAppendGlyph(Character& character, bool look_in_fallback_fonts = true); + + // Regenerate layers if dirty, such as after adding new glyphs. + bool UpdateLayersOnDirty(); + + // Create a new layer from the given font effect if it does not already exist. + FontFaceLayer* GetOrCreateLayer(const SharedPtr& font_effect); + + // (Re-)generate a layer in this font face handle. + bool GenerateLayer(FontFaceLayer* layer); + + FontGlyphMap glyphs; + + struct EffectLayerPair { + const FontEffect* font_effect; + UniquePtr layer; + }; + using FontLayerMap = Vector< EffectLayerPair >; + using FontLayerCache = SmallUnorderedMap< size_t, FontFaceLayer* >; + using LayerConfiguration = Vector< FontFaceLayer* >; + using LayerConfigurationList = Vector< LayerConfiguration >; + + // The list of all font layers, index by the effect that instanced them. + FontFaceLayer* base_layer; + FontLayerMap layers; + // Each font layer that generated geometry or textures, indexed by the font-effect's fingerprint key. + FontLayerCache layer_cache; + + int version = 0; + bool is_layers_dirty = false; + + // All configurations currently in use on this handle. New configurations will be generated as required. + LayerConfigurationList layer_configurations; + + FontMetrics metrics; + + FontFaceHandleFreetype ft_face; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceLayer.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceLayer.cpp new file mode 100644 index 000000000..c6b51603f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceLayer.cpp @@ -0,0 +1,261 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontFaceLayer.h" +#include "FontFaceHandleDefault.h" + +namespace Rml { + +FontFaceLayer::FontFaceLayer(const SharedPtr& _effect) : colour(255, 255, 255) +{ + effect = _effect; + if (effect) + colour = effect->GetColour(); +} + +FontFaceLayer::~FontFaceLayer() +{} + +bool FontFaceLayer::Generate(const FontFaceHandleDefault* handle, const FontFaceLayer* clone, bool clone_glyph_origins) +{ + // Clear the old layout if it exists. + { + // @performance: We could be much smarter about this, e.g. such as adding new glyphs to the existing texture layout and textures. + // Right now we re-generate the whole thing, including textures. + texture_layout = TextureLayout{}; + character_boxes.clear(); + textures.clear(); + } + + const FontGlyphMap& glyphs = handle->GetGlyphs(); + + // Generate the new layout. + if (clone) + { + // Clone the geometry and textures from the clone layer. + character_boxes = clone->character_boxes; + + // Copy the cloned layer's textures. + for (size_t i = 0; i < clone->textures.size(); ++i) + textures.push_back(clone->textures[i]); + + // Request the effect (if we have one) and adjust the origins as appropriate. + if (effect && !clone_glyph_origins) + { + for (auto& pair : glyphs) + { + Character character = pair.first; + const FontGlyph& glyph = pair.second; + + auto it = character_boxes.find(character); + if (it == character_boxes.end()) + { + // This can happen if the layers have been dirtied in FontHandleDefault. We will + // probably be regenerated soon, just skip the character for now. + continue; + } + + TextureBox& box = it->second; + + Vector2i glyph_origin(Math::RealToInteger(box.origin.x), Math::RealToInteger(box.origin.y)); + Vector2i glyph_dimensions(Math::RealToInteger(box.dimensions.x), Math::RealToInteger(box.dimensions.y)); + + if (effect->GetGlyphMetrics(glyph_origin, glyph_dimensions, glyph)) + { + box.origin.x = (float)glyph_origin.x; + box.origin.y = (float)glyph_origin.y; + } + else + box.texture_index = -1; + } + } + } + else + { + // Initialise the texture layout for the glyphs. + character_boxes.reserve(glyphs.size()); + for (auto& pair : glyphs) + { + Character character = pair.first; + const FontGlyph& glyph = pair.second; + + Vector2i glyph_origin(0, 0); + Vector2i glyph_dimensions = glyph.bitmap_dimensions; + + // Adjust glyph origin / dimensions for the font effect. + if (effect) + { + if (!effect->GetGlyphMetrics(glyph_origin, glyph_dimensions, glyph)) + continue; + } + + TextureBox box; + box.origin = Vector2f(float(glyph_origin.x + glyph.bearing.x), float(glyph_origin.y - glyph.bearing.y)); + box.dimensions = Vector2f(float(glyph_dimensions.x), float(glyph_dimensions.y)); + + RMLUI_ASSERT(box.dimensions.x >= 0 && box.dimensions.y >= 0); + + character_boxes[character] = box; + + // Add the character's dimensions into the texture layout engine. + texture_layout.AddRectangle((int)character, glyph_dimensions); + } + + constexpr int max_texture_dimensions = 1024; + + // Generate the texture layout; this will position the glyph rectangles efficiently and + // allocate the texture data ready for writing. + if (!texture_layout.GenerateLayout(max_texture_dimensions)) + return false; + + + // Iterate over each rectangle in the layout, copying the glyph data into the rectangle as + // appropriate and generating geometry. + for (int i = 0; i < texture_layout.GetNumRectangles(); ++i) + { + TextureLayoutRectangle& rectangle = texture_layout.GetRectangle(i); + const TextureLayoutTexture& texture = texture_layout.GetTexture(rectangle.GetTextureIndex()); + Character character = (Character)rectangle.GetId(); + RMLUI_ASSERT(character_boxes.find(character) != character_boxes.end()); + TextureBox& box = character_boxes[character]; + + // Set the character's texture index. + box.texture_index = rectangle.GetTextureIndex(); + + // Generate the character's texture coordinates. + box.texcoords[0].x = float(rectangle.GetPosition().x) / float(texture.GetDimensions().x); + box.texcoords[0].y = float(rectangle.GetPosition().y) / float(texture.GetDimensions().y); + box.texcoords[1].x = float(rectangle.GetPosition().x + rectangle.GetDimensions().x) / float(texture.GetDimensions().x); + box.texcoords[1].y = float(rectangle.GetPosition().y + rectangle.GetDimensions().y) / float(texture.GetDimensions().y); + } + + const FontEffect* effect_ptr = effect.get(); + const int handle_version = handle->GetVersion(); + + // Generate the textures. + for (int i = 0; i < texture_layout.GetNumTextures(); ++i) + { + int texture_id = i; + + TextureCallback texture_callback = [handle, effect_ptr, texture_id, handle_version](const String& /*name*/, UniquePtr& data, Vector2i& dimensions) -> bool { + bool result = handle->GenerateLayerTexture(data, dimensions, effect_ptr, texture_id, handle_version); + return result; + }; + + Texture texture; + texture.Set("font-face-layer", texture_callback); + textures.push_back(texture); + } + } + + return true; +} + +// Generates the texture data for a layer (for the texture database). +bool FontFaceLayer::GenerateTexture(UniquePtr& texture_data, Vector2i& texture_dimensions, int texture_id, const FontGlyphMap& glyphs) +{ + if (texture_id < 0 || + texture_id > texture_layout.GetNumTextures()) + return false; + + // Generate the texture data. + texture_data = texture_layout.GetTexture(texture_id).AllocateTexture(); + texture_dimensions = texture_layout.GetTexture(texture_id).GetDimensions(); + + for (int i = 0; i < texture_layout.GetNumRectangles(); ++i) + { + TextureLayoutRectangle& rectangle = texture_layout.GetRectangle(i); + Character character = (Character)rectangle.GetId(); + RMLUI_ASSERT(character_boxes.find(character) != character_boxes.end()); + + TextureBox& box = character_boxes[character]; + + if (box.texture_index != texture_id) + continue; + + auto it = glyphs.find((Character)rectangle.GetId()); + if (it == glyphs.end()) + continue; + + const FontGlyph& glyph = it->second; + + if (effect == nullptr) + { + // Copy the glyph's bitmap data into its allocated texture. + if (glyph.bitmap_data) + { + byte* destination = rectangle.GetTextureData(); + const byte* source = glyph.bitmap_data; + + for (int j = 0; j < glyph.bitmap_dimensions.y; ++j) + { + for (int k = 0; k < glyph.bitmap_dimensions.x; ++k) + destination[k * 4 + 3] = source[k]; + + destination += rectangle.GetTextureStride(); + source += glyph.bitmap_dimensions.x; + } + } + } + else + { + effect->GenerateGlyphTexture(rectangle.GetTextureData(), Vector2i(Math::RealToInteger(box.dimensions.x), Math::RealToInteger(box.dimensions.y)), rectangle.GetTextureStride(), glyph); + } + } + + return true; +} + +// Returns the effect used to generate the layer. +const FontEffect* FontFaceLayer::GetFontEffect() const +{ + return effect.get(); +} + +// Returns on the layer's textures. +const Texture* FontFaceLayer::GetTexture(int index) +{ + RMLUI_ASSERT(index >= 0); + RMLUI_ASSERT(index < GetNumTextures()); + + return &(textures[index]); +} + +// Returns the number of textures employed by this layer. +int FontFaceLayer::GetNumTextures() const +{ + return (int)textures.size(); +} + +// Returns the layer's colour. +const Colourb& FontFaceLayer::GetColour() const +{ + return colour; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceLayer.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceLayer.h new file mode 100644 index 000000000..2f660a8a1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFaceLayer.h @@ -0,0 +1,146 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTFACELAYER_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTFACELAYER_H + +#include "../../../Include/RmlUi/Core/FontGlyph.h" +#include "../../../Include/RmlUi/Core/Geometry.h" +#include "../../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../../Include/RmlUi/Core/Texture.h" +#include "../TextureLayout.h" + +namespace Rml { + +class FontEffect; +class FontFaceHandleDefault; + +/** + A textured layer stored as part of a font face handle. Each handle will have at least a base + layer for the standard font. Further layers can be added to allow rendering of text effects. + + @author Peter Curry + */ + +class FontFaceLayer +{ +public: + FontFaceLayer(const SharedPtr& _effect); + ~FontFaceLayer(); + + /// Generates or re-generates the character and texture data for the layer. + /// @param[in] handle The handle generating this layer. + /// @param[in] effect The effect to initialise the layer with. + /// @param[in] clone The layer to optionally clone geometry and texture data from. + /// @return True if the layer was generated successfully, false if not. + bool Generate(const FontFaceHandleDefault* handle, const FontFaceLayer* clone = nullptr, bool clone_glyph_origins = false); + + /// Generates the texture data for a layer (for the texture database). + /// @param[out] texture_data The pointer to be set to the generated texture data. + /// @param[out] texture_dimensions The dimensions of the texture. + /// @param[in] texture_id The index of the texture within the layer to generate. + /// @param[in] glyphs The glyphs required by the font face handle. + bool GenerateTexture(UniquePtr& texture_data, Vector2i& texture_dimensions, int texture_id, const FontGlyphMap& glyphs); + + /// Generates the geometry required to render a single character. + /// @param[out] geometry An array of geometries this layer will write to. It must be at least as big as the number of textures in this layer. + /// @param[in] character_code The character to generate geometry for. + /// @param[in] position The position of the baseline. + /// @param[in] colour The colour of the string. + inline void GenerateGeometry(Geometry* geometry, const Character character_code, const Vector2f& position, const Colourb& colour) const + { + auto it = character_boxes.find(character_code); + if (it == character_boxes.end()) + return; + + const TextureBox& box = it->second; + + if (box.texture_index < 0) + return; + + // Generate the geometry for the character. + Vector< Vertex >& character_vertices = geometry[box.texture_index].GetVertices(); + Vector< int >& character_indices = geometry[box.texture_index].GetIndices(); + + character_vertices.resize(character_vertices.size() + 4); + character_indices.resize(character_indices.size() + 6); + GeometryUtilities::GenerateQuad( + &character_vertices[0] + (character_vertices.size() - 4), + &character_indices[0] + (character_indices.size() - 6), + Vector2f(position.x + box.origin.x, position.y + box.origin.y).Round(), + box.dimensions, + colour, + box.texcoords[0], + box.texcoords[1], + (int)character_vertices.size() - 4 + ); + } + + /// Returns the effect used to generate the layer. + const FontEffect* GetFontEffect() const; + + /// Returns one of the layer's textures. + const Texture* GetTexture(int index); + /// Returns the number of textures employed by this layer. + int GetNumTextures() const; + + /// Returns the layer's colour. + const Colourb& GetColour() const; + +private: + + + struct TextureBox + { + TextureBox() : texture_index(-1) { } + + // The offset, in pixels, of the baseline from the start of this character's geometry. + Vector2f origin; + // The width and height, in pixels, of this character's geometry. + Vector2f dimensions; + // The texture coordinates for the character's geometry. + Vector2f texcoords[2]; + + // The texture this character renders from. + int texture_index; + }; + + using CharacterMap = UnorderedMap; + using TextureList = Vector; + + SharedPtr effect; + + TextureLayout texture_layout; + + CharacterMap character_boxes; + TextureList textures; + Colourb colour; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFamily.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFamily.cpp new file mode 100644 index 000000000..7cb483976 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFamily.cpp @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontFamily.h" +#include "FontFace.h" + +namespace Rml { + +FontFamily::FontFamily(const String& name) : name(name) +{ +} + +// Returns a handle to the most appropriate font in the family, at the correct size. +FontFaceHandleDefault* FontFamily::GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size) +{ + // Search for a face of the same style, and match the weight as closely as we can. + FontFace* matching_face = nullptr; + for (size_t i = 0; i < font_faces.size(); i++) + { + // If we've found a face matching the style, then ... great! We'll match it regardless of the weight. However, + // if it's a perfect match, then we'll stop looking altogether. + if (font_faces[i]->GetStyle() == style) + { + matching_face = font_faces[i].get(); + + if (font_faces[i]->GetWeight() == weight) + break; + } + } + + if (matching_face == nullptr) + return nullptr; + + return matching_face->GetHandle(size); +} + + +// Adds a new face to the family. +FontFace* FontFamily::AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream) +{ + auto face = MakeUnique(ft_face, style, weight, release_stream); + FontFace* result = face.get(); + + font_faces.push_back(std::move(face)); + + return result; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFamily.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFamily.h new file mode 100644 index 000000000..d084d0a1f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontFamily.h @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTFAMILY_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTFAMILY_H + +#include "FontTypes.h" + +namespace Rml { + +class FontFace; +class FontFaceHandleDefault; + +/** + @author Peter Curry + */ + +class FontFamily +{ +public: + FontFamily(const String& name); + + /// Returns a handle to the most appropriate font in the family, at the correct size. + /// @param[in] style The style of the desired handle. + /// @param[in] weight The weight of the desired handle. + /// @param[in] size The size of desired handle, in points. + /// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise. + FontFaceHandleDefault* GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size); + + + /// Adds a new face to the family. + /// @param[in] ft_face The previously loaded FreeType face. + /// @param[in] style The style of the new face. + /// @param[in] weight The weight of the new face. + /// @param[in] release_stream True if the application must free the face's memory stream. + /// @return True if the face was loaded successfully, false otherwise. + FontFace* AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, bool release_stream); + +protected: + String name; + + using FontFaceList = Vector< UniquePtr >; + FontFaceList font_faces; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontProvider.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontProvider.cpp new file mode 100644 index 000000000..44389cc36 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontProvider.cpp @@ -0,0 +1,197 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FontProvider.h" +#include "FontFace.h" +#include "FontFamily.h" +#include "FreeTypeInterface.h" +#include "../../../Include/RmlUi/Core/Core.h" +#include "../../../Include/RmlUi/Core/FileInterface.h" +#include "../../../Include/RmlUi/Core/Log.h" +#include "../../../Include/RmlUi/Core/StringUtilities.h" +#include + +namespace Rml { + +static FontProvider* g_font_provider = nullptr; + +FontProvider::FontProvider() +{ + RMLUI_ASSERT(!g_font_provider); +} + +FontProvider::~FontProvider() +{ + RMLUI_ASSERT(g_font_provider == this); +} + +bool FontProvider::Initialise() +{ + RMLUI_ASSERT(!g_font_provider); + if (!FreeType::Initialise()) + return false; + g_font_provider = new FontProvider; + return true; +} + +void FontProvider::Shutdown() +{ + RMLUI_ASSERT(g_font_provider); + delete g_font_provider; + g_font_provider = nullptr; + FreeType::Shutdown(); +} + +FontProvider& FontProvider::Get() +{ + RMLUI_ASSERT(g_font_provider); + return *g_font_provider; +} + +FontFaceHandleDefault* FontProvider::GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size) +{ + RMLUI_ASSERTMSG(family == StringUtilities::ToLower(family), "Font family name must be converted to lowercase before entering here."); + + FontFamilyMap& families = Get().font_families; + + auto it = families.find(family); + if (it == families.end()) + return nullptr; + + return it->second->GetFaceHandle(style, weight, size); +} + +int FontProvider::CountFallbackFontFaces() +{ + return (int)Get().fallback_font_faces.size(); +} + +FontFaceHandleDefault* FontProvider::GetFallbackFontFace(int index, int font_size) +{ + auto& faces = FontProvider::Get().fallback_font_faces; + + if (index >= 0 && index < (int)faces.size()) + return faces[index]->GetHandle(font_size); + + return nullptr; +} + + +bool FontProvider::LoadFontFace(const String& file_name, bool fallback_face) +{ + FileInterface* file_interface = GetFileInterface(); + FileHandle handle = file_interface->Open(file_name); + + if (!handle) + { + Log::Message(Log::LT_ERROR, "Failed to load font face from %s, could not open file.", file_name.c_str()); + return false; + } + + size_t length = file_interface->Length(handle); + + byte* buffer = new byte[length]; + file_interface->Read(buffer, length, handle); + file_interface->Close(handle); + + bool result = Get().LoadFontFace(buffer, (int)length, fallback_face, true, file_name); + + return result; +} + + +bool FontProvider::LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face) +{ + const String source = "memory"; + + bool result = Get().LoadFontFace(data, data_size, fallback_face, false, source, font_family, style, weight); + + return result; +} + +bool FontProvider::LoadFontFace(const byte* data, int data_size, bool fallback_face, bool local_data, const String& source, + String font_family, Style::FontStyle style, Style::FontWeight weight) +{ + FontFaceHandleFreetype ft_face = FreeType::LoadFace(data, data_size, source); + + if (!ft_face) + { + if (local_data) + delete[] data; + + Log::Message(Log::LT_ERROR, "Failed to load font face %s (from %s).", font_family.c_str(), source.c_str()); + return false; + } + + if (font_family.empty()) + { + FreeType::GetFaceStyle(ft_face, font_family, style, weight); + } + + if (!AddFace(ft_face, font_family, style, weight, fallback_face, local_data)) + { + Log::Message(Log::LT_ERROR, "Failed to load font face %s (from %s).", font_family.c_str(), source.c_str()); + return false; + } + + Log::Message(Log::LT_INFO, "Loaded font face %s (from %s).", font_family.c_str(), source.c_str()); + return true; +} + +bool FontProvider::AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face, bool release_stream) +{ + String family_lower = StringUtilities::ToLower(family); + FontFamily* font_family = nullptr; + auto it = font_families.find(family_lower); + if (it != font_families.end()) + { + font_family = (FontFamily*)it->second.get(); + } + else + { + auto font_family_ptr = MakeUnique(family_lower); + font_family = font_family_ptr.get(); + font_families[family_lower] = std::move(font_family_ptr); + } + + FontFace* font_face_result = font_family->AddFace(face, style, weight, release_stream); + + if (font_face_result && fallback_face) + { + auto it_fallback_face = std::find(fallback_font_faces.begin(), fallback_font_faces.end(), font_face_result); + if (it_fallback_face == fallback_font_faces.end()) + { + fallback_font_faces.push_back(font_face_result); + } + } + + return static_cast(font_face_result); +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontProvider.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontProvider.h new file mode 100644 index 000000000..110db18ca --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontProvider.h @@ -0,0 +1,97 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTPROVIDER_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTPROVIDER_H + +#include "../../../Include/RmlUi/Core/Types.h" +#include "../../../Include/RmlUi/Core/ComputedValues.h" +#include "FontTypes.h" + +namespace Rml { + +class FontFace; +class FontFamily; +class FontFaceHandleDefault; + +/** + The font provider contains all font families currently in use by RmlUi. + @author Peter Curry + */ + +class FontProvider +{ +public: + static bool Initialise(); + static void Shutdown(); + + /// Returns a handle to a font face that can be used to position and render text. This will return the closest match + /// it can find, but in the event a font family is requested that does not exist, nullptr will be returned instead of a + /// valid handle. + /// @param[in] family The family of the desired font handle. + /// @param[in] style The style of the desired font handle. + /// @param[in] weight The weight of the desired font handle. + /// @param[in] size The size of desired handle, in points. + /// @return A valid handle if a matching (or closely matching) font face was found, nullptr otherwise. + static FontFaceHandleDefault* GetFontFaceHandle(const String& family, Style::FontStyle style, Style::FontWeight weight, int size); + + /// Adds a new font face to the database. The face's family, style and weight will be determined from the face itself. + static bool LoadFontFace(const String& file_name, bool fallback_face); + + /// Adds a new font face from memory. + static bool LoadFontFace(const byte* data, int data_size, const String& font_family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face); + + /// Return the number of fallback font faces. + static int CountFallbackFontFaces(); + + /// Return a font face handle with the given index, at the given font size. + static FontFaceHandleDefault* GetFallbackFontFace(int index, int font_size); + +private: + FontProvider(); + ~FontProvider(); + + static FontProvider& Get(); + + bool LoadFontFace(const byte* data, int data_size, bool fallback_face, bool local_data, const String& source, + String font_family = {}, Style::FontStyle style = Style::FontStyle::Normal, Style::FontWeight weight = Style::FontWeight::Normal); + + bool AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face, bool release_stream); + + using FontFaceList = Vector; + using FontFamilyMap = UnorderedMap< String, UniquePtr>; + + FontFamilyMap font_families; + FontFaceList fallback_font_faces; + + static const String debugger_font_family_name; + +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontTypes.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontTypes.h new file mode 100644 index 000000000..512851a02 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FontTypes.h @@ -0,0 +1,52 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FONTTYPES_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FONTTYPES_H + +#include "../../../Include/RmlUi/Core/Types.h" +#include "../../../Include/RmlUi/Core/ComputedValues.h" +#include "../../../Include/RmlUi/Core/FontGlyph.h" + +namespace Rml { + +using FontFaceHandleFreetype = uintptr_t; + +struct FontMetrics +{ + int size; + int x_height; + int line_height; + int baseline; + + float underline_position; + float underline_thickness; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FreeTypeInterface.cpp b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FreeTypeInterface.cpp new file mode 100644 index 000000000..aa6123fec --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FreeTypeInterface.cpp @@ -0,0 +1,376 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "FreeTypeInterface.h" +#include "../../../Include/RmlUi/Core/Log.h" + +#include +#include +#include FT_FREETYPE_H + +namespace Rml { + +static FT_Library ft_library = nullptr; + + +static bool BuildGlyph(FT_Face ft_face, Character character, FontGlyphMap& glyphs); +static void BuildGlyphMap(FT_Face ft_face, int size, FontGlyphMap& glyphs); +static void GenerateMetrics(FT_Face ft_face, FontMetrics& metrics); + + +bool FreeType::Initialise() +{ + RMLUI_ASSERT(!ft_library); + + FT_Error result = FT_Init_FreeType(&ft_library); + if (result != 0) + { + Log::Message(Log::LT_ERROR, "Failed to initialise FreeType, error %d.", result); + Shutdown(); + return false; + } + + return true; +} + +void FreeType::Shutdown() +{ + if (ft_library != nullptr) + { + FT_Done_FreeType(ft_library); + ft_library = nullptr; + } +} + +// Loads a FreeType face from memory. +FontFaceHandleFreetype FreeType::LoadFace(const byte* data, int data_length, const String& source) +{ + RMLUI_ASSERT(ft_library); + + FT_Face face = nullptr; + int error = FT_New_Memory_Face(ft_library, (const FT_Byte*)data, data_length, 0, &face); + if (error != 0) + { + Log::Message(Log::LT_ERROR, "FreeType error %d while loading face from %s.", error, source.c_str()); + return 0; + } + + // Initialise the character mapping on the face. + if (face->charmap == nullptr) + { + FT_Select_Charmap(face, FT_ENCODING_APPLE_ROMAN); + if (face->charmap == nullptr) + { + Log::Message(Log::LT_ERROR, "Font face (from %s) does not contain a Unicode or Apple Roman character map.", source.c_str()); + FT_Done_Face(face); + return 0; + } + } + + return (FontFaceHandleFreetype)face; +} + +bool FreeType::ReleaseFace(FontFaceHandleFreetype in_face, bool release_stream) +{ + FT_Face face = (FT_Face)in_face; + + FT_Byte* face_memory = face->stream->base; + FT_Error error = FT_Done_Face(face); + + if (release_stream) + delete[] face_memory; + + return (error == 0); +} + +void FreeType::GetFaceStyle(FontFaceHandleFreetype in_face, String& font_family, Style::FontStyle& style, Style::FontWeight& weight) +{ + FT_Face face = (FT_Face)in_face; + + font_family = face->family_name; + style = face->style_flags & FT_STYLE_FLAG_ITALIC ? Style::FontStyle::Italic : Style::FontStyle::Normal; + weight = face->style_flags & FT_STYLE_FLAG_BOLD ? Style::FontWeight::Bold : Style::FontWeight::Normal; +} + + + +// Initialises the handle so it is able to render text. +bool FreeType::InitialiseFaceHandle(FontFaceHandleFreetype face, int font_size, FontGlyphMap& glyphs, FontMetrics& metrics) +{ + FT_Face ft_face = (FT_Face)face; + + metrics.size = font_size; + + // Set the character size on the font face. + FT_Error error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0); + if (error != 0) + { + Log::Message(Log::LT_ERROR, "Unable to set the character size '%d' on the font face '%s %s'.", font_size, ft_face->family_name, ft_face->style_name); + return false; + } + + // Construct the initial list of glyphs. + BuildGlyphMap(ft_face, font_size, glyphs); + + // Generate the metrics for the handle. + GenerateMetrics(ft_face, metrics); + + return true; +} + +bool FreeType::AppendGlyph(FontFaceHandleFreetype face, int font_size, Character character, FontGlyphMap& glyphs) +{ + FT_Face ft_face = (FT_Face)face; + + RMLUI_ASSERT(glyphs.find(character) == glyphs.end()); + RMLUI_ASSERT(ft_face); + + // Set face size again in case it was used at another size in another font face handle. + FT_Error error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0); + if (error != 0) + { + Log::Message(Log::LT_ERROR, "Unable to set the character size '%d' on the font face '%s %s'.", font_size, ft_face->family_name, ft_face->style_name); + return false; + } + + if (!BuildGlyph(ft_face, character, glyphs)) + return false; + + return true; +} + + +int FreeType::GetKerning(FontFaceHandleFreetype face, int font_size, Character lhs, Character rhs) +{ + FT_Face ft_face = (FT_Face)face; + + if (!FT_HAS_KERNING(ft_face)) + return 0; + + // Set face size again in case it was used at another size in another font face handle. + FT_Error ft_error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0); + if (ft_error) + return 0; + + FT_Vector ft_kerning; + + ft_error = FT_Get_Kerning( + ft_face, + FT_Get_Char_Index(ft_face, (FT_ULong)lhs), + FT_Get_Char_Index(ft_face, (FT_ULong)rhs), + FT_KERNING_DEFAULT, + &ft_kerning + ); + + if (ft_error) + return 0; + + int kerning = ft_kerning.x >> 6; + return kerning; +} + + + +static void BuildGlyphMap(FT_Face ft_face, int size, FontGlyphMap& glyphs) +{ + glyphs.reserve(128); + + // Add the ASCII characters now. Other characters are added later as needed. + FT_ULong code_min = 32; + FT_ULong code_max = 126; + + for (FT_ULong character_code = code_min; character_code <= code_max; ++character_code) + BuildGlyph(ft_face, (Character)character_code, glyphs); + + // Add a replacement character for rendering unknown characters. + Character replacement_character = Character::Replacement; + auto it = glyphs.find(replacement_character); + if (it == glyphs.end()) + { + FontGlyph glyph; + glyph.dimensions = { size / 3, (size * 2) / 3 }; + glyph.bitmap_dimensions = glyph.dimensions; + glyph.advance = glyph.dimensions.x + 2; + glyph.bearing = { 1, glyph.dimensions.y }; + + glyph.bitmap_owned_data.reset(new byte[glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y]); + glyph.bitmap_data = glyph.bitmap_owned_data.get(); + + for (int y = 0; y < glyph.bitmap_dimensions.y; y++) + { + for (int x = 0; x < glyph.bitmap_dimensions.x; x++) + { + constexpr int stroke = 1; + int i = y * glyph.bitmap_dimensions.x + x; + bool near_edge = (x < stroke || x >= glyph.bitmap_dimensions.x - stroke || y < stroke || y >= glyph.bitmap_dimensions.y - stroke); + glyph.bitmap_owned_data[i] = (near_edge ? 0xdd : 0); + } + } + + glyphs[replacement_character] = std::move(glyph); + } +} + +static bool BuildGlyph(FT_Face ft_face, Character character, FontGlyphMap& glyphs) +{ + int index = FT_Get_Char_Index(ft_face, (FT_ULong)character); + if (index == 0) + return false; + + FT_Error error = FT_Load_Glyph(ft_face, index, 0); + if (error != 0) + { + Log::Message(Log::LT_WARNING, "Unable to load glyph for character '%u' on the font face '%s %s'; error code: %d.", character, ft_face->family_name, ft_face->style_name, error); + return false; + } + + error = FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL); + if (error != 0) + { + Log::Message(Log::LT_WARNING, "Unable to render glyph for character '%u' on the font face '%s %s'; error code: %d.", character, ft_face->family_name, ft_face->style_name, error); + return false; + } + + auto result = glyphs.emplace(character, FontGlyph{}); + if (!result.second) + { + Log::Message(Log::LT_WARNING, "Glyph character '%u' is already loaded in the font face '%s %s'.", character, ft_face->family_name, ft_face->style_name); + return false; + } + + FontGlyph& glyph = result.first->second; + + FT_GlyphSlot ft_glyph = ft_face->glyph; + + // Set the glyph's dimensions. + glyph.dimensions.x = ft_glyph->metrics.width >> 6; + glyph.dimensions.y = ft_glyph->metrics.height >> 6; + + // Set the glyph's bearing. + glyph.bearing.x = ft_glyph->metrics.horiBearingX >> 6; + glyph.bearing.y = ft_glyph->metrics.horiBearingY >> 6; + + // Set the glyph's advance. + glyph.advance = ft_glyph->metrics.horiAdvance >> 6; + + // Set the glyph's bitmap dimensions. + glyph.bitmap_dimensions.x = ft_glyph->bitmap.width; + glyph.bitmap_dimensions.y = ft_glyph->bitmap.rows; + + // Copy the glyph's bitmap data from the FreeType glyph handle to our glyph handle. + if (glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y != 0) + { + // Check the pixel mode is supported. + if (ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO && + ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY) + { + glyph.bitmap_owned_data.reset(); + glyph.bitmap_data = nullptr; + Log::Message(Log::LT_WARNING, "Unable to render glyph on the font face '%s %s'; unsupported pixel mode (%d).", ft_glyph->face->family_name, ft_glyph->face->style_name, ft_glyph->bitmap.pixel_mode); + } + else + { + glyph.bitmap_owned_data.reset(new byte[glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y]); + glyph.bitmap_data = glyph.bitmap_owned_data.get(); + + const byte* source_bitmap = ft_glyph->bitmap.buffer; + byte* destination_bitmap = glyph.bitmap_owned_data.get(); + + // Copy the bitmap data into the newly-allocated space on our glyph. + switch (ft_glyph->bitmap.pixel_mode) + { + // Unpack 1-bit data into 8-bit. + case FT_PIXEL_MODE_MONO: + { + for (int i = 0; i < glyph.bitmap_dimensions.y; ++i) + { + int mask = 0x80; + const byte* source_byte = source_bitmap; + for (int j = 0; j < glyph.bitmap_dimensions.x; ++j) + { + if ((*source_byte & mask) == mask) + destination_bitmap[j] = 255; + else + destination_bitmap[j] = 0; + + mask >>= 1; + if (mask <= 0) + { + mask = 0x80; + ++source_byte; + } + } + + destination_bitmap += glyph.bitmap_dimensions.x; + source_bitmap += ft_glyph->bitmap.pitch; + } + } + break; + + // Directly copy 8-bit data. + case FT_PIXEL_MODE_GRAY: + { + for (int i = 0; i < glyph.bitmap_dimensions.y; ++i) + { + memcpy(destination_bitmap, source_bitmap, glyph.bitmap_dimensions.x); + destination_bitmap += glyph.bitmap_dimensions.x; + source_bitmap += ft_glyph->bitmap.pitch; + } + } + break; + } + } + } + else + { + glyph.bitmap_owned_data.reset(); + glyph.bitmap_data = nullptr; + } + + return true; +} + +static void GenerateMetrics(FT_Face ft_face, FontMetrics& metrics) +{ + metrics.line_height = ft_face->size->metrics.height >> 6; + metrics.baseline = metrics.line_height - (ft_face->size->metrics.ascender >> 6); + + metrics.underline_position = FT_MulFix(ft_face->underline_position, ft_face->size->metrics.y_scale) / float(1 << 6); + metrics.underline_thickness = FT_MulFix(ft_face->underline_thickness, ft_face->size->metrics.y_scale) / float(1 << 6); + metrics.underline_thickness = Math::Max(metrics.underline_thickness, 1.0f); + + // Determine the x-height of this font face. + int index = FT_Get_Char_Index(ft_face, 'x'); + if (FT_Load_Glyph(ft_face, index, 0) == 0) + metrics.x_height = ft_face->glyph->metrics.height >> 6; + else + metrics.x_height = 0; +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/FontEngineDefault/FreeTypeInterface.h b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FreeTypeInterface.h new file mode 100644 index 000000000..0fc207497 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineDefault/FreeTypeInterface.h @@ -0,0 +1,63 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_FONTENGINEDEFAULT_FREETYPEINTERFACE_H +#define RMLUI_CORE_FONTENGINEDEFAULT_FREETYPEINTERFACE_H + +#include "FontTypes.h" + +namespace Rml { + +namespace FreeType { + +// Initialize FreeType library. +bool Initialise(); +// Shutdown FreeType library. +void Shutdown(); + +// Loads a FreeType face from memory, 'source' is only used for logging. +FontFaceHandleFreetype LoadFace(const byte* data, int data_length, const String& source); + +// Releases the FreeType face. +bool ReleaseFace(FontFaceHandleFreetype face, bool release_stream); + +// Retrieves the font family, style and weight of the given font face. +void GetFaceStyle(FontFaceHandleFreetype face, String& font_family, Style::FontStyle& style, Style::FontWeight& weight); + +// Initializes a face for a given font size. Glyphs are filled with the ASCII subset, and the font face metrics are set. +bool InitialiseFaceHandle(FontFaceHandleFreetype face, int font_size, FontGlyphMap& glyphs, FontMetrics& metrics); + +// Build a new glyph representing the given code point and append to 'glyphs'. +bool AppendGlyph(FontFaceHandleFreetype face, int font_size, Character character, FontGlyphMap& glyphs); + +// Returns the kerning between two characters. +int GetKerning(FontFaceHandleFreetype face, int font_size, Character lhs, Character rhs); + +} +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/FontEngineInterface.cpp b/thirdparty/RmlUi/Source/Core/FontEngineInterface.cpp new file mode 100644 index 000000000..ef7a94721 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/FontEngineInterface.cpp @@ -0,0 +1,104 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/FontEngineInterface.h" + +namespace Rml { + +FontEngineInterface::FontEngineInterface() +{ +} + +FontEngineInterface::~FontEngineInterface() +{ +} + +bool FontEngineInterface::LoadFontFace(const String& /*file_name*/, bool /*fallback_face*/) +{ + return false; +} + +bool FontEngineInterface::LoadFontFace(const byte* /*data*/, int /*data_size*/, const String& /*font_family*/, + Style::FontStyle /*style*/, Style::FontWeight /*weight*/, bool /*fallback_face*/) +{ + return false; +} + +FontFaceHandle FontEngineInterface::GetFontFaceHandle(const String& /*family*/, Style::FontStyle /*style*/, + Style::FontWeight /*weight*/, int /*size*/) +{ + return 0; +} + +FontEffectsHandle FontEngineInterface::PrepareFontEffects(FontFaceHandle /*handle*/, const FontEffectList& /*font_effects*/) +{ + return 0; +} + +int FontEngineInterface::GetSize(FontFaceHandle /*handle*/) +{ + return 0; +} + +int FontEngineInterface::GetXHeight(FontFaceHandle /*handle*/) +{ + return 0; +} + +int FontEngineInterface::GetLineHeight(FontFaceHandle /*handle*/) +{ + return 0; +} + +int FontEngineInterface::GetBaseline(FontFaceHandle /*handle*/) +{ + return 0; +} + +float FontEngineInterface::GetUnderline(FontFaceHandle /*handle*/, float& /*thickness*/) +{ + return 0; +} + +int FontEngineInterface::GetStringWidth(FontFaceHandle /*handle*/, const String& /*string*/, Character /*prior_character*/) +{ + return 0; +} + +int FontEngineInterface::GenerateString(FontFaceHandle /*face_handle*/, FontEffectsHandle /*font_effects_handle*/, const String& /*string*/, + const Vector2f& /*position*/, const Colourb& /*colour*/, GeometryList& /*geometry*/) +{ + return 0; +} + +int FontEngineInterface::GetVersion(FontFaceHandle /*handle*/) +{ + return 0; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Geometry.cpp b/thirdparty/RmlUi/Source/Core/Geometry.cpp new file mode 100644 index 000000000..f69cca01c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Geometry.cpp @@ -0,0 +1,199 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/RenderInterface.h" +#include "GeometryDatabase.h" +#include + + +namespace Rml { + +Geometry::Geometry(Element* host_element) : host_element(host_element) +{ + database_handle = GeometryDatabase::Insert(this); +} + +Geometry::Geometry(Context* host_context) : host_context(host_context) +{ + database_handle = GeometryDatabase::Insert(this); +} + +Geometry::Geometry(Geometry&& other) +{ + MoveFrom(other); + database_handle = GeometryDatabase::Insert(this); +} + +Geometry& Geometry::operator=(Geometry&& other) +{ + MoveFrom(other); + // Keep the database handles from construction unchanged, they are tied to the *this* pointer and should not change. + return *this; +} + +void Geometry::MoveFrom(Geometry& other) +{ + host_context = std::exchange(other.host_context, nullptr); + host_element = std::exchange(other.host_element, nullptr); + + vertices = std::move(other.vertices); + indices = std::move(other.indices); + + texture = std::exchange(other.texture, nullptr); + + compiled_geometry = std::exchange(other.compiled_geometry, 0); + compile_attempted = std::exchange(other.compile_attempted, false); +} + +Geometry::~Geometry() +{ + GeometryDatabase::Erase(database_handle); + + Release(); +} + +// Set the host element for this geometry; this should be passed in the constructor if possible. +void Geometry::SetHostElement(Element* _host_element) +{ + if (host_element == _host_element) + return; + + if (host_element != nullptr) + { + Release(); + host_context = nullptr; + } + + host_element = _host_element; +} + +void Geometry::Render(const Vector2f& translation) +{ + RenderInterface* const render_interface = GetRenderInterface(); + if (!render_interface) + return; + + // Render our compiled geometry if possible. + if (compiled_geometry) + { + RMLUI_ZoneScopedN("RenderCompiled"); + render_interface->RenderCompiledGeometry(compiled_geometry, translation); + } + // Otherwise, if we actually have geometry, try to compile it if we haven't already done so, otherwise render it in + // immediate mode. + else + { + if (vertices.empty() || + indices.empty()) + return; + + RMLUI_ZoneScopedN("RenderGeometry"); + + if (!compile_attempted) + { + compile_attempted = true; + compiled_geometry = render_interface->CompileGeometry(&vertices[0], (int)vertices.size(), &indices[0], (int)indices.size(), texture ? texture->GetHandle(render_interface) : 0); + + // If we managed to compile the geometry, we can clear the local copy of vertices and indices and + // immediately render the compiled version. + if (compiled_geometry) + { + render_interface->RenderCompiledGeometry(compiled_geometry, translation); + return; + } + } + + // Either we've attempted to compile before (and failed), or the compile we just attempted failed; either way, + // render the uncompiled version. + render_interface->RenderGeometry(&vertices[0], (int)vertices.size(), &indices[0], (int)indices.size(), texture ? texture->GetHandle(GetRenderInterface()) : 0, translation); + } +} + +// Returns the geometry's vertices. If these are written to, Release() should be called to force a recompile. +Vector< Vertex >& Geometry::GetVertices() +{ + return vertices; +} + +// Returns the geometry's indices. If these are written to, Release() should be called to force a recompile. +Vector< int >& Geometry::GetIndices() +{ + return indices; +} + +// Gets the geometry's texture. +const Texture* Geometry::GetTexture() const +{ + return texture; +} + +// Sets the geometry's texture. +void Geometry::SetTexture(const Texture* _texture) +{ + texture = _texture; + Release(); +} + +void Geometry::Release(bool clear_buffers) +{ + if (compiled_geometry) + { + GetRenderInterface()->ReleaseCompiledGeometry(compiled_geometry); + compiled_geometry = 0; + } + + compile_attempted = false; + + if (clear_buffers) + { + vertices.clear(); + indices.clear(); + } +} + +// Returns the host context's render interface. +RenderInterface* Geometry::GetRenderInterface() +{ + if (!host_context) + { + if (host_element) + host_context = host_element->GetContext(); + } + + if (host_context) + return host_context->GetRenderInterface(); + else + return ::Rml::GetRenderInterface(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/GeometryDatabase.cpp b/thirdparty/RmlUi/Source/Core/GeometryDatabase.cpp new file mode 100644 index 000000000..3eb6f02b8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/GeometryDatabase.cpp @@ -0,0 +1,183 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "GeometryDatabase.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include + +namespace Rml { + +namespace GeometryDatabase { + +class Database { +public: + Database() { + constexpr size_t reserve_size = 512; + geometry_list.reserve(reserve_size); + free_list.reserve(reserve_size); + } + + ~Database() { +#ifdef RMLUI_TESTS_ENABLED + RMLUI_ASSERT(geometry_list.size() == free_list.size()); + std::sort(free_list.begin(), free_list.end()); + for (size_t i = 0; i < free_list.size(); i++) + { + RMLUI_ASSERT(i == free_list[i]); + } +#endif + } + + GeometryDatabaseHandle insert(Geometry* value) + { + GeometryDatabaseHandle handle; + if (free_list.empty()) + { + handle = GeometryDatabaseHandle(geometry_list.size()); + geometry_list.push_back(value); + } + else + { + handle = free_list.back(); + free_list.pop_back(); + geometry_list[handle] = value; + } + return handle; + } + + void erase(GeometryDatabaseHandle handle) + { + free_list.push_back(handle); + } + + // Iterate over every item in the database, skipping free slots. + template + void for_each(Func func) + { + std::sort(free_list.begin(), free_list.end()); + + size_t i_begin_next = 0; + for (GeometryDatabaseHandle freelist_entry : free_list) + { + const size_t i_end = size_t(freelist_entry); + const size_t i_begin = i_begin_next; + i_begin_next = i_end + 1; + + for (size_t i = i_begin; i < i_end; i++) + func(geometry_list[i]); + } + + for (size_t i = i_begin_next; i < geometry_list.size(); i++) + func(geometry_list[i]); + } + +private: + // List of all active geometry, in addition to free slots. + // Free slots (as defined by the 'free_list') may contain dangling pointers and must not be dereferenced. + Vector geometry_list; + // Declares free slots in the 'geometry_list' as indices. + Vector free_list; +}; + + +static Database geometry_database; + +GeometryDatabaseHandle Insert(Geometry* geometry) +{ + return geometry_database.insert(geometry); +} + +void Erase(GeometryDatabaseHandle handle) +{ + geometry_database.erase(handle); +} + +void ReleaseAll() +{ + geometry_database.for_each([](Geometry* geometry) { + geometry->Release(); + }); +} + + + +#ifdef RMLUI_TESTS_ENABLED + +static class TestGeometryDatabase { +private: + Vector geometry_list; + + bool list_database_equivalent() + { + int i = 0; + bool result = true; + GetDatabase().for_each([this, &i, &result](Geometry* geometry) { + result &= (geometry == &geometry_list[i++]); + }); + return result; + } + +public: + TestGeometryDatabase() : geometry_list(10) + { + bool result = true; + + int i = 0; + for (auto& geometry : geometry_list) + geometry.GetIndices().push_back(i++); + + result &= list_database_equivalent(); + + geometry_list.reserve(2000); + result &= list_database_equivalent(); + + geometry_list.erase(geometry_list.begin() + 5); + result &= list_database_equivalent(); + + std::swap(geometry_list.front(), geometry_list.back()); + geometry_list.pop_back(); + result &= list_database_equivalent(); + + std::swap(geometry_list.front(), geometry_list.back()); + result &= list_database_equivalent(); + + geometry_list.emplace_back(); + result &= list_database_equivalent(); + + geometry_list.clear(); + result &= list_database_equivalent(); + + RMLUI_ASSERT(result); + } + +} test_geometry_database; + +#endif + +} +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/GeometryDatabase.h b/thirdparty/RmlUi/Source/Core/GeometryDatabase.h new file mode 100644 index 000000000..35f718d95 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/GeometryDatabase.h @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_GEOMETRYDATABASE_H +#define RMLUI_CORE_GEOMETRYDATABASE_H + +#include + +namespace Rml { + +class Geometry; +using GeometryDatabaseHandle = uint32_t; + +/** + The geometry database stores a reference to all active geometry. + + The intention is for the user to be able to re-compile all geometry in use. + + It is expected that every Insert() call is followed (at some later time) by + exactly one Erase() call with the same handle value. +*/ + +namespace GeometryDatabase { + + GeometryDatabaseHandle Insert(Geometry* geometry); + void Erase(GeometryDatabaseHandle handle); + + void ReleaseAll(); + +} + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/GeometryUtilities.cpp b/thirdparty/RmlUi/Source/Core/GeometryUtilities.cpp new file mode 100644 index 000000000..804cf34f8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/GeometryUtilities.cpp @@ -0,0 +1,110 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/Geometry.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +GeometryUtilities::GeometryUtilities() +{ +} + +GeometryUtilities::~GeometryUtilities() +{ +} + +// Generates a quad from a position, size and colour. +void GeometryUtilities::GenerateQuad(Vertex* vertices, int* indices, const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour, int index_offset) +{ + GenerateQuad(vertices, indices, origin, dimensions, colour, Vector2f(0, 0), Vector2f(1, 1), index_offset); +} + +// Generates a quad from a position, size, colour and texture coordinates. +void GeometryUtilities::GenerateQuad(Vertex* vertices, int* indices, const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour, const Vector2f& top_left_texcoord, const Vector2f& bottom_right_texcoord, int index_offset) +{ + vertices[0].position = origin; + vertices[0].colour = colour; + vertices[0].tex_coord = top_left_texcoord; + + vertices[1].position = Vector2f(origin.x + dimensions.x, origin.y); + vertices[1].colour = colour; + vertices[1].tex_coord = Vector2f(bottom_right_texcoord.x, top_left_texcoord.y); + + vertices[2].position = origin + dimensions; + vertices[2].colour = colour; + vertices[2].tex_coord = bottom_right_texcoord; + + vertices[3].position = Vector2f(origin.x, origin.y + dimensions.y); + vertices[3].colour = colour; + vertices[3].tex_coord = Vector2f(top_left_texcoord.x, bottom_right_texcoord.y); + + indices[0] = index_offset + 0; + indices[1] = index_offset + 3; + indices[2] = index_offset + 1; + + indices[3] = index_offset + 1; + indices[4] = index_offset + 3; + indices[5] = index_offset + 2; +} + +// Generates the geometry required to render a line above, below or through a line of text. +void GeometryUtilities::GenerateLine(FontFaceHandle font_face_handle, Geometry* geometry, const Vector2f& position, int width, Style::TextDecoration height, const Colourb& colour) +{ + Vector< Vertex >& line_vertices = geometry->GetVertices(); + Vector< int >& line_indices = geometry->GetIndices(); + float underline_thickness = 0; + float underline_position = GetFontEngineInterface()->GetUnderline(font_face_handle, underline_thickness); + int size = GetFontEngineInterface()->GetSize(font_face_handle); + int x_height = GetFontEngineInterface()->GetXHeight(font_face_handle); + + float offset; + switch (height) + { + case Style::TextDecoration::Underline: offset = -underline_position; break; + case Style::TextDecoration::Overline: offset = -underline_position - (float)size; break; + case Style::TextDecoration::LineThrough: offset = -0.65f * (float)x_height; break; + default: return; + } + + line_vertices.resize(line_vertices.size() + 4); + line_indices.resize(line_indices.size() + 6); + GeometryUtilities::GenerateQuad( + &line_vertices[0] + ((int)line_vertices.size() - 4), + &line_indices[0] + ((int)line_indices.size() - 6), + Vector2f(position.x, position.y + offset).Round(), + Vector2f((float) width, underline_thickness), + colour, + (int)line_vertices.size() - 4 + ); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/IdNameMap.h b/thirdparty/RmlUi/Source/Core/IdNameMap.h new file mode 100644 index 000000000..83096004b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/IdNameMap.h @@ -0,0 +1,116 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_IDNAMEMAP_H +#define RMLUI_CORE_IDNAMEMAP_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Types.h" +#include + +namespace Rml { + +template +class IdNameMap { + Vector name_map; // IDs are indices into the name_map + UnorderedMap reverse_map; + +protected: + IdNameMap(size_t num_ids_to_reserve) { + static_assert((int)ID::Invalid == 0, "Invalid id must be zero"); + name_map.reserve(num_ids_to_reserve); + reverse_map.reserve(num_ids_to_reserve); + AddPair(ID::Invalid, "invalid"); + } + +public: + void AddPair(ID id, const String& name) + { + // Should only be used for defined IDs + if ((size_t)id >= name_map.size()) + name_map.resize(1 + (size_t)id); + name_map[(size_t)id] = name; + bool inserted = reverse_map.emplace(name, id).second; + RMLUI_ASSERT(inserted); + (void)inserted; + } + + void AssertAllInserted(ID number_of_defined_ids) const + { + std::ptrdiff_t cnt = std::count_if(name_map.begin(), name_map.end(), [](const String& name) { return !name.empty(); }); + RMLUI_ASSERT(cnt == (std::ptrdiff_t)number_of_defined_ids && reverse_map.size() == (size_t)number_of_defined_ids); + (void)number_of_defined_ids; + (void)cnt; + } + + ID GetId(const String& name) const + { + auto it = reverse_map.find(name); + if (it != reverse_map.end()) + return it->second; + return ID::Invalid; + } + const String& GetName(ID id) const + { + if (static_cast(id) < name_map.size()) + return name_map[static_cast(id)]; + return name_map[static_cast(ID::Invalid)]; + } + + ID GetOrCreateId(const String& name) + { + // All predefined properties must be set before possibly adding custom properties here + RMLUI_ASSERT(name_map.size() == reverse_map.size()); + + ID next_id = static_cast(name_map.size()); + + // Only insert if not already in list + auto pair = reverse_map.emplace(name, next_id); + const auto& it = pair.first; + bool inserted = pair.second; + + if (inserted) + name_map.push_back(name); + + // Return the property id that already existed, or the new one if inserted + return it->second; + } +}; + +class PropertyIdNameMap : public IdNameMap { +public: + PropertyIdNameMap(size_t reserve_num_properties) : IdNameMap(reserve_num_properties) {} +}; + +class ShorthandIdNameMap : public IdNameMap { +public: + ShorthandIdNameMap(size_t reserve_num_shorthands) : IdNameMap(reserve_num_shorthands) {} +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/LayoutBlockBox.cpp b/thirdparty/RmlUi/Source/Core/LayoutBlockBox.cpp new file mode 100644 index 000000000..f76810758 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutBlockBox.cpp @@ -0,0 +1,703 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LayoutBlockBox.h" +#include "LayoutBlockBoxSpace.h" +#include "LayoutEngine.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/ElementScroll.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include + +namespace Rml { + +// Creates a new block box for rendering a block element. +LayoutBlockBox::LayoutBlockBox(LayoutEngine* _layout_engine, LayoutBlockBox* _parent, Element* _element) : position(0, 0) +{ + RMLUI_ZoneScoped; + + space = new LayoutBlockBoxSpace(this); + + layout_engine = _layout_engine; + parent = _parent; + + context = BLOCK; + element = _element; + interrupted_chain = nullptr; + + box_cursor = 0; + vertical_overflow = false; + + // Get our offset root from our parent, if it has one; otherwise, our element is the offset parent. + if (parent != nullptr && + parent->offset_root->GetElement() != nullptr) + offset_root = parent->offset_root; + else + offset_root = this; + + // Determine the offset parent for this element. + LayoutBlockBox* self_offset_parent; + if (parent != nullptr && + parent->offset_parent->GetElement() != nullptr) + self_offset_parent = parent->offset_parent; + else + self_offset_parent = this; + + // Determine the offset parent for our children. + if (parent != nullptr && + parent->offset_parent->GetElement() != nullptr && + (element == nullptr || element->GetPosition() == Style::Position::Static)) + offset_parent = parent->offset_parent; + else + offset_parent = this; + + // Build the box for our element, and position it if we can. + if (parent != nullptr) + { + space->ImportSpace(*parent->space); + + // Build our box if possible; if not, it will have to be set up manually. + layout_engine->BuildBox(box, min_height, max_height, parent, element); + + // Position ourselves within our containing block (if we have a valid offset parent). + if (parent->GetElement() != nullptr) + { + if (self_offset_parent != this) + { + // Get the next position within our offset parent's containing block. + parent->PositionBlockBox(position, box, element ? element->GetComputedValues().clear : Style::Clear::None); + element->SetOffset(position - (self_offset_parent->GetPosition() - offset_root->GetPosition()), self_offset_parent->GetElement()); + } + else + element->SetOffset(position, nullptr); + } + } + + if (element != nullptr) + { + const auto& computed = element->GetComputedValues(); + wrap_content = computed.white_space != Style::WhiteSpace::Nowrap; + + // Determine if this element should have scrollbars or not, and create them if so. + overflow_x_property = computed.overflow_x; + overflow_y_property = computed.overflow_y; + + if (overflow_x_property == Style::Overflow::Scroll) + element->GetElementScroll()->EnableScrollbar(ElementScroll::HORIZONTAL, box.GetSize(Box::PADDING).x); + else + element->GetElementScroll()->DisableScrollbar(ElementScroll::HORIZONTAL); + + if (overflow_y_property == Style::Overflow::Scroll) + element->GetElementScroll()->EnableScrollbar(ElementScroll::VERTICAL, box.GetSize(Box::PADDING).x); + else + element->GetElementScroll()->DisableScrollbar(ElementScroll::VERTICAL); + } + else + { + wrap_content = true; + overflow_x_property = Style::Overflow::Visible; + overflow_y_property = Style::Overflow::Visible; + } +} + +// Creates a new block box in an inline context. +LayoutBlockBox::LayoutBlockBox(LayoutEngine* _layout_engine, LayoutBlockBox* _parent) : position(-1, -1) +{ + layout_engine = _layout_engine; + parent = _parent; + offset_parent = parent->offset_parent; + offset_root = parent->offset_root; + + space = _parent->space; + + context = INLINE; + line_boxes.push_back(new LayoutLineBox(this)); + wrap_content = parent->wrap_content; + + element = nullptr; + interrupted_chain = nullptr; + + box_cursor = 0; + vertical_overflow = false; + + layout_engine->BuildBox(box, min_height, max_height, parent, nullptr); + parent->PositionBlockBox(position, box, Style::Clear::None); + box.SetContent(Vector2f(box.GetSize(Box::CONTENT).x, -1)); + + // Reset the min and max heights; they're not valid for inline block boxes. + min_height = 0; + max_height = FLT_MAX; +} + +// Releases the block box. +LayoutBlockBox::~LayoutBlockBox() +{ + for (size_t i = 0; i < block_boxes.size(); i++) + delete block_boxes[i]; + + for (size_t i = 0; i < line_boxes.size(); i++) + delete line_boxes[i]; + + if (context == BLOCK) + delete space; +} + +// Closes the box. +LayoutBlockBox::CloseResult LayoutBlockBox::Close() +{ + // If the last child of this block box is an inline box, then we haven't closed it; close it now! + if (context == BLOCK) + { + CloseResult result = CloseInlineBlockBox(); + if (result != OK) + return LAYOUT_SELF; + } + // Otherwise, we're an inline context box; so close our last line, which will still be open. + else + { + line_boxes.back()->Close(); + + // Expand our content area if any line boxes had to push themselves out. + Vector2f content_area = box.GetSize(); + for (size_t i = 0; i < line_boxes.size(); i++) + content_area.x = Math::Max(content_area.x, line_boxes[i]->GetDimensions().x); + + box.SetContent(content_area); + } + + // Set this box's height, if necessary. + if (box.GetSize(Box::CONTENT).y < 0) + { + Vector2f content_area = box.GetSize(); + content_area.y = Math::Clamp(box_cursor, min_height, max_height); + + if (element != nullptr) + content_area.y = Math::Max(content_area.y, space->GetDimensions().y); + + box.SetContent(content_area); + } + + // Set the computed box on the element. + if (element != nullptr) + { + if (context == BLOCK) + { + // Calculate the dimensions of the box's *internal* content; this is the tightest-fitting box around all of the + // internal elements, plus this element's padding. + Vector2f content_box(0, 0); + + for (size_t i = 0; i < block_boxes.size(); i++) + content_box.x = Math::Max(content_box.x, block_boxes[i]->GetBox().GetSize(Box::MARGIN).x); + + // Check how big our floated area is. + Vector2f space_box = space->GetDimensions(); + content_box.x = Math::Max(content_box.x, space_box.x); + + // If our content is larger than our window, we can enable the horizontal scrollbar if + // we're set to auto-scrollbars. If we're set to always use scrollbars, then the horiontal + // scrollbar will already have been enabled in the constructor. + if (content_box.x > box.GetSize().x) + { + if (overflow_x_property == Style::Overflow::Auto) + { + element->GetElementScroll()->EnableScrollbar(ElementScroll::HORIZONTAL, box.GetSize(Box::PADDING).x); + + if (!CatchVerticalOverflow()) + return LAYOUT_SELF; + } + } + + content_box.x += (box.GetEdge(Box::PADDING, Box::LEFT) + box.GetEdge(Box::PADDING, Box::RIGHT)); + + content_box.y = box_cursor; + content_box.y = Math::Max(content_box.y, space_box.y); + if (!CatchVerticalOverflow(content_box.y)) + return LAYOUT_SELF; + + content_box.y += (box.GetEdge(Box::PADDING, Box::TOP) + box.GetEdge(Box::PADDING, Box::BOTTOM)); + + element->SetBox(box); + element->SetContentBox(space->GetOffset(), content_box); + + // Format any scrollbars which were enabled on this element. + element->GetElementScroll()->FormatScrollbars(); + } + else + element->SetBox(box); + } + + // Increment the parent's cursor. + if (parent != nullptr) + { + // If this close fails, it means this block box has caused our parent block box to generate an automatic + // vertical scrollbar. + if (!parent->CloseBlockBox(this)) + return LAYOUT_PARENT; + } + + // If we represent a positioned element, then we can now (as we've been sized) act as the containing block for all + // the absolutely-positioned elements of our descendants. + if (context == BLOCK && + element != nullptr) + { + if (element->GetPosition() != Style::Position::Static) + CloseAbsoluteElements(); + } + + return OK; +} + +// Called by a closing block box child. +bool LayoutBlockBox::CloseBlockBox(LayoutBlockBox* child) +{ + RMLUI_ASSERT(context == BLOCK); + box_cursor = (child->GetPosition().y - child->box.GetEdge(Box::MARGIN, Box::TOP) - (box.GetPosition().y + position.y)) + child->GetBox().GetSize(Box::MARGIN).y; + + return CatchVerticalOverflow(); +} + +// Called by a closing line box child. +LayoutInlineBox* LayoutBlockBox::CloseLineBox(LayoutLineBox* child, LayoutInlineBox* overflow, LayoutInlineBox* overflow_chain) +{ + RMLUI_ZoneScoped; + + RMLUI_ASSERT(context == INLINE); + if (child->GetDimensions().x > 0) + box_cursor = (child->GetPosition().y - (box.GetPosition().y + position.y)) + child->GetDimensions().y; + + // If we have any pending floating elements for our parent, then this would be an ideal time to position them. + if (!float_elements.empty()) + { + for (size_t i = 0; i < float_elements.size(); ++i) + parent->PositionFloat(float_elements[i], box_cursor); + + float_elements.clear(); + } + + // Add a new line box. + line_boxes.push_back(new LayoutLineBox(this)); + + if (overflow_chain != nullptr) + line_boxes.back()->AddChainedBox(overflow_chain); + + if (overflow != nullptr) + return line_boxes.back()->AddBox(overflow); + + return nullptr; +} + +// Adds a new block element to this block box. +LayoutBlockBox* LayoutBlockBox::AddBlockElement(Element* element) +{ + RMLUI_ZoneScoped; + + RMLUI_ASSERT(context == BLOCK); + + // Check if our most previous block box is rendering in an inline context. + if (!block_boxes.empty() && + block_boxes.back()->context == INLINE) + { + LayoutBlockBox* inline_block_box = block_boxes.back(); + LayoutInlineBox* open_inline_box = inline_block_box->line_boxes.back()->GetOpenInlineBox(); + if (open_inline_box != nullptr) + { + // There's an open inline box chain, which means this block element is parented to it. The chain needs to + // be positioned (if it hasn't already), closed and duplicated after this block box closes. Also, this + // block needs to be aware of its parentage, so it can correctly compute its relative position. First of + // all, we need to close the inline box; this will position the last line if necessary, but it will also + // create a new line in the inline block box; we want this line to be in an inline box after our block + // element. + if (inline_block_box->Close() != OK) + return nullptr; + + interrupted_chain = open_inline_box; + } + else + { + // There are no open inline boxes, so this inline box just needs to be closed. + if (CloseInlineBlockBox() != OK) + return nullptr; + } + } + + block_boxes.push_back(new LayoutBlockBox(layout_engine, this, element)); + return block_boxes.back(); +} + +// Adds a new inline element to this inline box. +LayoutInlineBox* LayoutBlockBox::AddInlineElement(Element* element, const Box& box) +{ + RMLUI_ZoneScoped; + + if (context == BLOCK) + { + LayoutInlineBox* inline_box; + + // If we have an open child rendering in an inline context, we can add this element into it. + if (!block_boxes.empty() && + block_boxes.back()->context == INLINE) + inline_box = block_boxes.back()->AddInlineElement(element, box); + + // No dice! Ah well, nothing for it but to open a new inline context block box. + else + { + block_boxes.push_back(new LayoutBlockBox(layout_engine, this)); + + if (interrupted_chain != nullptr) + { + block_boxes.back()->line_boxes.back()->AddChainedBox(interrupted_chain); + interrupted_chain = nullptr; + } + + inline_box = block_boxes.back()->AddInlineElement(element, box); + } + + return inline_box; + } + else + { + // We're an inline context box, so we'll add this new inline element into our line boxes. + return line_boxes.back()->AddElement(element, box); + } +} + +// Adds a line-break to this block box. +void LayoutBlockBox::AddBreak() +{ + float line_height = element->GetLineHeight(); + + // Check for an inline box as our last child; if so, we can simply end its line and bail. + if (!block_boxes.empty()) + { + LayoutBlockBox* block_box = block_boxes.back(); + if (block_box->context == INLINE) + { + LayoutLineBox* last_line = block_box->line_boxes.back(); + if (last_line->GetDimensions().y < 0) + block_box->box_cursor += line_height; + else + last_line->Close(); + + return; + } + } + + // No inline box as our last child; no problem, just increment the cursor by the line height of this element. + box_cursor += line_height; +} + +// Adds an element to this block box to be handled as a floating element. +bool LayoutBlockBox::AddFloatElement(Element* element) +{ + // If we have an open inline block box, then we have to position the box a little differently. + if (!block_boxes.empty() && + block_boxes.back()->context == INLINE) + block_boxes.back()->float_elements.push_back(element); + + // Nope ... just place it! + else + PositionFloat(element); + + return true; +} + +// Adds an element to this block box to be handled as an absolutely-positioned element. +void LayoutBlockBox::AddAbsoluteElement(Element* element) +{ + RMLUI_ASSERT(context == BLOCK); + + AbsoluteElement absolute_element; + absolute_element.element = element; + + PositionBox(absolute_element.position, 0); + + // If we have an open inline-context block box as our last child, then the absolute element must appear after it, + // but not actually close the box. + if (!block_boxes.empty() + && block_boxes.back()->context == INLINE) + { + LayoutBlockBox* inline_context_box = block_boxes.back(); + float last_line_height = inline_context_box->line_boxes.back()->GetDimensions().y; + + absolute_element.position.y += (inline_context_box->box_cursor + Math::Max(0.0f, last_line_height)); + } + + // Find the positioned parent for this element. + LayoutBlockBox* absolute_parent = this; + while (absolute_parent != absolute_parent->offset_parent) + absolute_parent = absolute_parent->parent; + + absolute_parent->absolute_elements.push_back(absolute_element); +} + +// Lays out, sizes, and positions all absolute elements in this block relative to the containing block. +void LayoutBlockBox::CloseAbsoluteElements() +{ + if (!absolute_elements.empty()) + { + // The size of the containing box, including the padding. This is used to resolve relative offsets. + Vector2f containing_block = GetBox().GetSize(Box::PADDING); + + for (size_t i = 0; i < absolute_elements.size(); i++) + { + Element* absolute_element = absolute_elements[i].element; + Vector2f absolute_position = absolute_elements[i].position; + absolute_position -= position - offset_root->GetPosition(); + + // Lay out the element. + LayoutEngine layout_engine; + layout_engine.FormatElement(absolute_element, containing_block); + + // Now that the element's box has been built, we can offset the position we determined was appropriate for + // it by the element's margin. This is necessary because the coordinate system for the box begins at the + // border, not the margin. + absolute_position.x += absolute_element->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + absolute_position.y += absolute_element->GetBox().GetEdge(Box::MARGIN, Box::TOP); + + // Set the offset of the element; the element itself will take care of any RCSS-defined positional offsets. + absolute_element->SetOffset(absolute_position, element); + } + + absolute_elements.clear(); + } +} + +// Returns the offset from the top-left corner of this box that the next child box will be positioned at. +void LayoutBlockBox::PositionBox(Vector2f& box_position, float top_margin, Style::Clear clear_property) const +{ + // If our element is establishing a new offset hierarchy, then any children of ours don't inherit our offset. + box_position = GetPosition(); + box_position += box.GetPosition(); + box_position.y += box_cursor; + + float clear_margin = space->ClearBoxes(box_position.y + top_margin, clear_property) - (box_position.y + top_margin); + if (clear_margin > 0) + box_position.y += clear_margin; + else + { + // Check for a collapsing vertical margin. + if (!block_boxes.empty() && + block_boxes.back()->context == BLOCK) + { + float bottom_margin = block_boxes.back()->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM); + box_position.y -= Math::Min(top_margin, bottom_margin); + } + } +} + +// Returns the offset from the top-left corner of this box's offset element the next child block box, of the given +// dimensions, will be positioned at. This will include the margins on the new block box. +void LayoutBlockBox::PositionBlockBox(Vector2f& box_position, const Box& box, Style::Clear clear_property) const +{ + PositionBox(box_position, box.GetEdge(Box::MARGIN, Box::TOP), clear_property); + box_position.x += box.GetEdge(Box::MARGIN, Box::LEFT); + box_position.y += box.GetEdge(Box::MARGIN, Box::TOP); +} + +// Returns the offset from the top-left corner of this box for the next line. +void LayoutBlockBox::PositionLineBox(Vector2f& box_position, float& box_width, bool& _wrap_content, const Vector2f& dimensions) const +{ + Vector2f cursor; + PositionBox(cursor); + + space->PositionBox(box_position, box_width, cursor.y, dimensions); + + // Also, probably shouldn't check for widths when positioning the box? + _wrap_content = wrap_content; +} + + +// Calculate the dimensions of the box's internal width; i.e. the size of the largest line, plus this element's padding. +float LayoutBlockBox::InternalContentWidth() const +{ + float content_width = 0.0f; + + if (context == BLOCK) + { + + for (size_t i = 0; i < block_boxes.size(); i++) + { + content_width = Math::Max(content_width, block_boxes[i]->InternalContentWidth()); + } + + // Work-around for supporting 'width' specification of 'display:block' elements inside 'display:inline-block'. + // Alternative solution: Add some 'intrinsic_width' property to every 'LayoutBlockBox' and have that propagate up to the nearest 'inline-block'. + if (element) + { + auto& computed = element->GetComputedValues(); + const float block_width = box.GetSize(Box::CONTENT).x; + + if(computed.width.type != Style::Width::Auto) + { + float w_value = ResolveValue(computed.width, block_width); + content_width = Math::Max(content_width, w_value); + } + + float min_width = ResolveValue(computed.min_width, block_width); + content_width = Math::Max(content_width, min_width); + + if (computed.max_width.value >= 0.f) + { + float value = ResolveValue(computed.max_width, block_width); + content_width = Math::Min(content_width, value); + } + } + + content_width += (box.GetEdge(Box::PADDING, Box::LEFT) + box.GetEdge(Box::PADDING, Box::RIGHT)); + content_width += (box.GetEdge(Box::MARGIN, Box::LEFT) + box.GetEdge(Box::MARGIN, Box::RIGHT)); + } + else + { + // Find the largest line in this layout block + for (size_t i = 0; i < line_boxes.size(); i++) + { + // Perhaps a more robust solution is to modify how we set the line box dimension on 'line_box->close()' + // and use that, or add another value in the line_box ... but seems to work for now. + LayoutLineBox* line_box = line_boxes[i]; + content_width = Math::Max(content_width, line_box->GetBoxCursor()); + } + content_width = Math::Min(content_width, box.GetSize(Box::CONTENT).x); + } + + return content_width; +} + + +// Returns the block box's element. +Element* LayoutBlockBox::GetElement() const +{ + return element; +} + +// Returns the block box's parent. +LayoutBlockBox* LayoutBlockBox::GetParent() const +{ + return parent; +} + +// Returns the position of the block box, relative to its parent's content area. +const Vector2f& LayoutBlockBox::GetPosition() const +{ + return position; +} + +// Returns the element against which all positions of boxes in the hierarchy are calculated relative to. +LayoutBlockBox* LayoutBlockBox::GetOffsetParent() const +{ + return offset_parent; +} + +// Returns the block box against which all positions of boxes in the hierarchy are calculated relative to. +LayoutBlockBox* LayoutBlockBox::GetOffsetRoot() const +{ + return offset_root; +} + +// Returns the block box's dimension box. +Box& LayoutBlockBox::GetBox() +{ + return box; +} + +// Returns the block box's dimension box. +const Box& LayoutBlockBox::GetBox() const +{ + return box; +} + +void* LayoutBlockBox::operator new(size_t size) +{ + void* memory = LayoutEngine::AllocateLayoutChunk(size); + return memory; +} + +void LayoutBlockBox::operator delete(void* chunk) +{ + LayoutEngine::DeallocateLayoutChunk(chunk); +} + +// Closes our last block box, if it is an open inline block box. +LayoutBlockBox::CloseResult LayoutBlockBox::CloseInlineBlockBox() +{ + if (!block_boxes.empty() && + block_boxes.back()->context == INLINE) + return block_boxes.back()->Close(); + + return OK; +} + +// Positions a floating element within this block box. +void LayoutBlockBox::PositionFloat(Element* element, float offset) +{ + Vector2f box_position; + PositionBox(box_position); + + space->PositionBox(box_position.y + offset, element); +} + +// Checks if we have a new vertical overflow on an auto-scrolling element. +bool LayoutBlockBox::CatchVerticalOverflow(float cursor) +{ + if (cursor == -1) + cursor = box_cursor; + + float box_height = box.GetSize().y; + if (box_height < 0) + box_height = max_height; + + // If we're auto-scrolling and our height is fixed, we have to check if this box has exceeded our client height. + if (!vertical_overflow && + box_height >= 0 && + overflow_y_property == Style::Overflow::Auto) + { + if (cursor > box_height - element->GetElementScroll()->GetScrollbarSize(ElementScroll::HORIZONTAL)) + { + RMLUI_ZoneScopedC(0xDD3322); + vertical_overflow = true; + element->GetElementScroll()->EnableScrollbar(ElementScroll::VERTICAL, box.GetSize(Box::PADDING).x); + + for (size_t i = 0; i < block_boxes.size(); i++) + delete block_boxes[i]; + block_boxes.clear(); + + delete space; + space = new LayoutBlockBoxSpace(this); + + box_cursor = 0; + interrupted_chain = nullptr; + + return false; + } + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/LayoutBlockBox.h b/thirdparty/RmlUi/Source/Core/LayoutBlockBox.h new file mode 100644 index 000000000..d68085b6a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutBlockBox.h @@ -0,0 +1,237 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LAYOUTBLOCKBOX_H +#define RMLUI_CORE_LAYOUTBLOCKBOX_H + +#include "LayoutLineBox.h" +#include "../../Include/RmlUi/Core/Box.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class LayoutBlockBoxSpace; +class LayoutEngine; + +/** + @author Peter Curry + */ + +class LayoutBlockBox +{ +public: + enum FormattingContext + { + BLOCK, + INLINE + }; + + enum CloseResult + { + OK, + LAYOUT_SELF, + LAYOUT_PARENT + }; + + /// Creates a new block box for rendering a block element. + /// @param layout_engine[in] The layout engine that created this block box. + /// @param parent[in] The parent of this block box. This will be nullptr for the root element. + /// @param element[in] The element this block box is laying out. + LayoutBlockBox(LayoutEngine* layout_engine, LayoutBlockBox* parent, Element* element); + /// Creates a new block box in an inline context. + /// @param layout_engine[in] The layout engine that created this block box. + /// @param parent[in] The parent of this block box. + LayoutBlockBox(LayoutEngine* layout_engine, LayoutBlockBox* parent); + /// Releases the block box. + ~LayoutBlockBox(); + + /// Closes the box. This will determine the element's height (if it was unspecified). + /// @return The result of the close; this may request a reformat of this element or our parent. + CloseResult Close(); + + /// Called by a closing block box child. Increments the cursor. + /// @param child[in] The closing child block box. + /// @return False if the block box caused an automatic vertical scrollbar to appear, forcing an entire reformat of the block box. + bool CloseBlockBox(LayoutBlockBox* child); + /// Called by a closing line box child. Increments the cursor, and creates a new line box to fit the overflow + /// (if any). + /// @param child[in] The closing child line box. + /// @param overflow[in] The overflow from the closing line box. May be nullptr if there was no overflow. + /// @param overflow_chain[in] The end of the chained hierarchy to be spilled over to the new line, as the parent to the overflow box (if one exists). + /// @return If the line box had overflow, this will be the last inline box created by the overflow. + LayoutInlineBox* CloseLineBox(LayoutLineBox* child, LayoutInlineBox* overflow, LayoutInlineBox* overflow_chain); + + /// Adds a new block element to this block-context box. + /// @param element[in] The new block element. + /// @param placed[in] True if the element is to be placed, false otherwise. + /// @return The block box representing the element. Once the element's children have been positioned, Close() must be called on it. + LayoutBlockBox* AddBlockElement(Element* element); + /// Adds a new inline element to this inline-context box. + /// @param element[in] The new inline element. + /// @param box[in] The box defining the element's bounds. + /// @return The inline box representing the element. Once the element's children have been positioned, Close() must be called on it. + LayoutInlineBox* AddInlineElement(Element* element, const Box& box); + /// Adds a line-break to this block box. + void AddBreak(); + + /// Adds an element to this block box to be handled as a floating element. + bool AddFloatElement(Element* element); + + /// Adds an element to this block box to be handled as an absolutely-positioned element. This element will be + /// laid out, sized and positioned appropriately once this box is finished. This should only be called on boxes + /// rendering in a block-context. + /// @param element[in] The element to be positioned absolutely within this block box. + void AddAbsoluteElement(Element* element); + /// Formats, sizes, and positions all absolute elements in this block. + void CloseAbsoluteElements(); + + /// Returns the offset from the top-left corner of this box's offset element the next child box will be + /// positioned at. + /// @param[out] box_position The box cursor position. + /// @param[in] top_margin The top margin of the box. This will be collapsed as appropriate against other block boxes. + /// @param[in] clear_property The value of the underlying element's clear property. + void PositionBox(Vector2f& box_position, float top_margin = 0, Style::Clear clear_property = Style::Clear::None) const; + /// Returns the offset from the top-left corner of this box's offset element the next child block box, of the + /// given dimensions, will be positioned at. This will include the margins on the new block box. + /// @param[out] box_position The block box cursor position. + /// @param[in] box The dimensions of the new box. + /// @param[in] clear_property The value of the underlying element's clear property. + void PositionBlockBox(Vector2f& box_position, const Box& box, Style::Clear clear_property) const; + /// Returns the offset from the top-left corner of this box for the next line. + /// @param box_position[out] The line box position. + /// @param box_width[out] The available width for the line box. + /// @param wrap_content[out] Set to true if the line box should grow to fit inline boxes, false if it should wrap them. + /// @param dimensions[in] The minimum dimensions of the line. + void PositionLineBox(Vector2f& box_position, float& box_width, bool& wrap_content, const Vector2f& dimensions) const; + + float InternalContentWidth() const; + + /// Returns the block box's element. + /// @return The block box's element. + Element* GetElement() const; + + /// Returns the block box's parent. + /// @return The block box's parent. + LayoutBlockBox* GetParent() const; + + /// Returns the position of the block box, relative to its parent's content area. + /// @return The relative position of the block box. + const Vector2f& GetPosition() const; + + /// Returns the block box against which all positions of boxes in the hierarchy are set relative to. + /// @return This box's offset parent. + LayoutBlockBox* GetOffsetParent() const; + /// Returns the block box against which all positions of boxes in the hierarchy are calculated relative to. + /// @return This box's offset root. + LayoutBlockBox* GetOffsetRoot() const; + + + /// Returns the block box's dimension box. + /// @return The block box's dimension box. + Box& GetBox(); + /// Returns the block box's dimension box. + /// @return The block box's dimension box. + const Box& GetBox() const; + + void* operator new(size_t size); + void operator delete(void* chunk); + +private: + struct AbsoluteElement + { + Element* element; + Vector2f position; + }; + + // Closes our last block box, if it is an open inline block box. + CloseResult CloseInlineBlockBox(); + + // Positions a floating element within this block box. + void PositionFloat(Element* element, float offset = 0); + + // Checks if we have a new vertical overflow on an auto-scrolling element. If so, our vertical scrollbar will + // be enabled and our block boxes will be destroyed. All content will need to re-formatted. Returns true if no + // overflow occured, false if it did. + bool CatchVerticalOverflow(float cursor = -1); + + typedef Vector< AbsoluteElement > AbsoluteElementList; + typedef Vector< LayoutBlockBox* > BlockBoxList; + typedef Vector< LayoutLineBox* > LineBoxList; + + // The object managing our space, as occupied by floating elements of this box and our ancestors. + LayoutBlockBoxSpace* space; + + // The box's layout engine. + LayoutEngine* layout_engine; + // The element this box represents. This will be nullptr for boxes rendering in an inline context. + Element* element; + + // The element we'll be computing our offset relative to during layout. + LayoutBlockBox* offset_root; + // The element this block box's children are to be offset from. + LayoutBlockBox* offset_parent; + + // The box's block parent. This will be nullptr for the root of the box tree. + LayoutBlockBox* parent; + + // The context of the box's context; either block or inline. + FormattingContext context; + + // The block box's position. + Vector2f position; + // The block box's size. + Box box; + float min_height; + float max_height; + // Used by inline contexts only; set to true if the block box's line boxes should stretch to fit their inline content instead of wrapping. + bool wrap_content; + + // The vertical position of the next block box to be added to this box, relative to the top of this box. + float box_cursor; + + // Used by block contexts only; stores the list of block boxes under this box. + BlockBoxList block_boxes; + // Used by block contexts only; stores any elements that are to be absolutely positioned within this block box. + AbsoluteElementList absolute_elements; + // Used by block contexts only; stores an inline element hierarchy that was interrupted by a child block box. + // The hierarchy will be resumed in an inline-context box once the intervening block box is completed. + LayoutInlineBox* interrupted_chain; + // Used by block contexts only; stores the value of the overflow property for the element. + Style::Overflow overflow_x_property; + Style::Overflow overflow_y_property; + // Used by block contexts only; if true, we've enabled our vertical scrollbar. + bool vertical_overflow; + + // Used by inline contexts only; stores the list of line boxes flowing inline content. + LineBoxList line_boxes; + // Used by inline contexts only; stores any floating elements that are waiting for a line break to be positioned. + ElementList float_elements; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/LayoutBlockBoxSpace.cpp b/thirdparty/RmlUi/Source/Core/LayoutBlockBoxSpace.cpp new file mode 100644 index 000000000..49421f5fd --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutBlockBoxSpace.cpp @@ -0,0 +1,288 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LayoutBlockBoxSpace.h" +#include "LayoutBlockBox.h" +#include "LayoutEngine.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementScroll.h" +#include + +namespace Rml { + +LayoutBlockBoxSpace::LayoutBlockBoxSpace(LayoutBlockBox* _parent) : offset(0, 0), dimensions(0, 0) +{ + parent = _parent; +} + +LayoutBlockBoxSpace::~LayoutBlockBoxSpace() +{ +} + +// Imports boxes from another block into this space. +void LayoutBlockBoxSpace::ImportSpace(const LayoutBlockBoxSpace& space) +{ + // Copy all the boxes from the parent into this space. Could do some optimisation here! + for (int i = 0; i < NUM_ANCHOR_EDGES; ++i) + { + for (size_t j = 0; j < space.boxes[i].size(); ++j) + boxes[i].push_back(space.boxes[i][j]); + } +} + +// Generates the position for a box of a given size within a containing block box. +void LayoutBlockBoxSpace::PositionBox(Vector2f& box_position, float& box_width, float cursor, const Vector2f& dimensions) const +{ + box_width = PositionBox(box_position, cursor, dimensions); +} + +// Generates and sets the position for a floating box of a given size within our block box. +float LayoutBlockBoxSpace::PositionBox(float cursor, Element* element) +{ + Vector2f element_size = element->GetBox().GetSize(Box::MARGIN); + Style::Float float_property = element->GetComputedValues().float_; + + // Shift the cursor down (if necessary) so it isn't placed any higher than a previously-floated box. + for (int i = 0; i < NUM_ANCHOR_EDGES; ++i) + { + if (!boxes[i].empty()) + cursor = Math::Max(cursor, boxes[i].back().offset.y); + } + + // Shift the cursor down past to clear boxes, if necessary. + cursor = ClearBoxes(cursor, element->GetComputedValues().clear); + + // Find a place to put this box. + Vector2f element_offset; + PositionBox(element_offset, cursor, element_size, float_property); + + // It's been placed, so we can now add it to our list of floating boxes. + boxes[float_property == Style::Float::Left ? LEFT : RIGHT].push_back(SpaceBox(element_offset, element_size)); + + // Set our offset and dimensions (if necessary) so they enclose the new box. + Vector2f normalised_offset = element_offset - (parent->GetPosition() + parent->GetBox().GetPosition()); + offset.x = Math::Min(offset.x, normalised_offset.x); + offset.y = Math::Min(offset.y, normalised_offset.y); + dimensions.x = Math::Max(dimensions.x, normalised_offset.x + element_size.x); + dimensions.y = Math::Max(dimensions.y, normalised_offset.y + element_size.y); + + // Shift the offset into the correct space relative to the element's offset parent. + element_offset += Vector2f(element->GetBox().GetEdge(Box::MARGIN, Box::LEFT), element->GetBox().GetEdge(Box::MARGIN, Box::TOP)); + element->SetOffset(element_offset - parent->GetOffsetParent()->GetPosition(), parent->GetOffsetParent()->GetElement()); + + return element_offset.y + element_size.y; +} + +// Determines the appropriate vertical position for an object that is choosing to clear floating elements to the left +// or right (or both). +float LayoutBlockBoxSpace::ClearBoxes(float cursor, Style::Clear clear_property) +{ + using namespace Style; + // Clear left boxes. + if (clear_property == Clear::Left || + clear_property == Clear::Both) + { + for (size_t i = 0; i < boxes[LEFT].size(); ++i) + cursor = Math::Max(cursor, boxes[LEFT][i].offset.y + boxes[LEFT][i].dimensions.y); + } + + // Clear right boxes. + if (clear_property == Clear::Right || + clear_property == Clear::Both) + { + for (size_t i = 0; i < boxes[RIGHT].size(); ++i) + cursor = Math::Max(cursor, boxes[RIGHT][i].offset.y + boxes[RIGHT][i].dimensions.y); + } + + return cursor; +} + +// Generates the position for an arbitrary box within our space layout, floated against either the left or right edge. +float LayoutBlockBoxSpace::PositionBox(Vector2f& box_position, float cursor, const Vector2f& dimensions, Style::Float float_property) const +{ + float parent_scrollbar_width = parent->GetElement()->GetElementScroll()->GetScrollbarSize(ElementScroll::VERTICAL); + float parent_origin = parent->GetPosition().x + parent->GetBox().GetPosition(Box::CONTENT).x; + float parent_edge = parent->GetBox().GetSize().x + parent_origin - parent_scrollbar_width; + + AnchorEdge box_edge = float_property == Style::Float::Right ? RIGHT : LEFT; + + box_position.y = cursor; + box_position.x = box_edge == LEFT ? 0 : (parent->GetBox().GetSize().x - dimensions.x) - parent_scrollbar_width; + box_position.x += parent_origin; + + float next_cursor = FLT_MAX; + + // First up; we iterate through all boxes that share our edge, pushing ourself to the side of them if we intersect + // them. We record the height of the lowest box that gets in our way; in the event we can't be positioned at this + // height, we'll reposition ourselves at that height for the next iteration. + for (size_t i = 0; i < boxes[box_edge].size(); ++i) + { + const SpaceBox& fixed_box = boxes[box_edge][i]; + + // If the fixed box's bottom edge is above our top edge, then we can safely skip it. + if (fixed_box.offset.y + fixed_box.dimensions.y <= box_position.y) + continue; + + // If the fixed box's top edge is below our bottom edge, then we can safely skip it. + if (fixed_box.offset.y >= box_position.y + dimensions.y) + continue; + + // We're intersecting this box vertically, so the box is pushed to the side if necessary. + bool collision = false; + if (box_edge == LEFT) + { + float right_edge = fixed_box.offset.x + fixed_box.dimensions.x; + collision = box_position.x < right_edge; + if (collision) + box_position.x = right_edge; + } + else + { + collision = box_position.x + dimensions.x > fixed_box.offset.x; + if (collision) + box_position.x = fixed_box.offset.x - dimensions.x; + } + + // If there was a collision, then we *might* want to remember the height of this box if it is the earliest- + // terminating box we've collided with so far. + if (collision) + { + next_cursor = Math::Min(next_cursor, fixed_box.offset.y + fixed_box.dimensions.y); + + // Were we pushed out of our containing box? If so, try again at the next cursor position. + float normalised_position = box_position.x - parent_origin; + if (normalised_position < 0 || + normalised_position + dimensions.x > parent->GetBox().GetSize().x) + return PositionBox(box_position, next_cursor + 0.01f, dimensions, float_property); + } + } + + // Second; we go through all of the boxes on the other edge, checking for horizontal collisions and determining the + // maximum width the box can stretch to, if it is placed at this location. + float maximum_box_width = box_edge == LEFT ? parent_edge - box_position.x : box_position.x + dimensions.x; + + for (size_t i = 0; i < boxes[1 - box_edge].size(); ++i) + { + const SpaceBox& fixed_box = boxes[1 - box_edge][i]; + + // If the fixed box's bottom edge is above our top edge, then we can safely skip it. + if (fixed_box.offset.y + fixed_box.dimensions.y <= box_position.y) + continue; + + // If the fixed box's top edge is below our bottom edge, then we can safely skip it. + if (fixed_box.offset.y >= box_position.y + dimensions.y) + continue; + + // We intersect this box vertically, so check if it intersects horizontally. + bool collision = false; + if (box_edge == LEFT) + { + maximum_box_width = Math::Min(maximum_box_width, fixed_box.offset.x - box_position.x); + collision = box_position.x + dimensions.x > fixed_box.offset.x; + } + else + { + maximum_box_width = Math::Min(maximum_box_width, (box_position.x + dimensions.x) - (fixed_box.offset.x + fixed_box.dimensions.x)); + collision = box_position.x < fixed_box.offset.x + fixed_box.dimensions.x; + } + + // If we collided with this box ... d'oh! We'll try again lower down the page, at the highest bottom-edge of + // any of the boxes we've been pushed around by so far. + if (collision) + { + next_cursor = Math::Min(next_cursor, fixed_box.offset.y + fixed_box.dimensions.y); + return PositionBox(box_position, next_cursor + 0.01f, dimensions, float_property); + } + } + + // Third; we go through all of the boxes (on both sides), checking for vertical collisions. + for (int i = 0; i < 2; ++i) + { + for (size_t j = 0; j < boxes[i].size(); ++j) + { + const SpaceBox& fixed_box = boxes[i][j]; + + // If the fixed box's bottom edge is above our top edge, then we can safely skip it. + if (fixed_box.offset.y + fixed_box.dimensions.y <= box_position.y) + continue; + + // If the fixed box's top edge is below our bottom edge, then we can safely skip it. + if (fixed_box.offset.y >= box_position.y + dimensions.y) + continue; + + // We collide vertically; if we also collide horizontally, then we have to try again further down the + // layout. If the fixed box's left edge is to right of our right edge, then we can safely skip it. + if (fixed_box.offset.x >= box_position.x + dimensions.x) + continue; + + // If the fixed box's right edge is to the left of our left edge, then we can safely skip it. + if (fixed_box.offset.x + fixed_box.dimensions.x <= box_position.x) + continue; + + // D'oh! We hit this box. Ah well; we'll try again lower down the page, at the highest bottom-edge of any + // of the boxes we've been pushed around by so far. + next_cursor = Math::Min(next_cursor, fixed_box.offset.y + fixed_box.dimensions.y); + return PositionBox(box_position, next_cursor + 0.01f, dimensions, float_property); + } + } + + // Looks like we've found a winner! + return maximum_box_width; +} + +// Returns the top-left offset of the boxes within the space. +const Vector2f& LayoutBlockBoxSpace::GetOffset() const +{ + return offset; +} + +// Returns the dimensions of the boxes within the space. +Vector2f LayoutBlockBoxSpace::GetDimensions() const +{ + return dimensions - offset; +} + +void* LayoutBlockBoxSpace::operator new(size_t size) +{ + return LayoutEngine::AllocateLayoutChunk(size); +} + +void LayoutBlockBoxSpace::operator delete(void* chunk) +{ + LayoutEngine::DeallocateLayoutChunk(chunk); +} + +LayoutBlockBoxSpace::SpaceBox::SpaceBox() : offset(0, 0), dimensions(0, 0) +{ +} + +LayoutBlockBoxSpace::SpaceBox::SpaceBox(const Vector2f& offset, const Vector2f& dimensions) : offset(offset), dimensions(dimensions) +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/LayoutBlockBoxSpace.h b/thirdparty/RmlUi/Source/Core/LayoutBlockBoxSpace.h new file mode 100644 index 000000000..883dd0e25 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutBlockBoxSpace.h @@ -0,0 +1,127 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LAYOUTBLOCKBOXSPACE_H +#define RMLUI_CORE_LAYOUTBLOCKBOXSPACE_H + +#include "../../Include/RmlUi/Core/ComputedValues.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class Element; +class LayoutBlockBox; + +/** + Each block box has a space object for managing the space occupied by its floating elements, and those of its + ancestors as relevant. + + @author Peter Curry + */ + +class LayoutBlockBoxSpace +{ +public: + LayoutBlockBoxSpace(LayoutBlockBox* parent); + ~LayoutBlockBoxSpace(); + + /// Imports boxes from another block into this space. + /// @param[in] space The space to import boxes from. + void ImportSpace(const LayoutBlockBoxSpace& space); + + /// Generates the position for a box of a given size within our block box. + /// @param[out] box_position The generated position for the box. + /// @param[out] box_width The available width for the box. + /// @param[in] cursor The ideal vertical position for the box. + /// @param[in] dimensions The minimum available space required for the box. + void PositionBox(Vector2f& box_position, float& box_width, float cursor, const Vector2f& dimensions) const; + + /// Generates and sets the position for a floating box of a given size within our block box. The element's box + /// is then added into our list of floating boxes. + /// @param[in] cursor The ideal vertical position for the box. + /// @param[in] element The element to position. + /// @return The offset of the bottom outer edge of the element. + float PositionBox(float cursor, Element* element); + + /// Determines the appropriate vertical position for an object that is choosing to clear floating elements to + /// the left or right (or both). + /// @param[in] cursor The ideal vertical position. + /// @param[in] clear_property The value of the clear property of the clearing object. + /// @return The appropriate vertical position for the clearing object. + float ClearBoxes(float cursor, Style::Clear clear_property); + + /// Returns the top-left corner of the boxes within the space. + /// @return The space's offset. + const Vector2f& GetOffset() const; + /// Returns the dimensions of the boxes within the space. + /// @return The space's dimensions. + Vector2f GetDimensions() const; + + void* operator new(size_t size); + void operator delete(void* chunk); + +private: + enum AnchorEdge + { + LEFT = 0, + RIGHT = 1, + NUM_ANCHOR_EDGES = 2 + }; + + /// Generates the position for an arbitrary box within our space layout, floated against either the left or + /// right edge. + /// @param box_position[out] The generated position for the box. + /// @param cursor[in] The ideal vertical position for the box. + /// @param dimensions[in] The size of the box to place. + /// @return The maximum width at the box position. + float PositionBox(Vector2f& box_position, float cursor, const Vector2f& dimensions, Style::Float float_property = Style::Float::None) const; + + struct SpaceBox + { + SpaceBox(); + SpaceBox(const Vector2f& offset, const Vector2f& dimensions); + + Vector2f offset; + Vector2f dimensions; + }; + + typedef Vector< SpaceBox > SpaceBoxList; + + // Our block-box parent. + LayoutBlockBox* parent; + + // The boxes floating in our space. + SpaceBoxList boxes[NUM_ANCHOR_EDGES]; + + // The offset and dimensions of the boxes added specifically into this space. + Vector2f offset; + Vector2f dimensions; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/LayoutEngine.cpp b/thirdparty/RmlUi/Source/Core/LayoutEngine.cpp new file mode 100644 index 000000000..1cb96137d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutEngine.cpp @@ -0,0 +1,692 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LayoutEngine.h" +#include "../../Include/RmlUi/Core/Math.h" +#include "Pool.h" +#include "LayoutBlockBoxSpace.h" +#include "LayoutInlineBoxText.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementScroll.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/Types.h" +#include +#include + +namespace Rml { + +#define MAX(a, b) (a > b ? a : b) + +struct LayoutChunk +{ + static const unsigned int size = MAX(sizeof(LayoutBlockBox), MAX(sizeof(LayoutInlineBox), MAX(sizeof(LayoutInlineBoxText), MAX(sizeof(LayoutLineBox), sizeof(LayoutBlockBoxSpace))))); + alignas(std::max_align_t) char buffer[size]; +}; + +static Pool< LayoutChunk > layout_chunk_pool(200, true); + +LayoutEngine::LayoutEngine() +{ + block_box = nullptr; + block_context_box = nullptr; +} + +LayoutEngine::~LayoutEngine() +{ +} + +// Formats the contents for a root-level element (usually a document or floating element). +bool LayoutEngine::FormatElement(Element* element, const Vector2f& containing_block, bool shrink_to_fit) +{ +#ifdef RMLUI_ENABLE_PROFILING + RMLUI_ZoneScopedC(0xB22222); + auto name = CreateString(80, "%s %x", element->GetAddress(false, false).c_str(), element); + RMLUI_ZoneName(name.c_str(), name.size()); +#endif + + block_box = new LayoutBlockBox(this, nullptr, nullptr); + block_box->GetBox().SetContent(containing_block); + + block_context_box = block_box->AddBlockElement(element); + + for (int i = 0; i < element->GetNumChildren(); i++) + { + if (!FormatElement(element->GetChild(i))) + i = -1; + } + + if (shrink_to_fit) + { + // For inline blocks with 'auto' width, we want to shrink the box back to its inner content width, recreating the LayoutBlockBox. + float content_width = block_box->InternalContentWidth(); + + if (content_width < containing_block.x) + { + RMLUI_ZoneScopedNC("shrink_to_fit", 0xB27222); + + Vector2f shrinked_block_size(content_width, containing_block.y); + + delete block_box; + block_box = new LayoutBlockBox(this, nullptr, nullptr); + block_box->GetBox().SetContent(shrinked_block_size); + + block_context_box = block_box->AddBlockElement(element); + + for (int i = 0; i < element->GetNumChildren(); i++) + { + if (!FormatElement(element->GetChild(i))) + i = -1; + } + } + } + + block_context_box->Close(); + block_context_box->CloseAbsoluteElements(); + + element->OnLayout(); + + delete block_box; + return true; +} + +// Generates the box for an element. +void LayoutEngine::BuildBox(Box& box, const Vector2f& containing_block, Element* element, bool inline_element) +{ + if (element == nullptr) + { + box.SetContent(containing_block); + return; + } + + const ComputedValues& computed = element->GetComputedValues(); + + // Calculate the padding area. + float padding = ResolveValue(computed.padding_top, containing_block.x); + box.SetEdge(Box::PADDING, Box::TOP, Math::Max(0.0f, padding)); + padding = ResolveValue(computed.padding_right, containing_block.x); + box.SetEdge(Box::PADDING, Box::RIGHT, Math::Max(0.0f, padding)); + padding = ResolveValue(computed.padding_bottom, containing_block.x); + box.SetEdge(Box::PADDING, Box::BOTTOM, Math::Max(0.0f, padding)); + padding = ResolveValue(computed.padding_left, containing_block.x); + box.SetEdge(Box::PADDING, Box::LEFT, Math::Max(0.0f, padding)); + + // Calculate the border area. + box.SetEdge(Box::BORDER, Box::TOP, Math::Max(0.0f, computed.border_top_width)); + box.SetEdge(Box::BORDER, Box::RIGHT, Math::Max(0.0f, computed.border_right_width)); + box.SetEdge(Box::BORDER, Box::BOTTOM, Math::Max(0.0f, computed.border_bottom_width)); + box.SetEdge(Box::BORDER, Box::LEFT, Math::Max(0.0f, computed.border_left_width)); + + // Calculate the size of the content area. + Vector2f content_area(-1, -1); + bool replaced_element = false; + + // If the element has intrinsic dimensions, then we use those as the basis for the content area and only adjust + // them if a non-auto style has been applied to them. + if (element->GetIntrinsicDimensions(content_area)) + { + replaced_element = true; + + Vector2f original_content_area = content_area; + + // The element has resized itself, so we only resize it if a RCSS width or height was set explicitly. A value of + // 'auto' (or 'auto-fit', ie, both keywords) means keep (or adjust) the intrinsic dimensions. + bool auto_width = false, auto_height = false; + + if (computed.width.type != Style::Width::Auto) + content_area.x = ResolveValue(computed.width, containing_block.x); + else + auto_width = true; + + if (computed.height.type != Style::Height::Auto) + content_area.y = ResolveValue(computed.height, containing_block.y); + else + auto_height = true; + + // If one of the dimensions is 'auto' then we need to scale it such that the original ratio is preserved. + if (auto_width && !auto_height) + content_area.x = (content_area.y / original_content_area.y) * original_content_area.x; + else if (auto_height && !auto_width) + content_area.y = (content_area.x / original_content_area.x) * original_content_area.y; + + // Reduce the width and height to make up for borders and padding. + content_area.x -= (box.GetEdge(Box::BORDER, Box::LEFT) + + box.GetEdge(Box::PADDING, Box::LEFT) + + box.GetEdge(Box::BORDER, Box::RIGHT) + + box.GetEdge(Box::PADDING, Box::RIGHT)); + content_area.y -= (box.GetEdge(Box::BORDER, Box::TOP) + + box.GetEdge(Box::PADDING, Box::TOP) + + box.GetEdge(Box::BORDER, Box::BOTTOM) + + box.GetEdge(Box::PADDING, Box::BOTTOM)); + + content_area.x = Math::Max(content_area.x, 0.0f); + content_area.y = Math::Max(content_area.y, 0.0f); + } + + // If the element is inline, then its calculations are much more straightforward (no worrying about auto margins + // and dimensions, etc). All we do is calculate the margins, set the content area and bail. + if (inline_element) + { + if (replaced_element) + { + content_area.x = ClampWidth(content_area.x, computed, containing_block.x); + content_area.y = ClampHeight(content_area.y, computed, containing_block.y); + } + + // If the element was not replaced, then we leave its dimension as unsized (-1, -1) and ignore the width and + // height properties. + box.SetContent(content_area); + + // Evaluate the margins. Any declared as 'auto' will resolve to 0. + box.SetEdge(Box::MARGIN, Box::TOP, ResolveValue(computed.margin_top, containing_block.x)); + box.SetEdge(Box::MARGIN, Box::RIGHT, ResolveValue(computed.margin_right, containing_block.x)); + box.SetEdge(Box::MARGIN, Box::BOTTOM, ResolveValue(computed.margin_bottom, containing_block.x)); + box.SetEdge(Box::MARGIN, Box::LEFT, ResolveValue(computed.margin_left, containing_block.x)); + } + + // The element is block, so we need to run the box through the ringer to potentially evaluate auto margins and + // dimensions. + else + { + box.SetContent(content_area); + BuildBoxWidth(box, computed, containing_block.x); + BuildBoxHeight(box, computed, containing_block.y); + } +} + +// Generates the box for an element placed in a block box. +void LayoutEngine::BuildBox(Box& box, float& min_height, float& max_height, LayoutBlockBox* containing_box, Element* element, bool inline_element) +{ + Vector2f containing_block = GetContainingBlock(containing_box); + BuildBox(box, containing_block, element, inline_element); + + float box_height = box.GetSize().y; + if (box_height < 0) + { + auto& computed = element->GetComputedValues(); + min_height = ResolveValue(computed.min_height, containing_block.y); + max_height = (computed.max_height.value < 0.f ? FLT_MAX : ResolveValue(computed.max_height, containing_block.y)); + } + else + { + min_height = box_height; + max_height = box_height; + } +} + +// Clamps the width of an element based from its min-width and max-width properties. +float LayoutEngine::ClampWidth(float width, const ComputedValues& computed, float containing_block_width) +{ + float min_width = ResolveValue(computed.min_width, containing_block_width); + float max_width = (computed.max_width.value < 0.f ? FLT_MAX : ResolveValue(computed.max_width, containing_block_width)); + + return Math::Clamp(width, min_width, max_width); +} + +// Clamps the height of an element based from its min-height and max-height properties. +float LayoutEngine::ClampHeight(float height, const ComputedValues& computed, float containing_block_height) +{ + float min_height = ResolveValue(computed.min_height, containing_block_height); + float max_height = (computed.max_height.value < 0.f ? FLT_MAX : ResolveValue(computed.max_height, containing_block_height)); + + return Math::Clamp(height, min_height, max_height); +} + +void* LayoutEngine::AllocateLayoutChunk(size_t size) +{ + RMLUI_ASSERT(size <= LayoutChunk::size); + (void)size; + + return layout_chunk_pool.AllocateAndConstruct(); +} + +void LayoutEngine::DeallocateLayoutChunk(void* chunk) +{ + layout_chunk_pool.DestroyAndDeallocate((LayoutChunk*) chunk); +} + +// Positions a single element and its children within this layout. +bool LayoutEngine::FormatElement(Element* element) +{ +#ifdef RMLUI_ENABLE_PROFILING + RMLUI_ZoneScoped; + auto name = CreateString(80, ">%s %x", element->GetAddress(false, false).c_str(), element); + RMLUI_ZoneName(name.c_str(), name.size()); +#endif + + auto& computed = element->GetComputedValues(); + + // Check if we have to do any special formatting for any elements that don't fit into the standard layout scheme. + if (FormatElementSpecial(element)) + return true; + + // Fetch the display property, and don't lay this element out if it is set to a display type of none. + if (computed.display == Style::Display::None) + return true; + + // Check for an absolute position; if this has been set, then we remove it from the flow and add it to the current + // block box to be laid out and positioned once the block has been closed and sized. + if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed) + { + // Display the element as a block element. + block_context_box->AddAbsoluteElement(element); + return true; + } + + // If the element is floating, we remove it from the flow. + Style::Float float_property = element->GetFloat(); + if (float_property != Style::Float::None) + { + // Format the element as a block element. + LayoutEngine layout_engine; + layout_engine.FormatElement(element, GetContainingBlock(block_context_box)); + + return block_context_box->AddFloatElement(element); + } + + // The element is nothing exceptional, so we treat it as a normal block, inline or replaced element. + switch (computed.display) + { + case Style::Display::Block: return FormatElementBlock(element); break; + case Style::Display::Inline: return FormatElementInline(element); break; + case Style::Display::InlineBlock: return FormatElementReplaced(element); break; + default: RMLUI_ERROR; + } + + return true; +} + +// Formats and positions an element as a block element. +bool LayoutEngine::FormatElementBlock(Element* element) +{ + RMLUI_ZoneScopedC(0x2F4F4F); + + LayoutBlockBox* new_block_context_box = block_context_box->AddBlockElement(element); + if (new_block_context_box == nullptr) + return false; + + block_context_box = new_block_context_box; + + // Format the element's children. + for (int i = 0; i < element->GetNumChildren(); i++) + { + if (!FormatElement(element->GetChild(i))) + i = -1; + } + + // Close the block box, and check the return code; we may have overflowed either this element or our parent. + new_block_context_box = block_context_box->GetParent(); + switch (block_context_box->Close()) + { + // We need to reformat ourself; format all of our children again and close the box. No need to check for error + // codes, as we already have our vertical slider bar. + case LayoutBlockBox::LAYOUT_SELF: + { + for (int i = 0; i < element->GetNumChildren(); i++) + FormatElement(element->GetChild(i)); + + if (block_context_box->Close() == LayoutBlockBox::OK) + { + element->OnLayout(); + break; + } + } + //-fallthrough + // We caused our parent to add a vertical scrollbar; bail out! + case LayoutBlockBox::LAYOUT_PARENT: + { + block_context_box = new_block_context_box; + return false; + } + break; + + default: + element->OnLayout(); + } + + block_context_box = new_block_context_box; + return true; +} + +// Formats and positions an element as an inline element. +bool LayoutEngine::FormatElementInline(Element* element) +{ + RMLUI_ZoneScopedC(0x3F6F6F); + + Box box; + float min_height, max_height; + BuildBox(box, min_height, max_height, block_context_box, element, true); + LayoutInlineBox* inline_box = block_context_box->AddInlineElement(element, box); + + // Format the element's children. + for (int i = 0; i < element->GetNumChildren(); i++) + { + if (!FormatElement(element->GetChild(i))) + return false; + } + + inline_box->Close(); +// element->OnLayout(); + + return true; +} + +// Positions an element as a sized inline element, formatting its internal hierarchy as a block element. +bool LayoutEngine::FormatElementReplaced(Element* element) +{ + RMLUI_ZoneScopedC(0x1F2F2F); + + // Format the element separately as a block element, then position it inside our own layout as an inline element. + Vector2f containing_block_size = GetContainingBlock(block_context_box); + + LayoutEngine layout_engine; + bool shrink_to_width = element->GetComputedValues().width.type == Style::Width::Auto; + layout_engine.FormatElement(element, containing_block_size, shrink_to_width); + + block_context_box->AddInlineElement(element, element->GetBox())->Close(); + + return true; +} + +// Executes any special formatting for special elements. +bool LayoutEngine::FormatElementSpecial(Element* element) +{ + static const String br("br"); + + // Check for a
tag. + if (element->GetTagName() == br) + { + block_context_box->AddBreak(); + element->OnLayout(); + return true; + } + + return false; +} + +// Returns the fully-resolved, fixed-width and -height containing block from a block box. +Vector2f LayoutEngine::GetContainingBlock(const LayoutBlockBox* containing_box) +{ + Vector2f containing_block; + + containing_block.x = containing_box->GetBox().GetSize(Box::CONTENT).x; + if (containing_box->GetElement() != nullptr) + containing_block.x -= containing_box->GetElement()->GetElementScroll()->GetScrollbarSize(ElementScroll::VERTICAL); + + while ((containing_block.y = containing_box->GetBox().GetSize(Box::CONTENT).y) < 0) + { + containing_box = containing_box->GetParent(); + if (containing_box == nullptr) + { + RMLUI_ERROR; + containing_block.y = 0; + } + } + if (containing_box != nullptr && + containing_box->GetElement() != nullptr) + containing_block.y -= containing_box->GetElement()->GetElementScroll()->GetScrollbarSize(ElementScroll::HORIZONTAL); + + containing_block.x = Math::Max(0.0f, containing_block.x); + containing_block.y = Math::Max(0.0f, containing_block.y); + + return containing_block; +} + +// Builds the block-specific width and horizontal margins of a Box. +void LayoutEngine::BuildBoxWidth(Box& box, const ComputedValues& computed, float containing_block_width) +{ + RMLUI_ZoneScoped; + + Vector2f content_area = box.GetSize(); + + // Determine if the element has an automatic width, and if not calculate it. + bool width_auto; + if (content_area.x >= 0) + { + width_auto = false; + } + else + { + if (computed.width.type == Style::Width::Auto) + { + width_auto = true; + } + else + { + width_auto = false; + content_area.x = ResolveValue(computed.width, containing_block_width); + } + } + + // Determine if the element has automatic margins. + bool margins_auto[2]; + int num_auto_margins = 0; + + for (int i = 0; i < 2; ++i) + { + auto* margin_value = (i == 0 ? &computed.margin_left : &computed.margin_right); + if (margin_value->type == Style::Margin::Auto) + { + margins_auto[i] = true; + num_auto_margins++; + } + else + { + margins_auto[i] = false; + box.SetEdge(Box::MARGIN, i == 0 ? Box::LEFT : Box::RIGHT, ResolveValue(*margin_value, containing_block_width)); + } + } + + // If the width is set to auto, we need to calculate the width + if (width_auto) + { + float left = 0.0f, right = 0.0f; + // If we are dealing with an absolutely positioned element we need to + // consider if the left and right properties are set, since the width can be affected. + if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed) + { + if (computed.left.type != Style::Left::Auto) + left = ResolveValue(computed.left, containing_block_width ); + if (computed.right.type != Style::Right::Auto) + right = ResolveValue(computed.right, containing_block_width); + } + + // We resolve any auto margins to 0 and the width is set to whatever is left of the containing block. + if (margins_auto[0]) + box.SetEdge(Box::MARGIN, Box::LEFT, 0); + if (margins_auto[1]) + box.SetEdge(Box::MARGIN, Box::RIGHT, 0); + + content_area.x = containing_block_width - (left + + box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + + box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT) + + right); + content_area.x = Math::Max(0.0f, content_area.x); + } + // Otherwise, the margins that are set to auto will pick up the remaining width of the containing block. + else if (num_auto_margins > 0) + { + float margin = (containing_block_width - (box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + + box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT) + + content_area.x)) / num_auto_margins; + + if (margins_auto[0]) + box.SetEdge(Box::MARGIN, Box::LEFT, margin); + if (margins_auto[1]) + box.SetEdge(Box::MARGIN, Box::RIGHT, margin); + } + + // Clamp the calculated width; if the width is changed by the clamp, then the margins need to be recalculated if + // they were set to auto. + float clamped_width = ClampWidth(content_area.x, computed, containing_block_width); + if (clamped_width != content_area.x) + { + content_area.x = clamped_width; + box.SetContent(content_area); + + if (num_auto_margins > 0) + { + // Reset the automatic margins. + if (margins_auto[0]) + box.SetEdge(Box::MARGIN, Box::LEFT, 0); + if (margins_auto[1]) + box.SetEdge(Box::MARGIN, Box::RIGHT, 0); + + BuildBoxWidth(box, computed, containing_block_width); + } + } + else + box.SetContent(content_area); +} + +// Builds the block-specific height and vertical margins of a Box. +void LayoutEngine::BuildBoxHeight(Box& box, const ComputedValues& computed, float containing_block_height) +{ + RMLUI_ZoneScoped; + + Vector2f content_area = box.GetSize(); + + // Determine if the element has an automatic height, and if not calculate it. + bool height_auto; + if (content_area.y >= 0) + { + height_auto = false; + } + else + { + if (computed.height.type == Style::Height::Auto) + { + height_auto = true; + } + else + { + height_auto = false; + content_area.y = ResolveValue(computed.height, containing_block_height); + } + } + + // Determine if the element has automatic margins. + bool margins_auto[2]; + int num_auto_margins = 0; + + for (int i = 0; i < 2; ++i) + { + auto* margin_value = (i == 0 ? &computed.margin_top : &computed.margin_bottom); + if (margin_value->type == Style::Margin::Auto) + { + margins_auto[i] = true; + num_auto_margins++; + } + else + { + margins_auto[i] = false; + box.SetEdge(Box::MARGIN, i == 0 ? Box::TOP : Box::BOTTOM, ResolveValue(*margin_value, containing_block_height)); + } + } + + // If the height is set to auto, we need to calculate the height + if (height_auto) + { + // We resolve any auto margins to 0 + if (margins_auto[0]) + box.SetEdge(Box::MARGIN, Box::TOP, 0); + if (margins_auto[1]) + box.SetEdge(Box::MARGIN, Box::BOTTOM, 0); + + // If the height is set to auto for a box in normal flow, the height is set to -1. + content_area.y = -1; + + // But if we are dealing with an absolutely positioned element we need to + // consider if the top and bottom properties are set, since the height can be affected. + if (computed.position == Style::Position::Absolute || computed.position == Style::Position::Fixed) + { + float top = 0.0f, bottom = 0.0f; + + if (computed.top.type != Style::Top::Auto && computed.bottom.type != Style::Bottom::Auto) + { + top = ResolveValue(computed.top, containing_block_height ); + bottom = ResolveValue(computed.bottom, containing_block_height ); + + // The height gets resolved to whatever is left of the containing block + content_area.y = containing_block_height - (top + + box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + + box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM) + + bottom); + content_area.y = Math::Max(0.0f, content_area.y); + } + } + } + // Otherwise, the margins that are set to auto will pick up the remaining width of the containing block. + else if (num_auto_margins > 0) + { + float margin; + if (content_area.y >= 0) + { + margin = (containing_block_height - (box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + + box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM) + + content_area.y)) / num_auto_margins; + } + else + margin = 0; + + if (margins_auto[0]) + box.SetEdge(Box::MARGIN, Box::TOP, margin); + if (margins_auto[1]) + box.SetEdge(Box::MARGIN, Box::BOTTOM, margin); + } + + if (content_area.y >= 0) + { + // Clamp the calculated height; if the height is changed by the clamp, then the margins need to be recalculated if + // they were set to auto. + float clamped_height = ClampHeight(content_area.y, computed, containing_block_height); + if (clamped_height != content_area.y) + { + content_area.y = clamped_height; + box.SetContent(content_area); + + if (num_auto_margins > 0) + { + // Reset the automatic margins. + if (margins_auto[0]) + box.SetEdge(Box::MARGIN, Box::TOP, 0); + if (margins_auto[1]) + box.SetEdge(Box::MARGIN, Box::BOTTOM, 0); + + BuildBoxHeight(box, computed, containing_block_height); + } + + return; + } + } + + box.SetContent(content_area); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/LayoutEngine.h b/thirdparty/RmlUi/Source/Core/LayoutEngine.h new file mode 100644 index 000000000..c01ac8227 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutEngine.h @@ -0,0 +1,128 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LAYOUTENGINE_H +#define RMLUI_CORE_LAYOUTENGINE_H + +#include "LayoutBlockBox.h" + +namespace Rml { + +class Box; + +/** + @author Robert Curry + */ + +class LayoutEngine +{ +public: + /// Constructs a new layout engine. + LayoutEngine(); + ~LayoutEngine(); + + /// Formats the contents for a root-level element (usually a document, floating or replaced element). + /// @param element[in] The element to lay out. + /// @param containing_block[in] The size of the containing block. + bool FormatElement(Element* element, const Vector2f& containing_block, bool shrink_to_fit = false); + + /// Generates the box for an element. + /// @param[out] box The box to be built. + /// @param[in] containing_block The dimensions of the content area of the block containing the element. + /// @param[in] element The element to build the box for. + /// @param[in] inline_element True if the element is placed in an inline context, false if not. + static void BuildBox(Box& box, const Vector2f& containing_block, Element* element, bool inline_element = false); + /// Generates the box for an element placed in a block box. + /// @param[out] box The box to be built. + /// @param[out] min_height The minimum height of the element's box. + /// @param[out] max_height The maximum height of the element's box. + /// @param[in] containing_box The block box containing the element. + /// @param[in] element The element to build the box for. + /// @param[in] inline_element True if the element is placed in an inline context, false if not. + static void BuildBox(Box& box, float& min_height, float& max_height, LayoutBlockBox* containing_box, Element* element, bool inline_element = false); + + /// Clamps the width of an element based from its min-width and max-width properties. + /// @param[in] width The width to clamp. + /// @param[in] element The element to read the properties from. + /// @param[in] containing_block_width The width of the element's containing block. + /// @return The clamped width. + static float ClampWidth(float width, const ComputedValues& computed, float containing_block_width); + /// Clamps the height of an element based from its min-height and max-height properties. + /// @param[in] height The height to clamp. + /// @param[in] element The element to read the properties from. + /// @param[in] containing_block_height The height of the element's containing block. + /// @return The clamped height. + static float ClampHeight(float height, const ComputedValues& computed, float containing_block_height); + + static void* AllocateLayoutChunk(size_t size); + static void DeallocateLayoutChunk(void* chunk); + +private: + /// Positions a single element and its children within this layout. + /// @param[in] element The element to lay out. + bool FormatElement(Element* element); + + /// Formats and positions an element as a block element. + /// @param[in] element The block element. + bool FormatElementBlock(Element* element); + /// Formats and positions an element as an inline element. + /// @param[in] element The inline element. + bool FormatElementInline(Element* element); + /// Positions an element as a sized inline element, formatting its internal hierarchy as a block element. + /// @param[in] element The replaced element. + bool FormatElementReplaced(Element* element); + /// Executes any special formatting for special elements. + /// @param[in] element The element to parse. + /// @return True if the element was parsed as a special element, false otherwise. + bool FormatElementSpecial(Element* element); + + /// Returns the fully-resolved, fixed-width and -height containing block from a block box. + /// @param[in] containing_box The leaf box. + /// @return The dimensions of the content area, using the latest fixed dimensions for width and height in the hierarchy. + static Vector2f GetContainingBlock(const LayoutBlockBox* containing_box); + + /// Builds the block-specific width and horizontal margins of a Box. + /// @param[in,out] box The box to generate. The padding and borders must be set on the box already. If the content area is sized, then it will be used instead of the width property. + /// @param[in] element The element the box is being generated for. + /// @param[in] containing_block_width The width of the containing block. + static void BuildBoxWidth(Box& box, const ComputedValues& computed, float containing_block_width); + /// Builds the block-specific height and vertical margins of a Box. + /// @param[in,out] box The box to generate. The padding and borders must be set on the box already. If the content area is sized, then it will be used instead of the height property. + /// @param[in] element The element the box is being generated for. + /// @param[in] containing_block_height The height of the containing block. + static void BuildBoxHeight(Box& box, const ComputedValues& computed, float containing_block_height); + + // The root block box, representing the document. + LayoutBlockBox* block_box; + + // The open block box containing displaying in a block-context. + LayoutBlockBox* block_context_box; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/LayoutInlineBox.cpp b/thirdparty/RmlUi/Source/Core/LayoutInlineBox.cpp new file mode 100644 index 000000000..9288b7d3c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutInlineBox.cpp @@ -0,0 +1,417 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LayoutInlineBox.h" +#include "LayoutBlockBox.h" +#include "LayoutEngine.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/Property.h" + +namespace Rml { + +// Constructs a new inline box for an element. +LayoutInlineBox::LayoutInlineBox(Element* _element, const Box& _box) : position(0, 0), box(_box) +{ + line = nullptr; + + parent = nullptr; + element = _element; + + width = 0; + + // If this box has intrinsic dimensions, then we set our height to the total height of the element; otherwise, it + // is zero height. + if (box.GetSize().y > 0) + { + height = box.GetSize(Box::MARGIN).y; + baseline = element->GetBaseline() + box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM); + } + else + { + FontFaceHandle font_face = element->GetFontFaceHandle(); + if (font_face != 0) + { + height = element->GetLineHeight(); + baseline = (height - GetFontEngineInterface()->GetLineHeight(font_face)) * 0.5f + GetFontEngineInterface()->GetBaseline(font_face); + } + else + { + height = 0; + baseline = 0; + } + } + + vertical_align_property = element->GetComputedValues().vertical_align; + + chained = false; + chain = nullptr; +} + +// Constructs a new inline box for a split box. +LayoutInlineBox::LayoutInlineBox(LayoutInlineBox* _chain) : position(0, 0), box(_chain->GetBox()) +{ + line = nullptr; + + parent = nullptr; + element = _chain->element; + + width = 0; + height = _chain->height; + baseline = _chain->baseline; + vertical_align_property = _chain->vertical_align_property; + + _chain->chain = this; + chain = nullptr; + chained = true; + + // As we're a split box, our left side is cleared and content set back to (-1, -1). + box.SetEdge(Box::PADDING, Box::LEFT, 0); + box.SetEdge(Box::BORDER, Box::LEFT, 0); + box.SetEdge(Box::MARGIN, Box::LEFT, 0); + box.SetContent(Vector2f(-1, -1)); +} + +LayoutInlineBox::~LayoutInlineBox() +{ +} + +// Sets the inline box's line. +void LayoutInlineBox::SetLine(LayoutLineBox* _line) +{ + line = _line; +} + +// Sets the inline box's parent. +void LayoutInlineBox::SetParent(LayoutInlineBox* _parent) +{ + parent = _parent; + if (parent != nullptr) + parent->children.push_back(this); +} + +// Closes the box. +void LayoutInlineBox::Close() +{ + if (chain) + chain->Close(); + else + { + RMLUI_ASSERT(line != nullptr); + line->CloseInlineBox(this); + } +} + +// Returns true if this box needs to close on its line. +bool LayoutInlineBox::CanOverflow() const +{ + return box.GetSize().x < 0; +} + +// Returns true if this box's element is the last child of its parent. +bool LayoutInlineBox::IsLastChild() const +{ + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return true; + + return parent->GetLastChild() == element; +} + +// Flows the inline box's content into its parent line. +LayoutInlineBox* LayoutInlineBox::FlowContent(bool RMLUI_UNUSED_PARAMETER(first_box), float RMLUI_UNUSED_PARAMETER(available_width), float RMLUI_UNUSED_PARAMETER(right_spacing_width)) +{ + RMLUI_UNUSED(first_box); + RMLUI_UNUSED(available_width); + RMLUI_UNUSED(right_spacing_width); + + // If we're representing a sized element, then add our element's width onto our parent's. + if (parent != nullptr && + box.GetSize().x > 0) + parent->width += box.GetSize(Box::MARGIN).x; + + // Nothing else to do here; static elements will automatically be 'flowed' into their lines when they are placed. + return nullptr; +} + +// Computes and sets the vertical position of this element, relative to its parent box. +void LayoutInlineBox::CalculateBaseline(float& ascender, float& descender) +{ + using namespace Style; + // We're vertically-aligned with one of the standard types. + switch (vertical_align_property.type) + { + // Aligned with our parent box's baseline, our relative vertical position is set to 0. + case VerticalAlign::Baseline: + { + SetVerticalPosition(0); + } + break; + + // The middle of this box is aligned with the baseline of its parent's plus half an ex. + case VerticalAlign::Middle: + { + FontFaceHandle parent_font = GetParentFont(); + int x_height = 0; + if (parent_font != 0) + x_height = GetFontEngineInterface()->GetXHeight(parent_font) / -2; + + SetVerticalPosition(x_height + (height / 2 - baseline)); + } + break; + + // This box's baseline is offset from its parent's so it is appropriate for rendering subscript. + case VerticalAlign::Sub: + { + FontFaceHandle parent_font = GetParentFont(); + if (parent_font == 0) + SetVerticalPosition(0); + else + SetVerticalPosition(float(GetFontEngineInterface()->GetLineHeight(parent_font)) * 0.2f); + } + break; + + // This box's baseline is offset from its parent's so it is appropriate for rendering superscript. + case VerticalAlign::Super: + { + FontFaceHandle parent_font = GetParentFont(); + if (parent_font == 0) + SetVerticalPosition(0); + else + SetVerticalPosition(float(-1 * GetFontEngineInterface()->GetLineHeight(parent_font)) * 0.4f); + } + break; + + // The top of this box is aligned to the top of its parent's font. + case VerticalAlign::TextTop: + { + FontFaceHandle parent_font = GetParentFont(); + if (parent_font == 0) + SetVerticalPosition(0); + else + SetVerticalPosition((height - baseline) - (GetFontEngineInterface()->GetLineHeight(parent_font) - GetFontEngineInterface()->GetBaseline(parent_font))); + } + break; + + // The bottom of this box is aligned to the bottom of its parent's font (not the baseline). + case VerticalAlign::TextBottom: + { + FontFaceHandle parent_font = GetParentFont(); + if (parent_font == 0) + SetVerticalPosition(0); + else + SetVerticalPosition(GetFontEngineInterface()->GetBaseline(parent_font) - baseline); + } + break; + + // This box is aligned with the line box, not an inline box, so we can't position it yet. + case VerticalAlign::Top: + case VerticalAlign::Bottom: + break; + + // The baseline of this box is offset by a fixed amount from its parent's baseline. + case VerticalAlign::Length: + default: + { + SetVerticalPosition(-1.f * vertical_align_property.value); + } + break; + } + + // Set the ascender and descender relative to this element. If we're an unsized element (span, em, etc) then we + // have no dimensions ourselves. + if (box.GetSize() == Vector2f(-1, -1)) + { + ascender = 0; + descender = 0; + } + else + { + ascender = height - baseline; + descender = height - ascender; + } + + for (size_t i = 0; i < children.size(); ++i) + { + // Don't include any of our children that are aligned relative to the line box; the line box treats them + // separately. + if (children[i]->GetVerticalAlignProperty().type != Style::VerticalAlign::Top && + children[i]->GetVerticalAlignProperty().type != Style::VerticalAlign::Bottom) + { + float child_ascender, child_descender; + children[i]->CalculateBaseline(child_ascender, child_descender); + + ascender = Math::Max(ascender, child_ascender - children[i]->GetPosition().y); + descender = Math::Max(descender, child_descender + children[i]->GetPosition().y); + } + } +} + +// Offsets the baseline of this box, and all of its children, by the ascender of the parent line box. +void LayoutInlineBox::OffsetBaseline(float ascender) +{ + for (size_t i = 0; i < children.size(); ++i) + { + // Don't offset any of our children that are aligned relative to the line box; the line box will take care of + // them separately. + if (children[i]->GetVerticalAlignProperty().type != Style::VerticalAlign::Top && + children[i]->GetVerticalAlignProperty().type != Style::VerticalAlign::Bottom) + children[i]->OffsetBaseline(ascender + position.y); + } + + position.y += (ascender - (height - baseline)); +} + +// Returns the inline box's offset from its parent's content area. +const Vector2f& LayoutInlineBox::GetPosition() const +{ + return position; +} + +// Sets the inline box's relative horizontal offset from its parent's content area. +void LayoutInlineBox::SetHorizontalPosition(float _position) +{ + position.x = _position; +} + +// Sets the inline box's relative vertical offset from its parent's content area. +void LayoutInlineBox::SetVerticalPosition(float _position) +{ + position.y = _position; +} + +void LayoutInlineBox::PositionElement() +{ + if (box.GetSize() == Vector2f(-1, -1)) + { + // If this unsised element has any top margins, border or padding, then shift the position up so the borders + // and background will render in the right place. + position.y -= box.GetCumulativeEdge(Box::CONTENT, Box::TOP); + } + // Otherwise; we're a sized element (replaced or inline-block), so we need to offset our element's vertical + // position by our top margin (as the origin of an element is the top-left of the border, not the margin). + else + position.y += box.GetEdge(Box::MARGIN, Box::TOP); + + if (!chained) + element->SetOffset(line->GetRelativePosition() + position, line->GetBlockBox()->GetOffsetParent()->GetElement()); +} + +// Sizes the inline box's element. +void LayoutInlineBox::SizeElement(bool split) +{ + // Resize the box for an unsized inline element. + if (box.GetSize() == Vector2f(-1, -1)) + { + box.SetContent(Vector2f(width, element->GetLineHeight())); + if (parent != nullptr) + parent->width += width; + } + + Box element_box = box; + if (split) + { + element_box.SetEdge(Box::MARGIN, Box::RIGHT, 0); + element_box.SetEdge(Box::BORDER, Box::RIGHT, 0); + element_box.SetEdge(Box::PADDING, Box::RIGHT, 0); + } + + // The elements of a chained box have already had their positions set by the first link. + if (chained) + { + element_box.SetOffset((line->GetPosition() + position) - element->GetRelativeOffset(Box::BORDER)); + element->AddBox(element_box); + + if (chain != nullptr) + element->OnLayout(); + } + else + { + element->SetBox(element_box); + element->OnLayout(); + } +} + +// Returns the vertical align property of the box's element. +Style::VerticalAlign LayoutInlineBox::GetVerticalAlignProperty() const +{ + return vertical_align_property; +} + +// Returns the inline box's element. +Element* LayoutInlineBox::GetElement() +{ + return element; +} + +// Returns the inline box's parent. +LayoutInlineBox* LayoutInlineBox::GetParent() +{ + return parent; +} + +// Returns the inline box's dimension box. +const Box& LayoutInlineBox::GetBox() const +{ + return box; +} + +// Returns the height of the inline box. +float LayoutInlineBox::GetHeight() const +{ + return height; +} + +// Returns the baseline of the inline box. +float LayoutInlineBox::GetBaseline() const +{ + return baseline; +} + +void* LayoutInlineBox::operator new(size_t size) +{ + return LayoutEngine::AllocateLayoutChunk(size); +} + +void LayoutInlineBox::operator delete(void* chunk) +{ + LayoutEngine::DeallocateLayoutChunk(chunk); +} + +// Returns our parent box's font face handle. +FontFaceHandle LayoutInlineBox::GetParentFont() const +{ + if (parent == nullptr) + return line->GetBlockBox()->GetParent()->GetElement()->GetFontFaceHandle(); + else + return parent->GetElement()->GetFontFaceHandle(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/LayoutInlineBox.h b/thirdparty/RmlUi/Source/Core/LayoutInlineBox.h new file mode 100644 index 000000000..6d34c9d1a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutInlineBox.h @@ -0,0 +1,176 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LAYOUTINLINEBOX_H +#define RMLUI_CORE_LAYOUTINLINEBOX_H + +#include "../../Include/RmlUi/Core/Box.h" +#include "../../Include/RmlUi/Core/ComputedValues.h" + +namespace Rml { + +class Element; +class ElementText; +class FontFaceHandleDefault; +class LayoutBlockBox; +class LayoutLineBox; + +/** + @author Peter Curry + */ + +class LayoutInlineBox +{ +public: + /// Constructs a new inline box for an element. + /// @param element[in] The element this inline box is flowing. + /// @param box[in] The extents of the inline box's element. + LayoutInlineBox(Element* element, const Box& box); + /// Constructs a new inline box for a split box. + /// @param chain[in] The box that has overflowed into us. + LayoutInlineBox(LayoutInlineBox* chain); + virtual ~LayoutInlineBox(); + + /// Sets the inline box's line. + /// @param line[in] The line this inline box resides in. + void SetLine(LayoutLineBox* line); + /// Sets the inline box's parent. + /// @param parent[in] The parent this inline box resides in. + void SetParent(LayoutInlineBox* parent); + + /// Closes the box. + void Close(); + + /// Flows the inline box's content into its parent line. + /// @param[in] first_box True if this box is the first box containing content to be flowed into this line. + /// @param[in] available_width The width available for flowing this box's content. This is measured from the left side of this box's content area. + /// @param[in] right_spacing_width The width of the spacing that must be left on the right of the element if no overflow occurs. If overflow occurs, then the entire width can be used. + /// @return The overflow box containing any content that spilled over from the flow. This must be nullptr if no overflow occured. + virtual LayoutInlineBox* FlowContent(bool first_box, float available_width, float right_spacing_width); + + /// Computes and sets the vertical position of this element, relative to its parent inline box (or block box, + /// for an un-nested inline box). + /// @param ascender[out] The maximum ascender of this inline box and all of its children. + /// @param descender[out] The maximum descender of this inline box and all of its children. + virtual void CalculateBaseline(float& ascender, float& descender); + /// Offsets the baseline of this box, and all of its children, by the ascender of the parent line box. + /// @param ascender[in] The ascender of the line box. + virtual void OffsetBaseline(float ascender); + + /// Returns true if this box is capable of overflowing, or if it must be rendered on a single line. + /// @return True if this box can overflow, false otherwise. + virtual bool CanOverflow() const; + /// Returns true if this box's element is the last child of its parent. + /// @param True if this box is a last child. + bool IsLastChild() const; + + /// Returns the inline box's offset from its line. + /// @return The box's offset from its line. + const Vector2f& GetPosition() const; + + /// Sets the inline box's horizontal offset from its parent's content area. + /// @param position[in] The box's horizontal offset. + void SetHorizontalPosition(float position); + /// Sets the inline box's vertical offset from its parent's content area. + /// @param position[in] The box's vertical offset. + void SetVerticalPosition(float position); + + /// Positions the inline box's element. + virtual void PositionElement(); + /// Sizes the inline box's element. + /// @param split[in] True if this box is split, false otherwise. + virtual void SizeElement(bool split); + + /// Returns the vertical align property of the box's element. + /// @return the vertical align property, or -1 if it is set to a numerical value. + Style::VerticalAlign GetVerticalAlignProperty() const; + + /// Returns the inline box's element. + /// @return The inline box's element. + Element* GetElement(); + + /// Returns the inline box's parent. + /// @param The parent of this inline box. This will be nullptr for a root-level inline box (ie, one that has a block element has a parent in the true hierarchy). + LayoutInlineBox* GetParent(); + + /// Returns the inline box's dimension box. + /// @return The inline box's dimension box. + const Box& GetBox() const; + /// Returns the height of the inline box. This is separate from the the box, as different types of inline + /// elements generate different line heights. The possible types are: + /// * replaced elements (or inline-block elements), which use their entire box (including margins) as their + /// height + /// * non-replaced elements, which use the maximum line-height of their children + /// * text elements, which use their line-height + float GetHeight() const; + /// Returns the baseline of the inline box. + /// @return The box's baseline. + float GetBaseline() const; + + void* operator new(size_t size); + void operator delete(void* chunk); + +protected: + /// Returns our parent box's font face handle. + /// @return The font face handle of our parent box. + FontFaceHandle GetParentFont() const; + + // The box's element. + Element* element; + + // The line box's offset relative to its parent block box. + Vector2f position; + // The element's inline box. + Box box; + // The inline box's width; note that this is stored separately from the box dimensions. It is only used by + // nesting inline boxes, such as HTML spans containing text. + float width; + // The inline box's height; note that this is stored separately from the box dimensions, as inline elements + // don't necessarily have identical relationships between their box dimensions and line height. + float height; + + // The value of this box's element's vertical-align property. + Style::VerticalAlign vertical_align_property; + // The baseline of the inline element. + float baseline; + + // The inline box's parent; this will be nullptr if we're not a nested inline element. + LayoutInlineBox* parent; + // This inline box's line. + LayoutLineBox* line; + + Vector< LayoutInlineBox* > children; + + // The next link in our element's chain of inline boxes. + LayoutInlineBox* chain; + // True if we're a link in a chain of inline boxes flowing from previous lines. + bool chained; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/LayoutInlineBoxText.cpp b/thirdparty/RmlUi/Source/Core/LayoutInlineBoxText.cpp new file mode 100644 index 000000000..bdb725e7f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutInlineBoxText.cpp @@ -0,0 +1,169 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LayoutInlineBoxText.h" +#include "LayoutEngine.h" +#include "LayoutLineBox.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/FontEngineInterface.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/Profiling.h" + +namespace Rml { + +LayoutInlineBoxText::LayoutInlineBoxText(Element* element, int _line_begin) : LayoutInlineBox(element, Box()) +{ + line_begin = _line_begin; + + // Build the box to represent the dimensions of the first word. + BuildWordBox(); +} + +LayoutInlineBoxText::~LayoutInlineBoxText() +{ +} + +// Returns true if this box is capable of overflowing, or if it must be rendered on a single line. +bool LayoutInlineBoxText::CanOverflow() const +{ + return line_segmented; +} + +// Flows the inline box's content into its parent line. +LayoutInlineBox* LayoutInlineBoxText::FlowContent(bool first_box, float available_width, float right_spacing_width) +{ + ElementText* text_element = GetTextElement(); + RMLUI_ASSERT(text_element != nullptr); + + int line_length; + float line_width; + bool overflow = !text_element->GenerateLine(line_contents, line_length, line_width, line_begin, available_width, right_spacing_width, first_box, true); + + Vector2f content_area; + content_area.x = line_width; + content_area.y = box.GetSize().y; + box.SetContent(content_area); + + // Call the base-class's FlowContent() to increment the width of our parent's box. + LayoutInlineBox::FlowContent(first_box, available_width, right_spacing_width); + + if (overflow) + return new LayoutInlineBoxText(element, line_begin + line_length); + + return nullptr; +} + +// Computes and sets the vertical position of this element, relative to its parent inline box (or block box, for an un-nested inline box). +void LayoutInlineBoxText::CalculateBaseline(float& ascender, float& descender) +{ + ascender = height - baseline; + descender = height - ascender; +} + +// Offsets the baseline of this box, and all of its children, by the ascender of the parent line box. +void LayoutInlineBoxText::OffsetBaseline(float ascender) +{ + // Offset by the ascender. + position.y += (ascender - (height - baseline)); + + // Calculate the leading (the difference between font height and line height). + float leading = 0; + + FontFaceHandle font_face_handle = element->GetFontFaceHandle(); + if (font_face_handle != 0) + leading = height - GetFontEngineInterface()->GetLineHeight(font_face_handle); + + // Offset by the half-leading. + position.y += leading * 0.5f; +} + +// Positions the inline box's element. +void LayoutInlineBoxText::PositionElement() +{ + if (line_begin == 0) + { + LayoutInlineBox::PositionElement(); + + GetTextElement()->ClearLines(); + GetTextElement()->AddLine(Vector2f(0, 0), line_contents); + } + else + { + GetTextElement()->AddLine(line->GetRelativePosition() + position - element->GetRelativeOffset(Box::BORDER), line_contents); + } +} + +// Sizes the inline box's element. +void LayoutInlineBoxText::SizeElement(bool RMLUI_UNUSED_PARAMETER(split)) +{ + RMLUI_UNUSED(split); +} + +void* LayoutInlineBoxText::operator new(size_t size) +{ + return LayoutEngine::AllocateLayoutChunk(size); +} + +void LayoutInlineBoxText::operator delete(void* chunk) +{ + LayoutEngine::DeallocateLayoutChunk(chunk); +} + +// Returns the box's element as a text element. +ElementText* LayoutInlineBoxText::GetTextElement() +{ + return rmlui_dynamic_cast< ElementText* >(element); +} + +// Builds a box for the first word of the element. +void LayoutInlineBoxText::BuildWordBox() +{ + RMLUI_ZoneScoped; + + ElementText* text_element = GetTextElement(); + RMLUI_ASSERT(text_element != nullptr); + + FontFaceHandle font_face_handle = text_element->GetFontFaceHandle(); + if (font_face_handle == 0) + { + height = 0; + baseline = 0; + Log::Message(Log::LT_WARNING, "No font face defined on element %s. Please specify a font-family in your RCSS, otherwise make sure Context::Update is run after new elements are constructed, before Context::Render.", text_element->GetAddress().c_str()); + return; + } + + Vector2f content_area; + line_segmented = !text_element->GenerateToken(content_area.x, line_begin); + content_area.y = element->GetLineHeight(); + box.SetContent(content_area); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/LayoutInlineBoxText.h b/thirdparty/RmlUi/Source/Core/LayoutInlineBoxText.h new file mode 100644 index 000000000..73114800a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutInlineBoxText.h @@ -0,0 +1,95 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LAYOUTINLINEBOXTEXT_H +#define RMLUI_CORE_LAYOUTINLINEBOXTEXT_H + +#include "LayoutInlineBox.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class LayoutInlineBoxText : public LayoutInlineBox +{ +public: + /// Constructs a new inline box for a text element. + /// @param[in] element The element this inline box is flowing. + /// @param[in] line_begin The index of the first character of the element's string this text box will render. + LayoutInlineBoxText(Element* element, int line_begin = 0); + virtual ~LayoutInlineBoxText(); + + /// Returns true if this box is capable of overflowing, or if it must be rendered on a single line. + /// @return True if this box can overflow, false otherwise. + bool CanOverflow() const override; + + /// Flows the inline box's content into its parent line. + /// @param[in] first_box True if this box is the first box containing content to be flowed into this line. + /// @param available_width[in] The width available for flowing this box's content. This is measured from the left side of this box's content area. + /// @param right_spacing_width[in] The width of the spacing that must be left on the right of the element if no overflow occurs. If overflow occurs, then the entire width can be used. + /// @return The overflow box containing any content that spilled over from the flow. This must be nullptr if no overflow occured. + LayoutInlineBox* FlowContent(bool first_box, float available_width, float right_spacing_width) override; + + /// Computes and sets the vertical position of this element, relative to its parent inline box (or block box, + /// for an un-nested inline box). + /// @param ascender[out] The maximum ascender of this inline box and all of its children. + /// @param descender[out] The maximum descender of this inline box and all of its children. + void CalculateBaseline(float& ascender, float& descender) override; + /// Offsets the baseline of this box, and all of its children, by the ascender of the parent line box. + /// @param ascender[in] The ascender of the line box. + void OffsetBaseline(float ascender) override; + + /// Positions the inline box's element. + void PositionElement() override; + /// Sizes the inline box's element. + void SizeElement(bool split) override; + + void* operator new(size_t size); + void operator delete(void* chunk); + +private: + /// Returns the box's element as a text element. + /// @return The box's element cast to a text element. + ElementText* GetTextElement(); + + /// Builds a box for the first word of the element. + void BuildWordBox(); + + // The index of the first character of this line. + int line_begin; + // The contents on this line. + String line_contents; + + // True if this line can be segmented into parts, false if it consists of only a single word. + bool line_segmented; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/LayoutLineBox.cpp b/thirdparty/RmlUi/Source/Core/LayoutLineBox.cpp new file mode 100644 index 000000000..82218b071 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutLineBox.cpp @@ -0,0 +1,391 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LayoutLineBox.h" +#include "LayoutBlockBox.h" +#include "LayoutEngine.h" +#include "LayoutInlineBoxText.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include + +namespace Rml { + +static float GetSpacing(const Box& box, Box::Edge edge) +{ + return box.GetEdge(Box::PADDING, edge) + + box.GetEdge(Box::BORDER, edge) + + box.GetEdge(Box::MARGIN, edge); +} + +LayoutLineBox::LayoutLineBox(LayoutBlockBox* _parent) : position(-1, -1), dimensions(-1, -1) +{ + parent = _parent; + + box_cursor = 0; + open_inline_box = nullptr; + + position_set = false; + wrap_content = false; +} + +LayoutLineBox::~LayoutLineBox() +{ + for (size_t i = 0; i < inline_boxes.size(); i++) + delete inline_boxes[i]; +} + +// Closes the line box, positioning all inline elements within it. +LayoutInlineBox* LayoutLineBox::Close(LayoutInlineBox* overflow) +{ + RMLUI_ZoneScoped; + + // If we haven't positioned this line yet, and it has elements in it, then this is a great opportunity to do so. + if (!position_set && + !inline_boxes.empty()) + { + parent->PositionLineBox(position, dimensions.x, wrap_content, Vector2f(0, 0)); + dimensions.y = 0; + + position_set = true; + } + // If the line has been positioned and our content is greater than our original size (for example, if we aren't + // wrapping or had to render a very long word), then we push our dimensions out to compensate. + else + dimensions.x = Math::Max(dimensions.x, box_cursor); + + // Now we calculate the baselines of each of our inline boxes relative to their parent box's baseline; either us, + // or another of our inline boxes. The maximum distance each element is above and below our baseline is calculated + // from that, and therefore our height. + float ascender = 0; + float descender = 0; + float minimum_height = 0; + + for (size_t i = 0; i < inline_boxes.size(); ++i) + { + LayoutInlineBox* inline_box = inline_boxes[i]; + + // Check if we've got an element aligned to the line box rather than a baseline. + if (inline_box->GetVerticalAlignProperty().type == Style::VerticalAlign::Top || + inline_box->GetVerticalAlignProperty().type == Style::VerticalAlign::Bottom) + { + // Get this element to calculate the baseline offsets of its children; it can't calculate its own baseline + // because we don't know the height of the line box yet. We don't actually care about its ascender or + // descender either, just its height. + float box_ascender, box_descender; + inline_box->CalculateBaseline(box_ascender, box_descender); + + minimum_height = Math::Max(minimum_height, inline_box->GetHeight()); + } + // Otherwise, we have an element anchored to a baseline, so we can fetch its ascender and descender relative + // to our baseline. + else if (inline_box->GetParent() == nullptr) + { + float box_ascender, box_descender; + inline_box->CalculateBaseline(box_ascender, box_descender); + + ascender = Math::Max(ascender, box_ascender - inline_box->GetPosition().y); + descender = Math::Max(descender, box_descender + inline_box->GetPosition().y); + } + } + + // We've now got the maximum ascender and descender, we can calculate the dimensions of the line box. + dimensions.y = Math::Max(minimum_height, ascender + descender); + // And from that, we can now set the final baseline of each box. + for (size_t i = 0; i < inline_boxes.size(); ++i) + { + LayoutInlineBox* inline_box = inline_boxes[i]; + + // Check again if this element is aligned to the line box. We don't need to worry about offsetting an element + // tied to the top of the line box, as its position will always stay at exactly 0. + if (inline_box->GetVerticalAlignProperty().type == Style::VerticalAlign::Top|| + inline_box->GetVerticalAlignProperty().type == Style::VerticalAlign::Bottom) + { + if (inline_box->GetVerticalAlignProperty().type == Style::VerticalAlign::Top) + inline_box->OffsetBaseline(inline_box->GetHeight() - inline_box->GetBaseline()); + else + inline_box->OffsetBaseline(dimensions.y - inline_box->GetBaseline()); + } + // Otherwise, this element is tied to a baseline. + else if (inline_box->GetParent() == nullptr) + inline_box->OffsetBaseline(ascender); + } + + // Position all the boxes horizontally in the line. We only need to reposition the elements if they're set to + // centre or right; the element are already placed left-aligned, and justification occurs at the text level. + Style::TextAlign text_align_property = parent->GetParent()->GetElement()->GetComputedValues().text_align; + if (text_align_property == Style::TextAlign::Center || + text_align_property == Style::TextAlign::Right) + { + float element_offset = 0; + switch (text_align_property) + { + case Style::TextAlign::Center: element_offset = (dimensions.x - box_cursor) * 0.5f; break; + case Style::TextAlign::Right: element_offset = (dimensions.x - box_cursor); break; + default: break; + } + + if (element_offset != 0) + { + for (size_t i = 0; i < inline_boxes.size(); i++) + inline_boxes[i]->SetHorizontalPosition(inline_boxes[i]->GetPosition().x + element_offset); + } + } + + // Get each line box to set the position of their element, relative to their parents. + for (int i = (int) inline_boxes.size() - 1; i >= 0; --i) + { + inline_boxes[i]->PositionElement(); + + // Check if this inline box is part of the open box chain. + bool inline_box_open = false; + LayoutInlineBox* open_box = open_inline_box; + while (open_box != nullptr && + !inline_box_open) + { + if (inline_boxes[i] == open_box) + inline_box_open = true; + + open_box = open_box->GetParent(); + } + + inline_boxes[i]->SizeElement(inline_box_open); + } + + return parent->CloseLineBox(this, overflow, open_inline_box); +} + +// Closes one of the line box's inline boxes. +void LayoutLineBox::CloseInlineBox(LayoutInlineBox* inline_box) +{ + RMLUI_ASSERT(open_inline_box == inline_box); + + open_inline_box = inline_box->GetParent(); + box_cursor += GetSpacing(inline_box->GetBox(), Box::RIGHT); +} + +// Attempts to add a new element to this line box. +LayoutInlineBox* LayoutLineBox::AddElement(Element* element, const Box& box) +{ + RMLUI_ZoneScoped; + + if (rmlui_dynamic_cast< ElementText* >(element) != nullptr) + return AddBox(new LayoutInlineBoxText(element)); + else + return AddBox(new LayoutInlineBox(element, box)); +} + +// Attempts to add a new inline box to this line. +LayoutInlineBox* LayoutLineBox::AddBox(LayoutInlineBox* box) +{ + RMLUI_ZoneScoped; + + // Set to true if we're flowing the first box (with content) on the line. + bool first_box = false; + // The spacing this element must leave on the right of the line, to account not only for its margins and padding, + // but also for its parents which will close immediately after it. + float right_spacing; + + // If this line is unplaced, then this is the first inline box; if it is sized, then we can place and size this + // line. + if (!position_set) + { + // Add the new box to the list of boxes in the line box. As this line box has not been placed, we don't have to + // check if it can fit yet. + AppendBox(box); + + // If the new box has a physical prescence, then we must place this line once we've figured out how wide it has to + // be. + if (box->GetBox().GetSize().x >= 0) + { + // Calculate the dimensions for the box we need to fit. + Vector2f minimum_dimensions = box->GetBox().GetSize(); + + // Add the width of any empty, already closed tags, or still opened spaced tags. + minimum_dimensions.x += box_cursor; + + // Calculate the right spacing for the element. + right_spacing = GetSpacing(box->GetBox(), Box::RIGHT); + // Add the right spacing for any ancestor elements that must close immediately after it. + LayoutInlineBox* closing_box = box; + while (closing_box && closing_box->IsLastChild()) + { + closing_box = closing_box->GetParent(); + if (closing_box) + right_spacing += GetSpacing(closing_box->GetBox(), Box::RIGHT); + } + + if (!box->CanOverflow()) + minimum_dimensions.x += right_spacing; + + parent->PositionLineBox(position, dimensions.x, wrap_content, minimum_dimensions); + dimensions.y = minimum_dimensions.y; + + first_box = true; + position_set = true; + } + else + return box; + } + + // This line has already been placed and sized, so we'll check if we can fit this new inline box on the line. + else + { + // Build up the spacing required on the right side of this element. This consists of the right spacing on the + // new element, and the right spacing on all parent element that will close next. + right_spacing = GetSpacing(box->GetBox(), Box::RIGHT); + if (open_inline_box != nullptr && + box->IsLastChild()) + { + LayoutInlineBox* closing_box = open_inline_box; + while (closing_box != nullptr && + closing_box->IsLastChild()) + { + closing_box = closing_box->GetParent(); + if (closing_box != nullptr) + right_spacing += GetSpacing(closing_box->GetBox(), Box::RIGHT); + } + } + + // Determine the inline box's spacing requirements (before we get onto it's actual content width). + float element_width = box->GetBox().GetPosition(Box::CONTENT).x; + if (!box->CanOverflow()) + element_width += right_spacing; + + // Add on the box's content area (if it has content). + if (box->GetBox().GetSize().x >= 0) + element_width += box->GetBox().GetSize().x; + + if (wrap_content && + box_cursor + element_width > dimensions.x) + { + // We can't fit the new inline element into this box! So we'll close this line box, and send the inline box + // onto the next line. + return Close(box); + } + else + { + // We can fit the new inline element into this box. + AppendBox(box); + } + } + + // Flow the box's content into the line. + LayoutInlineBox* overflow_box = open_inline_box->FlowContent(first_box, wrap_content ? dimensions.x - (open_inline_box->GetPosition().x + open_inline_box->GetBox().GetPosition(Box::CONTENT).x) : -1, right_spacing); + box_cursor += open_inline_box->GetBox().GetSize().x; + + // If our box overflowed, then we'll close this line (as no more content will fit onto it) and tell our block box + // to make a new line. + if (overflow_box != nullptr) + { + open_inline_box = open_inline_box->GetParent(); + return Close(overflow_box); + } + + return open_inline_box; +} + +// Adds an inline box as a chained hierarchy overflowing to this line. +void LayoutLineBox::AddChainedBox(LayoutInlineBox* chained_box) +{ + Stack< LayoutInlineBox* > hierarchy; + LayoutInlineBox* chain = chained_box; + while (chain != nullptr) + { + hierarchy.push(chain); + chain = chain->GetParent(); + } + + while (!hierarchy.empty()) + { + AddBox(new LayoutInlineBox(hierarchy.top())); + hierarchy.pop(); + } +} + +// Returns the position of the line box, relative to its parent's block box's content area. +const Vector2f& LayoutLineBox::GetPosition() const +{ + return position; +} + +// Returns the position of the line box, relative to its parent's block box's offset parent. +Vector2f LayoutLineBox::GetRelativePosition() const +{ + return position - (parent->GetOffsetParent()->GetPosition() - parent->GetOffsetRoot()->GetPosition()); +} + +// Returns the dimensions of the line box. +const Vector2f& LayoutLineBox::GetDimensions() const +{ + return dimensions; +} + +// Returns the line box's open inline box. +LayoutInlineBox* LayoutLineBox::GetOpenInlineBox() +{ + return open_inline_box; +} + +// Returns the line's containing block box. +LayoutBlockBox* LayoutLineBox::GetBlockBox() +{ + return parent; +} + +float LayoutLineBox::GetBoxCursor() const +{ + return box_cursor; +} + +void* LayoutLineBox::operator new(size_t size) +{ + return LayoutEngine::AllocateLayoutChunk(size); +} + +void LayoutLineBox::operator delete(void* chunk) +{ + LayoutEngine::DeallocateLayoutChunk(chunk); +} + +// Appends an inline box to the end of the line box's list of inline boxes. +void LayoutLineBox::AppendBox(LayoutInlineBox* box) +{ + inline_boxes.push_back(box); + + box->SetParent(open_inline_box); + box->SetLine(this); + box->SetHorizontalPosition(box_cursor + box->GetBox().GetEdge(Box::MARGIN, Box::LEFT)); + box_cursor += GetSpacing(box->GetBox(), Box::LEFT); + + open_inline_box = box; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/LayoutLineBox.h b/thirdparty/RmlUi/Source/Core/LayoutLineBox.h new file mode 100644 index 000000000..27343fd95 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/LayoutLineBox.h @@ -0,0 +1,123 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_LAYOUTLINEBOX_H +#define RMLUI_CORE_LAYOUTLINEBOX_H + +#include "LayoutInlineBox.h" + +namespace Rml { + +class LayoutBlockBox; + +/** + @author Peter Curry + */ + +class LayoutLineBox +{ +public: + LayoutLineBox(LayoutBlockBox* parent); + ~LayoutLineBox(); + + /// Closes the line box, positioning all inline elements within it. + /// @param overflow[in] The overflow box from a split inline box that caused this line to close. Leave this as nullptr if we closed naturally. + /// @return If there was any overflow, this will be the last element generated by the spilling content. Otherwise, this will be nullptr. + LayoutInlineBox* Close(LayoutInlineBox* overflow = nullptr); + + /// Closes one of the line box's inline boxes. + /// @param inline_box[in] The inline box to close. This should always be the line box's open box. + void CloseInlineBox(LayoutInlineBox* inline_box); + + /// Attempts to add a new element to this line box. If it can't fit, or needs to be split, new line boxes will + /// be created. The inline box for the final section of the element will be returned. + /// @param element[in] The element to fit into this line box. + /// @param box[in] The element's extents. + /// @return The inline box for the element. + LayoutInlineBox* AddElement(Element* element, const Box& box); + + /// Attempts to add a new inline box to this line. If it can't fit, or needs to be split, new line boxes will + /// be created. The inline box for the final section of the element will be returned. + /// @param box[in] The inline box to be added to the line. + /// @return The final inline box. + LayoutInlineBox* AddBox(LayoutInlineBox* box); + /// Adds an inline box as a chained hierarchy overflowing to this line. The chain will be extended into + /// this line box. + /// @param split_box[in] The box overflowed from a previous line. + void AddChainedBox(LayoutInlineBox* chained_box); + + /// Returns the position of the line box, relative to its parent's block box's content area. + /// @return The position of the line box. + const Vector2f& GetPosition() const; + /// Returns the position of the line box, relative to its parent's block box's offset parent. + /// @return The relative position of the line box. + Vector2f GetRelativePosition() const; + /// Returns the dimensions of the line box. + /// @return The dimensions of the line box. + const Vector2f& GetDimensions() const; + + /// Returns the line box's open inline box. + /// @return The line's open inline box, or nullptr if it currently has none. + LayoutInlineBox* GetOpenInlineBox(); + /// Returns the line's containing block box. + /// @return The line's block box. + LayoutBlockBox* GetBlockBox(); + + float GetBoxCursor() const; + + void* operator new(size_t size); + void operator delete(void* chunk); + +private: + /// Appends an inline box to the end of the line box's list of inline boxes. + void AppendBox(LayoutInlineBox* box); + + typedef Vector< LayoutInlineBox* > InlineBoxList; + + // The block box containing this line. + LayoutBlockBox* parent; + + // The top-left position of the line box; this is set when the first inline box is placed. + Vector2f position; + bool position_set; + + // The width and height of the line box; this is set when the line box is placed. + Vector2f dimensions; + bool wrap_content; + + // The horizontal cursor. This is where the next inline box will be placed along the line. + float box_cursor; + + // The list of inline boxes in this line box. These line boxes may be parented to others in this list. + InlineBoxList inline_boxes; + // The open inline box; this is nullptr if all inline boxes are closed. + LayoutInlineBox* open_inline_box; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Log.cpp b/thirdparty/RmlUi/Source/Core/Log.cpp new file mode 100644 index 000000000..eaef6459c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Log.cpp @@ -0,0 +1,101 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" + +#include +#ifdef RMLUI_PLATFORM_WIN32 +#include +#endif + +namespace Rml { + +// Initialises the logging interface. +bool Log::Initialise() +{ + return true; +} + +// Shutdown the log interface. +void Log::Shutdown() +{ +} + +// Log the specified message via the registered log interface +void Log::Message(Log::Type type, const char* fmt, ...) +{ + const int buffer_size = 1024; + char buffer[buffer_size]; + va_list argument_list; + + // Print the message to the buffer. + va_start(argument_list, fmt); + int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); + if (len < 0 || len > buffer_size - 2) + { + len = buffer_size - 2; + } + buffer[len] = '\0'; + va_end(argument_list); + + GetSystemInterface()->LogMessage(type, buffer); +} + +// Log a parse error on the specified file and line number. +void Log::ParseError(const String& filename, int line_number, const char* fmt, ...) +{ + const int buffer_size = 1024; + char buffer[buffer_size]; + va_list argument_list; + + // Print the message to the buffer. + va_start(argument_list, fmt); + int len = vsnprintf(buffer, buffer_size - 2, fmt, argument_list); + if (len < 0 || len > buffer_size - 2) + { + len = buffer_size - 2; + } + buffer[len] = '\0'; + va_end(argument_list); + + if (line_number >= 0) + Message(Log::LT_ERROR, "%s:%d: %s", filename.c_str(), line_number, buffer); + else + Message(Log::LT_ERROR, "%s: %s", filename.c_str(), buffer); +} + +bool Assert(const char* msg, const char* file, int line) +{ + String message = CreateString(1024, "%s\n%s:%d", msg, file, line); + return GetSystemInterface()->LogMessage(Log::LT_ASSERT, message); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Math.cpp b/thirdparty/RmlUi/Source/Core/Math.cpp new file mode 100644 index 000000000..70593fd99 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Math.cpp @@ -0,0 +1,220 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Math.h" +#include +#include +#include + +namespace Rml { + +namespace Math { + +const float RMLUI_PI = 3.141592653f; + +static constexpr float FZERO = 0.0001f; + +// Evaluates if a number is, or close to, zero. +RMLUICORE_API bool IsZero(float value) +{ + return AbsoluteValue(value) < FZERO; +} + +// Evaluates if two floating-point numbers are equal, or so similar that they could be considered +// so. +RMLUICORE_API bool AreEqual(float value_0, float value_1) +{ + return IsZero(value_1 - value_0); +} + +// Calculates the absolute value of a number. +RMLUICORE_API float AbsoluteValue(float value) +{ + return fabsf(value); +} + +// Calculates the cosine of an angle. +RMLUICORE_API float Cos(float angle) +{ + return cosf(angle); +} + +// Calculates the arc-cosine of an value. +RMLUICORE_API float ACos(float value) +{ + return acosf(value); +} + +// Calculates the sine of an angle. +RMLUICORE_API float Sin(float angle) +{ + return sinf(angle); +} + +// Calculates the arc-sine of an value. +RMLUICORE_API float ASin(float angle) +{ + return asinf(angle); +} + +// Calculates the tangent of an angle. +RMLUICORE_API float Tan(float angle) +{ + return tanf(angle); +} + +// Calculates the angle of a two-dimensional line. +RMLUICORE_API float ATan2(float y, float x) +{ + return atan2f(y, x); +} + +// Evaluates the natural exponential function on a value. +RMLUICORE_API float Exp(float value) +{ + return expf(value); +} + +// Converts an angle from radians to degrees. +RMLUICORE_API float RadiansToDegrees(float angle) +{ + return angle * (180.0f / RMLUI_PI); +} + +// Converts an angle from degrees to radians. +RMLUICORE_API float DegreesToRadians(float angle) +{ + return angle * (RMLUI_PI / 180.0f); +} + +// Normalises an angle in radians +RMLUICORE_API float NormaliseAngle(float angle) +{ + return fmodf(angle, RMLUI_PI * 2.0f); +} + +// Calculates the square root of a value. +RMLUICORE_API float SquareRoot(float value) +{ + return sqrtf(value); +} + +// Rounds a floating-point value to the nearest integer. +RMLUICORE_API float RoundFloat(float value) +{ + return roundf(value); +} + +// Rounds a floating-point value to the nearest integer. +RMLUICORE_API double RoundFloat(double value) +{ + return round(value); +} + +// Rounds a floating-point value to the nearest integer. +RMLUICORE_API int RoundToInteger(float value) +{ + if (value > 0.0f) + return RealToInteger(value + 0.5f); + + return RealToInteger(value - 0.5f); +} + +// Rounds a floating-point value up to the nearest integer. +RMLUICORE_API int RoundUpToInteger(float value) +{ + return RealToInteger(ceilf(value)); +} + +// Rounds a floating-point value down to the nearest integer. +RMLUICORE_API int RoundDownToInteger(float value) +{ + return RealToInteger(floorf(value)); +} + +// Efficiently truncates a floating-point value into an integer. +RMLUICORE_API int RealToInteger(float value) +{ + return int(value); +} + +// Converts the given number to a power of two, rounding up if necessary. +RMLUICORE_API int ToPowerOfTwo(int number) +{ + // Check if the number is already a power of two. + if ((number & (number - 1)) == 0) + return number; + + // Assuming 31 useful bits in an int here ... ! + for (int i = 31; i >= 0; i--) + { + if (number & (1 << i)) + { + if (i == 31) + return 1 << 31; + else + return 1 << (i + 1); + } + } + + return 0; +} + +// Converts from a hexadecimal digit to decimal. +RMLUICORE_API int HexToDecimal(char hex_digit) +{ + if (hex_digit >= '0' && hex_digit <= '9') + return hex_digit - '0'; + else if (hex_digit >= 'a' && hex_digit <= 'f') + return 10 + (hex_digit - 'a'); + else if (hex_digit >= 'A' && hex_digit <= 'F') + return 10 + (hex_digit - 'A'); + + return -1; +} + +// Generates a random floating-point value between 0 and a user-specified value. +RMLUICORE_API float RandomReal(float max_value) +{ + return (rand() / (float) RAND_MAX) * max_value; +} + +// Generates a random integer value between 0 and a user-specified value. +RMLUICORE_API int RandomInteger(int max_value) +{ + return (rand() % max_value); +} + +// Generates a random boolean value, with equal chance of true or false. +RMLUICORE_API bool RandomBool() +{ + return RandomInteger(2) == 1; +} + +} +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Memory.cpp b/thirdparty/RmlUi/Source/Core/Memory.cpp new file mode 100644 index 000000000..407c1c1f2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Memory.cpp @@ -0,0 +1,97 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Memory.h" +#include +#include +#include + +namespace Rml { + +namespace Detail { + +inline void* rmlui_align(size_t alignment, size_t size, void*& ptr, size_t& space) +{ +#if defined(_MSC_VER) + return std::align(alignment, size, ptr, space); +#else + // std::align replacement to support compilers missing this feature. + // From https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57350 + + uintptr_t pn = reinterpret_cast(ptr); + uintptr_t aligned = (pn + alignment - 1) & -alignment; + size_t padding = aligned - pn; + if (space < size + padding) + return nullptr; + space -= padding; + return ptr = reinterpret_cast(aligned); +#endif +} + +BasicStackAllocator::BasicStackAllocator(size_t N) : N(N), data((byte*)malloc(N)), p(data) +{} + +BasicStackAllocator::~BasicStackAllocator() noexcept { + RMLUI_ASSERT(p == data); + free(data); +} + +void* BasicStackAllocator::allocate(size_t alignment, size_t byte_size) +{ + size_t available_space = N - ((byte*)p - data); + + if (rmlui_align(alignment, byte_size, p, available_space)) + { + void* result = p; + p = (byte*)p + byte_size; + return result; + } + + // Fall back to malloc + return malloc(byte_size); +} + +void BasicStackAllocator::deallocate(void* obj) noexcept +{ + if (obj < data || obj >= data + N) + { + free(obj); + return; + } + p = obj; +} + +BasicStackAllocator& GetGlobalBasicStackAllocator() +{ + static BasicStackAllocator stack_allocator(10 * 1024); + return stack_allocator; +} + +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Memory.h b/thirdparty/RmlUi/Source/Core/Memory.h new file mode 100644 index 000000000..6766ffd89 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Memory.h @@ -0,0 +1,139 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_MEMORY_H +#define RMLUI_CORE_MEMORY_H + + +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/Traits.h" + +namespace Rml { + +namespace Detail { + + /** + Basic stack allocator. + + A very cheap allocator which only moves a pointer up and down during allocation and deallocation, respectively. + The allocator is initialized with some fixed memory. If it runs out, it falls back to malloc. + + Warning: Using this is dangerous as deallocation must happen in exact reverse order of allocation. + + Do not use this class directly. + */ + class BasicStackAllocator + { + public: + BasicStackAllocator(size_t N); + ~BasicStackAllocator() noexcept; + + void* allocate(size_t alignment, size_t byte_size); + void deallocate(void* obj) noexcept; + + private: + const size_t N; + byte* data; + void* p; + }; + + + BasicStackAllocator& GetGlobalBasicStackAllocator(); + +} /* namespace Detail */ + + + +/** + Global stack allocator. + + Can very cheaply allocate memory using the global stack allocator. Memory will be allocated from the + heap on the very first construction of a global stack allocator, and will persist and be re-used after. + Falls back to malloc if there is not enough space left. + + Warning: Using this is dangerous as deallocation must happen in exact reverse order of allocation. + Memory is shared between different global stack allocators. Should only be used for highly localized code, + where memory is allocated and then quickly thrown away. +*/ + +template +class GlobalStackAllocator +{ +public: + using value_type = T; + + GlobalStackAllocator() = default; + template constexpr GlobalStackAllocator(const GlobalStackAllocator&) noexcept {} + + T* allocate(size_t num_objects) { + return reinterpret_cast(Detail::GetGlobalBasicStackAllocator().allocate(alignof(T), num_objects * sizeof(T))); + } + + void deallocate(T* ptr, size_t) noexcept { + Detail::GetGlobalBasicStackAllocator().deallocate(ptr); + } +}; + +template +bool operator==(const GlobalStackAllocator&, const GlobalStackAllocator&) { return true; } +template +bool operator!=(const GlobalStackAllocator&, const GlobalStackAllocator&) { return false; } + + + +/** + A poor man's dynamic array. + + Constructs N objects on initialization which are default initialized. Can not be resized. +*/ + +template +class DynamicArray : Alloc, NonCopyMoveable { +public: + DynamicArray(size_t N) : N(N) { + p = Alloc::allocate(N); + for (size_t i = 0; i < N; i++) + new (p + i) T; + } + ~DynamicArray() noexcept { + for (size_t i = 0; i < N; i++) + p[i].~T(); + Alloc::deallocate(p, N); + } + + T* data() noexcept { return p; } + + T& operator[](size_t i) noexcept { return p[i]; } + +private: + size_t N; + T* p; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/ObserverPtr.cpp b/thirdparty/RmlUi/Source/Core/ObserverPtr.cpp new file mode 100644 index 000000000..74af58713 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/ObserverPtr.cpp @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/ObserverPtr.h" +#include "Pool.h" + +namespace Rml { + +static Pool< ObserverPtrBlock >& GetPool() +{ + // Wrap pool in a function to ensure it is initialized before use. + static Pool< ObserverPtrBlock > pool(400, true); + return pool; +} + + +void DeallocateObserverPtrBlockIfEmpty(ObserverPtrBlock* block) { + RMLUI_ASSERT(block->num_observers >= 0); + if (block->num_observers == 0 && block->pointed_to_object == nullptr) + { + GetPool().DestroyAndDeallocate(block); + } +} + +ObserverPtrBlock* AllocateObserverPtrBlock() +{ + return GetPool().AllocateAndConstruct(); +} + + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Plugin.cpp b/thirdparty/RmlUi/Source/Core/Plugin.cpp new file mode 100644 index 000000000..9c3e49398 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Plugin.cpp @@ -0,0 +1,94 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Plugin.h" + +namespace Rml { + +Plugin::~Plugin() +{ +} + +int Plugin::GetEventClasses() +{ + return EVT_ALL; +} + +void Plugin::OnInitialise() +{ +} + +void Plugin::OnShutdown() +{ +} + +// Called when a new context is created. +void Plugin::OnContextCreate(Context* RMLUI_UNUSED_PARAMETER(context)) +{ + RMLUI_UNUSED(context); +} + +// Called when a context is destroyed. +void Plugin::OnContextDestroy(Context* RMLUI_UNUSED_PARAMETER(context)) +{ + RMLUI_UNUSED(context); +} + +// Called when a document load request occurs, before the document's file is opened. +void Plugin::OnDocumentOpen(Context* RMLUI_UNUSED_PARAMETER(context), const String& RMLUI_UNUSED_PARAMETER(document_path)) +{ + RMLUI_UNUSED(context); + RMLUI_UNUSED(document_path); +} + +// Called when a document is successfully loaded from file or instanced, initialised and added to +// its context. +void Plugin::OnDocumentLoad(ElementDocument* RMLUI_UNUSED_PARAMETER(document)) +{ + RMLUI_UNUSED(document); +} + +// Called when a document is unloaded from its context. +void Plugin::OnDocumentUnload(ElementDocument* RMLUI_UNUSED_PARAMETER(document)) +{ + RMLUI_UNUSED(document); +} + +// Called when a new element is created. +void Plugin::OnElementCreate(Element* RMLUI_UNUSED_PARAMETER(element)) +{ + RMLUI_UNUSED(element); +} + +// Called when an element is destroyed. +void Plugin::OnElementDestroy(Element* RMLUI_UNUSED_PARAMETER(element)) +{ + RMLUI_UNUSED(element); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PluginRegistry.cpp b/thirdparty/RmlUi/Source/Core/PluginRegistry.cpp new file mode 100644 index 000000000..62a0a0681 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PluginRegistry.cpp @@ -0,0 +1,123 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "PluginRegistry.h" +#include "../../Include/RmlUi/Core/Plugin.h" + +namespace Rml { + +typedef Vector< Plugin* > PluginList; +static PluginList basic_plugins; +static PluginList document_plugins; +static PluginList element_plugins; + +PluginRegistry::PluginRegistry() +{ +} + +void PluginRegistry::RegisterPlugin(Plugin* plugin) +{ + int event_classes = plugin->GetEventClasses(); + + if (event_classes & Plugin::EVT_BASIC) + basic_plugins.push_back(plugin); + if (event_classes & Plugin::EVT_DOCUMENT) + document_plugins.push_back(plugin); + if (event_classes & Plugin::EVT_ELEMENT) + element_plugins.push_back(plugin); +} + +// Calls OnInitialise() on all plugins. +void PluginRegistry::NotifyInitialise() +{ + for (size_t i = 0; i < basic_plugins.size(); ++i) + basic_plugins[i]->OnInitialise(); +} + +// Calls OnShutdown() on all plugins. +void PluginRegistry::NotifyShutdown() +{ + while (!basic_plugins.empty()) + { + basic_plugins.back()->OnShutdown(); + basic_plugins.pop_back(); + } + document_plugins.clear(); + element_plugins.clear(); +} + +// Calls OnContextCreate() on all plugins. +void PluginRegistry::NotifyContextCreate(Context* context) +{ + for (size_t i = 0; i < basic_plugins.size(); ++i) + basic_plugins[i]->OnContextCreate(context); +} + +// Calls OnContextDestroy() on all plugins. +void PluginRegistry::NotifyContextDestroy(Context* context) +{ + for (size_t i = 0; i < basic_plugins.size(); ++i) + basic_plugins[i]->OnContextDestroy(context); +} + +// Calls OnDocumentOpen() on all plugins. +void PluginRegistry::NotifyDocumentOpen(Context* context, const String& document_path) +{ + for (size_t i = 0; i < document_plugins.size(); ++i) + document_plugins[i]->OnDocumentOpen(context, document_path); +} + +// Calls OnDocumentLoad() on all plugins. +void PluginRegistry::NotifyDocumentLoad(ElementDocument* document) +{ + for (size_t i = 0; i < document_plugins.size(); ++i) + document_plugins[i]->OnDocumentLoad(document); +} + +// Calls OnDocumentUnload() on all plugins. +void PluginRegistry::NotifyDocumentUnload(ElementDocument* document) +{ + for (size_t i = 0; i < document_plugins.size(); ++i) + document_plugins[i]->OnDocumentUnload(document); +} + +// Calls OnElementCreate() on all plugins. +void PluginRegistry::NotifyElementCreate(Element* element) +{ + for (size_t i = 0; i < element_plugins.size(); ++i) + element_plugins[i]->OnElementCreate(element); +} + +// Calls OnElementDestroy() on all plugins. +void PluginRegistry::NotifyElementDestroy(Element* element) +{ + for (size_t i = 0; i < element_plugins.size(); ++i) + element_plugins[i]->OnElementDestroy(element); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PluginRegistry.h b/thirdparty/RmlUi/Source/Core/PluginRegistry.h new file mode 100644 index 000000000..4acb17716 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PluginRegistry.h @@ -0,0 +1,77 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PLUGINREGISTRY_H +#define RMLUI_CORE_PLUGINREGISTRY_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class Context; +class Element; +class ElementDocument; +class Plugin; + +/** + @author Peter Curry + */ + +class PluginRegistry +{ +public: + static void RegisterPlugin(Plugin* plugin); + + /// Calls OnInitialise() on all plugins. + static void NotifyInitialise(); + /// Calls OnShutdown() on all plugins. + static void NotifyShutdown(); + + /// Calls OnContextCreate() on all plugins. + static void NotifyContextCreate(Context* context); + /// Calls OnContextDestroy() on all plugins. + static void NotifyContextDestroy(Context* context); + + /// Calls OnDocumentOpen() on all plugins. + static void NotifyDocumentOpen(Context* context, const String& document_path); + /// Calls OnDocumentLoad() on all plugins. + static void NotifyDocumentLoad(ElementDocument* document); + /// Calls OnDocumentUnload() on all plugins. + static void NotifyDocumentUnload(ElementDocument* document); + + /// Calls OnElementCreate() on all plugins. + static void NotifyElementCreate(Element* element); + /// Calls OnElementDestroy() on all plugins. + static void NotifyElementDestroy(Element* element); + +private: + PluginRegistry(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Pool.h b/thirdparty/RmlUi/Source/Core/Pool.h new file mode 100644 index 000000000..992000a55 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Pool.h @@ -0,0 +1,156 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_POOL_H +#define RMLUI_CORE_POOL_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Debug.h" +#include "../../Include/RmlUi/Core/Traits.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +template < typename PoolType > +class Pool +{ +private: + static constexpr size_t N = sizeof(PoolType); + static constexpr size_t A = alignof(PoolType); + + class PoolNode : public NonCopyMoveable + { + public: + alignas(A) unsigned char object[N]; + PoolNode* previous; + PoolNode* next; + }; + + class PoolChunk : public NonCopyMoveable + { + public: + PoolNode* chunk; + PoolChunk* next; + }; + +public: + /** + Iterator objects are used for safe traversal of the allocated + members of a pool. + */ + class Iterator + { + friend class Pool< PoolType >; + + public : + /// Increments the iterator to reference the next node in the + /// linked list. It is an error to call this function if the + /// node this iterator references is invalid. + inline void operator++() + { + RMLUI_ASSERT(node != nullptr); + node = node->next; + } + /// Returns true if it is OK to deference or increment this + /// iterator. + explicit inline operator bool() + { + return (node != nullptr); + } + + /// Returns the object referenced by the iterator's current + /// node. + inline PoolType& operator*() + { + return *reinterpret_cast(node->object); + } + /// Returns a pointer to the object referenced by the + /// iterator's current node. + inline PoolType* operator->() + { + return reinterpret_cast(node->object); + } + + private: + // Constructs an iterator referencing the given node. + inline Iterator(PoolNode* node) + { + this->node = node; + } + + PoolNode* node; + }; + + Pool(int chunk_size = 0, bool grow = false); + ~Pool(); + + /// Initialises the pool to a given size. + void Initialise(int chunk_size, bool grow = false); + + /// Returns the head of the linked list of allocated objects. + inline Iterator Begin(); + + /// Attempts to allocate an object into a free slot in the memory pool and construct it using the given arguments. + /// If the process is successful, the newly constructed object is returned. Otherwise, if the process fails due to + /// no free objects being available, nullptr is returned. + template + inline PoolType* AllocateAndConstruct(Args&&... args); + + /// Deallocates the object pointed to by the given iterator. + inline void DestroyAndDeallocate(Iterator& iterator); + /// Deallocates the given object. + inline void DestroyAndDeallocate(PoolType* object); + + /// Returns the number of objects in the pool. + inline int GetSize() const; + /// Returns the number of object chunks in the pool. + inline int GetNumChunks() const; + /// Returns the number of allocated objects in the pool. + inline int GetNumAllocatedObjects() const; + +private: + // Creates a new pool chunk and appends its nodes to the beginning of the free list. + void CreateChunk(); + + int chunk_size; + bool grow; + + PoolChunk* pool; + + // The heads of the two linked lists. + PoolNode* first_allocated_node; + PoolNode* first_free_node; + + int num_allocated_objects; +}; + +} // namespace Rml + +#include "Pool.inl" + +#endif diff --git a/thirdparty/RmlUi/Source/Core/Pool.inl b/thirdparty/RmlUi/Source/Core/Pool.inl new file mode 100644 index 000000000..fc6160738 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Pool.inl @@ -0,0 +1,255 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + + +namespace Rml { + +template < typename PoolType > +Pool< PoolType >::Pool(int _chunk_size, bool _grow) +{ + chunk_size = 0; + grow = _grow; + + num_allocated_objects = 0; + + pool = nullptr; + first_allocated_node = nullptr; + first_free_node = nullptr; + + if (_chunk_size > 0) + Initialise(_chunk_size, _grow); +} + +template < typename PoolType > +Pool< PoolType >::~Pool() +{ + PoolChunk* chunk = pool; + while (chunk) + { + PoolChunk* next_chunk = chunk->next; + + delete[] chunk->chunk; + delete chunk; + + chunk = next_chunk; + } +} + +// Initialises the pool to a given size. +template < typename PoolType > +void Pool< PoolType >::Initialise(int _chunk_size, bool _grow) +{ + // Should resize the pool here ... ? + if (chunk_size > 0) + return; + + if (_chunk_size <= 0) + return; + + grow = _grow; + chunk_size = _chunk_size; + pool = nullptr; + + // Create the initial chunk. + CreateChunk(); +} + +// Returns the head of the linked list of allocated objects. +template < typename PoolType > +typename Pool< PoolType >::Iterator Pool< PoolType >::Begin() +{ + return typename Pool< PoolType >::Iterator(first_allocated_node); +} + +// Attempts to allocate a deallocated object in the memory pool. +template +template +inline PoolType* Pool::AllocateAndConstruct(Args&&... args) +{ + // We can't allocate a new object if the deallocated list is empty. + if (first_free_node == nullptr) + { + // Attempt to grow the pool first. + if (grow) + { + CreateChunk(); + if (first_free_node == nullptr) + return nullptr; + } + else + return nullptr; + } + + // We're about to allocate an object. + ++num_allocated_objects; + + // This one! + PoolNode* allocated_object = first_free_node; + + // Remove the newly allocated object from the list of deallocated objects. + first_free_node = first_free_node->next; + if (first_free_node != nullptr) + first_free_node->previous = nullptr; + + // Add the newly allocated object to the head of the list of allocated objects. + if (first_allocated_node != nullptr) + { + allocated_object->previous = nullptr; + allocated_object->next = first_allocated_node; + first_allocated_node->previous = allocated_object; + } + else + { + // This object is the only allocated object. + allocated_object->previous = nullptr; + allocated_object->next = nullptr; + } + + first_allocated_node = allocated_object; + + return new (allocated_object->object) PoolType(std::forward(args)...); +} + +// Deallocates the object pointed to by the given iterator. +template < typename PoolType > +void Pool< PoolType >::DestroyAndDeallocate(Iterator& iterator) +{ + // We're about to deallocate an object. + --num_allocated_objects; + + PoolNode* object = iterator.node; + reinterpret_cast(object->object)->~PoolType(); + + // Get the previous and next pointers now, because they will be overwritten + // before we're finished. + PoolNode* previous_object = object->previous; + PoolNode* next_object = object->next; + + if (previous_object != nullptr) + previous_object->next = next_object; + else + { + RMLUI_ASSERT(first_allocated_node == object); + first_allocated_node = next_object; + } + + if (next_object != nullptr) + next_object->previous = previous_object; + + // Insert the freed node at the beginning of the free object list. + if (first_free_node == nullptr) + { + object->previous = nullptr; + object->next = nullptr; + } + else + { + object->previous = nullptr; + object->next = first_free_node; + } + + first_free_node = object; + + // Increment the iterator, so it points to the next active object. + iterator.node = next_object; +} + +// Deallocates the given object. +template < typename PoolType > +void Pool< PoolType >::DestroyAndDeallocate(PoolType* object) +{ + // This assumes the object has the same address as the node, which will be + // true as long as the struct definition does not change. + Iterator iterator((PoolNode*) object); + DestroyAndDeallocate(iterator); +} + +// Returns the number of objects in the pool. +template < typename PoolType > +int Pool< PoolType >::GetSize() const +{ + return chunk_size * GetNumChunks(); +} + +/// Returns the number of object chunks in the pool. +template < typename PoolType > +int Pool< PoolType >::GetNumChunks() const +{ + int num_chunks = 0; + + PoolChunk* chunk = pool; + while (chunk != nullptr) + { + ++num_chunks; + chunk = chunk->next; + } + + return num_chunks; +} + +// Returns the number of allocated objects in the pool. +template < typename PoolType > +int Pool< PoolType >::GetNumAllocatedObjects() const +{ + return num_allocated_objects; +} + +// Creates a new pool chunk and appends its nodes to the beginning of the free list. +template < typename PoolType > +void Pool< PoolType >::CreateChunk() +{ + if (chunk_size <= 0) + return; + + // Create the new chunk and mark it as the first chunk. + PoolChunk* new_chunk = new PoolChunk(); + new_chunk->next = pool; + pool = new_chunk; + + // Create chunk's pool nodes. + new_chunk->chunk = new PoolNode[chunk_size]; + + // Initialise the linked list. + for (int i = 0; i < chunk_size; i++) + { + if (i == 0) + new_chunk->chunk[i].previous = nullptr ; + else + new_chunk->chunk[i].previous = &new_chunk->chunk[i - 1]; + + if (i == chunk_size - 1) + new_chunk->chunk[i].next = first_free_node; + else + new_chunk->chunk[i].next = &new_chunk->chunk[i + 1]; + } + + first_free_node = new_chunk->chunk; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Profiling.cpp b/thirdparty/RmlUi/Source/Core/Profiling.cpp new file mode 100644 index 000000000..823fb0007 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Profiling.cpp @@ -0,0 +1,50 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "../../Include/RmlUi/Core/Profiling.h" + +#ifdef RMLUI_ENABLE_PROFILING +#include +#include + +// Overload global new and delete for memory inspection +void* operator new(std::size_t n) +{ + void* ptr = malloc(n); + TracyAlloc(ptr, n); + return ptr; +} +void operator delete(void* ptr) noexcept +{ + TracyFree(ptr); + free(ptr); +} + + +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertiesIterator.h b/thirdparty/RmlUi/Source/Core/PropertiesIterator.h new file mode 100644 index 000000000..9fd6044c6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertiesIterator.h @@ -0,0 +1,109 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ +#ifndef RMLUI_CORE_PROPERTIESITERATOR_H +#define RMLUI_CORE_PROPERTIESITERATOR_H + +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" + +namespace Rml { + +// An iterator for local properties defined on an element. +// Note: Modifying the underlying style invalidates the iterator. +class PropertiesIterator { +public: + using ValueType = Pair; + using PropertyIt = PropertyMap::const_iterator; + + PropertiesIterator(PropertyIt it_style, PropertyIt it_style_end, PropertyIt it_definition, PropertyIt it_definition_end) + : it_style(it_style), it_style_end(it_style_end), it_definition(it_definition), it_definition_end(it_definition_end) + { + ProceedToNextValid(); + } + + PropertiesIterator& operator++() { + if (it_style != it_style_end) + // We iterate over the local style properties first + ++it_style; + else + // .. and then over the properties given by the element's definition + ++it_definition; + // If we reached the end of one of the iterator pairs, we need to continue iteration on the next pair. + ProceedToNextValid(); + return *this; + } + + ValueType operator*() const + { + if (it_style != it_style_end) + return { it_style->first, it_style->second }; + return { it_definition->first, it_definition->second }; + } + + bool AtEnd() const { + return at_end; + } + +private: + PropertyIdSet iterated_properties; + PropertyIt it_style, it_style_end; + PropertyIt it_definition, it_definition_end; + bool at_end = false; + + inline bool IsDirtyRemove(PropertyId id) + { + if (!iterated_properties.Contains(id)) + { + iterated_properties.Insert(id); + return true; + } + return false; + } + + inline void ProceedToNextValid() + { + for (; it_style != it_style_end; ++it_style) + { + if (IsDirtyRemove(it_style->first)) + return; + } + + for (; it_definition != it_definition_end; ++it_definition) + { + if (IsDirtyRemove(it_definition->first)) + return; + } + + // All iterators are now at the end + at_end = true; + } +}; + + +} // namespace Rml +#endif \ No newline at end of file diff --git a/thirdparty/RmlUi/Source/Core/PropertiesIteratorView.cpp b/thirdparty/RmlUi/Source/Core/PropertiesIteratorView.cpp new file mode 100644 index 000000000..8353317bc --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertiesIteratorView.cpp @@ -0,0 +1,73 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/PropertiesIteratorView.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "PropertiesIterator.h" + +namespace Rml { + +PropertiesIteratorView::PropertiesIteratorView(UniquePtr ptr) : ptr(std::move(ptr)) {} + +PropertiesIteratorView::PropertiesIteratorView(PropertiesIteratorView&& other) noexcept : ptr(std::move(other.ptr)) {} + +PropertiesIteratorView& PropertiesIteratorView::operator=(PropertiesIteratorView&& other) noexcept +{ + ptr = std::move(other.ptr); + return *this; +} + +PropertiesIteratorView::~PropertiesIteratorView() +{} + +PropertiesIteratorView& PropertiesIteratorView::operator++() +{ + ++(*ptr); + return *this; +} + +PropertyId PropertiesIteratorView::GetId() const +{ + return (*(*ptr)).first; +} + +const String& PropertiesIteratorView::GetName() const +{ + return StyleSheetSpecification::GetPropertyName(GetId()); +} + +const Property& PropertiesIteratorView::GetProperty() const +{ + return (*(*ptr)).second; +} + +bool PropertiesIteratorView::AtEnd() const { + return ptr->AtEnd(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Property.cpp b/thirdparty/RmlUi/Source/Core/Property.cpp new file mode 100644 index 000000000..edcce6c09 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Property.cpp @@ -0,0 +1,50 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" + +namespace Rml { + +Property::Property() : unit(UNKNOWN), specificity(-1) +{ + definition = nullptr; + parser_index = -1; +} + +String Property::ToString() const +{ + if (!definition) + return value.Get< String >(); + + String string; + definition->GetValue(string, *this); + return string; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyDefinition.cpp b/thirdparty/RmlUi/Source/Core/PropertyDefinition.cpp new file mode 100644 index 000000000..981ff42f4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyDefinition.cpp @@ -0,0 +1,211 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" + +namespace Rml { + +PropertyDefinition::PropertyDefinition(PropertyId id, const String& _default_value, bool _inherited, bool _forces_layout) + : id(id), default_value(_default_value, Property::UNKNOWN), relative_target(RelativeTarget::None) +{ + inherited = _inherited; + forces_layout = _forces_layout; + default_value.definition = this; +} + +PropertyDefinition::~PropertyDefinition() +{ +} + +// Registers a parser to parse values for this definition. +PropertyDefinition& PropertyDefinition::AddParser(const String& parser_name, const String& parser_parameters) +{ + ParserState new_parser; + + // Fetch the parser. + new_parser.parser = StyleSheetSpecification::GetParser(parser_name); + if (new_parser.parser == nullptr) + { + Log::Message(Log::LT_ERROR, "Property was registered with invalid parser '%s'.", parser_name.c_str()); + return *this; + } + + // Split the parameter list, and set up the map. + if (!parser_parameters.empty()) + { + StringList parameter_list; + StringUtilities::ExpandString(parameter_list, parser_parameters); + for (size_t i = 0; i < parameter_list.size(); i++) + new_parser.parameters[parameter_list[i]] = (int) i; + } + + const int parser_index = (int)parsers.size(); + parsers.push_back(new_parser); + + // If the default value has not been parsed successfully yet, run it through the new parser. + if (default_value.unit == Property::UNKNOWN) + { + String unparsed_value = default_value.value.Get< String >(); + if (new_parser.parser->ParseValue(default_value, unparsed_value, new_parser.parameters)) + { + default_value.parser_index = parser_index; + } + else + { + default_value.value = unparsed_value; + default_value.unit = Property::UNKNOWN; + } + } + + return *this; +} + +// Called when parsing a RCSS declaration. +bool PropertyDefinition::ParseValue(Property& property, const String& value) const +{ + for (size_t i = 0; i < parsers.size(); i++) + { + if (parsers[i].parser->ParseValue(property, value, parsers[i].parameters)) + { + property.definition = this; + property.parser_index = (int) i; + return true; + } + } + + property.unit = Property::UNKNOWN; + return false; +} + +// Called to convert a parsed property back into a value. +bool PropertyDefinition::GetValue(String& value, const Property& property) const +{ + value = property.value.Get< String >(); + + switch (property.unit) + { + case Property::KEYWORD: + { + int parser_index = property.parser_index; + if (parser_index < 0 || parser_index >= (int)parsers.size()) + { + // Look for the keyword parser in the property's list of parsers + const auto* keyword_parser = StyleSheetSpecification::GetParser("keyword"); + for(int i = 0; i < (int)parsers.size(); i++) + { + if (parsers[i].parser == keyword_parser) + { + parser_index = i; + break; + } + } + // If we couldn't find it, exit now + if (parser_index < 0 || parser_index >= (int)parsers.size()) + return false; + } + + int keyword = property.value.Get< int >(); + for (ParameterMap::const_iterator i = parsers[parser_index].parameters.begin(); i != parsers[parser_index].parameters.end(); ++i) + { + if ((*i).second == keyword) + { + value = (*i).first; + break; + } + } + + return false; + } + break; + + case Property::COLOUR: + { + Colourb colour = property.value.Get< Colourb >(); + value = CreateString(32, "rgba(%d,%d,%d,%d)", colour.red, colour.green, colour.blue, colour.alpha); + } + break; + + case Property::PX: value += "px"; break; + case Property::DEG: value += "deg"; break; + case Property::RAD: value += "rad"; break; + case Property::DP: value += "dp"; break; + case Property::EM: value += "em"; break; + case Property::REM: value += "rem"; break; + case Property::PERCENT: value += "%"; break; + case Property::INCH: value += "in"; break; + case Property::CM: value += "cm"; break; + case Property::MM: value += "mm"; break; + case Property::PT: value += "pt"; break; + case Property::PC: value += "pc"; break; + default: break; + } + + return true; +} + +// Returns true if this property is inherited from a parent to child elements. +bool PropertyDefinition::IsInherited() const +{ + return inherited; +} + +// Returns true if this property forces a re-layout when changed. +bool PropertyDefinition::IsLayoutForced() const +{ + return forces_layout; +} + +// Returns the default for this property. +const Property* PropertyDefinition::GetDefaultValue() const +{ + return &default_value; +} + +/// Returns the default defined for this property. + +RelativeTarget PropertyDefinition::GetRelativeTarget() const +{ + return relative_target; +} + +PropertyId PropertyDefinition::GetId() const +{ + return id; +} + +/// Set target for units with scaling percentages + +PropertyDefinition & PropertyDefinition::SetRelativeTarget(RelativeTarget relative_target) +{ + this->relative_target = relative_target; + return *this; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyDictionary.cpp b/thirdparty/RmlUi/Source/Core/PropertyDictionary.cpp new file mode 100644 index 000000000..f44ad9d07 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyDictionary.cpp @@ -0,0 +1,112 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/PropertyDictionary.h" +#include "../../Include/RmlUi/Core/ID.h" + +namespace Rml { + +PropertyDictionary::PropertyDictionary() +{ +} + +// Sets a property on the dictionary. Any existing property with a similar name will be overwritten. +void PropertyDictionary::SetProperty(PropertyId id, const Property& property) +{ + RMLUI_ASSERT(id != PropertyId::Invalid); + properties[id] = property; +} + +// Removes a property from the dictionary, if it exists. +void PropertyDictionary::RemoveProperty(PropertyId id) +{ + RMLUI_ASSERT(id != PropertyId::Invalid); + properties.erase(id); +} + +// Returns the value of the property with the requested name, if one exists. +const Property* PropertyDictionary::GetProperty(PropertyId id) const +{ + PropertyMap::const_iterator iterator = properties.find(id); + if (iterator == properties.end()) + return nullptr; + + return &(*iterator).second; +} + +// Returns the number of properties in the dictionary. +int PropertyDictionary::GetNumProperties() const +{ + return (int)properties.size(); +} + +// Returns the map of properties in the dictionary. +const PropertyMap& PropertyDictionary::GetProperties() const +{ + return properties; +} + +// Imports potentially un-specified properties into the dictionary. +void PropertyDictionary::Import(const PropertyDictionary& property_dictionary, int property_specificity) +{ + for (PropertyMap::const_iterator iterator = property_dictionary.properties.begin(); iterator != property_dictionary.properties.end(); ++iterator) + { + const Property& property = iterator->second; + SetProperty(iterator->first, property, property_specificity > 0 ? property_specificity : property.specificity); + } +} + +// Merges the contents of another fully-specified property dictionary with this one. +void PropertyDictionary::Merge(const PropertyDictionary& property_dictionary, int specificity_offset) +{ + for (PropertyMap::const_iterator iterator = property_dictionary.properties.begin(); iterator != property_dictionary.properties.end(); ++iterator) + { + const Property& property = iterator->second; + SetProperty(iterator->first, property, property.specificity + specificity_offset); + } +} + +void PropertyDictionary::SetSourceOfAllProperties(const SharedPtr& property_source) +{ + for (auto& p : properties) + p.second.source = property_source; +} + +// Sets a property on the dictionary and its specificity. +void PropertyDictionary::SetProperty(PropertyId id, const Property& property, int specificity) +{ + PropertyMap::iterator iterator = properties.find(id); + if (iterator != properties.end() && + iterator->second.specificity > specificity) + return; + + Property& new_property = (properties[id] = property); + new_property.specificity = specificity; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserAnimation.cpp b/thirdparty/RmlUi/Source/Core/PropertyParserAnimation.cpp new file mode 100644 index 000000000..b700b94c0 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserAnimation.cpp @@ -0,0 +1,376 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2018 Michael R. P. Ragazzon + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "PropertyParserAnimation.h" +#include "PropertyShorthandDefinition.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" + + +namespace Rml { + +struct Keyword { + enum Type { NONE, TWEEN, ALL, ALTERNATE, INFINITE, PAUSED } type; + Tween tween; + Keyword(Tween tween) : type(TWEEN), tween(tween) {} + Keyword(Type type) : type(type) {} + + bool ValidTransition() const { + return type == NONE || type == TWEEN || type == ALL; + } + bool ValidAnimation() const { + return type == NONE || type == TWEEN || type == ALTERNATE || type == INFINITE || type == PAUSED; + } +}; + + +static const UnorderedMap keywords = { + {"none", {Keyword::NONE} }, + {"all", {Keyword::ALL}}, + {"alternate", {Keyword::ALTERNATE}}, + {"infinite", {Keyword::INFINITE}}, + {"paused", {Keyword::PAUSED}}, + + {"back-in", {Tween{Tween::Back, Tween::In}}}, + {"back-out", {Tween{Tween::Back, Tween::Out}}}, + {"back-in-out", {Tween{Tween::Back, Tween::InOut}}}, + + {"bounce-in", {Tween{Tween::Bounce, Tween::In}}}, + {"bounce-out", {Tween{Tween::Bounce, Tween::Out}}}, + {"bounce-in-out", {Tween{Tween::Bounce, Tween::InOut}}}, + + {"circular-in", {Tween{Tween::Circular, Tween::In}}}, + {"circular-out", {Tween{Tween::Circular, Tween::Out}}}, + {"circular-in-out", {Tween{Tween::Circular, Tween::InOut}}}, + + {"cubic-in", {Tween{Tween::Cubic, Tween::In}}}, + {"cubic-out", {Tween{Tween::Cubic, Tween::Out}}}, + {"cubic-in-out", {Tween{Tween::Cubic, Tween::InOut}}}, + + {"elastic-in", {Tween{Tween::Elastic, Tween::In}}}, + {"elastic-out", {Tween{Tween::Elastic, Tween::Out}}}, + {"elastic-in-out", {Tween{Tween::Elastic, Tween::InOut}}}, + + {"exponential-in", {Tween{Tween::Exponential, Tween::In}}}, + {"exponential-out", {Tween{Tween::Exponential, Tween::Out}}}, + {"exponential-in-out", {Tween{Tween::Exponential, Tween::InOut}}}, + + {"linear-in", {Tween{Tween::Linear, Tween::In}}}, + {"linear-out", {Tween{Tween::Linear, Tween::Out}}}, + {"linear-in-out", {Tween{Tween::Linear, Tween::InOut}}}, + + {"quadratic-in", {Tween{Tween::Quadratic, Tween::In}}}, + {"quadratic-out", {Tween{Tween::Quadratic, Tween::Out}}}, + {"quadratic-in-out", {Tween{Tween::Quadratic, Tween::InOut}}}, + + {"quartic-in", {Tween{Tween::Quartic, Tween::In}}}, + {"quartic-out", {Tween{Tween::Quartic, Tween::Out}}}, + {"quartic-in-out", {Tween{Tween::Quartic, Tween::InOut}}}, + + {"quintic-in", {Tween{Tween::Quintic, Tween::In}}}, + {"quintic-out", {Tween{Tween::Quintic, Tween::Out}}}, + {"quintic-in-out", {Tween{Tween::Quintic, Tween::InOut}}}, + + {"sine-in", {Tween{Tween::Sine, Tween::In}}}, + {"sine-out", {Tween{Tween::Sine, Tween::Out}}}, + {"sine-in-out", {Tween{Tween::Sine, Tween::InOut}}}, +}; + + + + +PropertyParserAnimation::PropertyParserAnimation(Type type) : type(type) +{ +} + + +static bool ParseAnimation(Property & property, const StringList& animation_values) +{ + AnimationList animation_list; + + for (const String& single_animation_value : animation_values) + { + Animation animation; + + StringList arguments; + StringUtilities::ExpandString(arguments, single_animation_value, ' '); + + bool duration_found = false; + bool delay_found = false; + bool num_iterations_found = false; + + for (auto& argument : arguments) + { + if (argument.empty()) + continue; + + // See if we have a or specifier as defined in keywords + auto it = keywords.find(argument); + if (it != keywords.end() && it->second.ValidAnimation()) + { + switch (it->second.type) + { + case Keyword::NONE: + { + if (animation_list.size() > 0) // The none keyword can not be part of multiple definitions + return false; + property = Property{ AnimationList{}, Property::ANIMATION }; + return true; + } + break; + case Keyword::TWEEN: + animation.tween = it->second.tween; + break; + case Keyword::ALTERNATE: + animation.alternate = true; + break; + case Keyword::INFINITE: + if (num_iterations_found) + return false; + animation.num_iterations = -1; + num_iterations_found = true; + break; + case Keyword::PAUSED: + animation.paused = true; + break; + default: + break; + } + } + else + { + // Either , , or a + float number = 0.0f; + int count = 0; + + if (sscanf(argument.c_str(), "%fs%n", &number, &count) == 1) + { + // Found a number, if there was an 's' unit, count will be positive + if (count > 0) + { + // Duration or delay was assigned + if (!duration_found) + { + duration_found = true; + animation.duration = number; + } + else if (!delay_found) + { + delay_found = true; + animation.delay = number; + } + else + return false; + } + else + { + // No 's' unit means num_iterations was found + if (!num_iterations_found) + { + animation.num_iterations = Math::RoundToInteger(number); + num_iterations_found = true; + } + else + return false; + } + } + else + { + // Must be an animation name + animation.name = argument; + } + } + } + + // Validate the parsed transition + if (animation.name.empty() || animation.duration <= 0.0f || (animation.num_iterations < -1 || animation.num_iterations == 0)) + { + return false; + } + + animation_list.push_back(std::move(animation)); + } + + property.value = std::move(animation_list); + property.unit = Property::ANIMATION; + + return true; +} + + +static bool ParseTransition(Property & property, const StringList& transition_values) +{ + TransitionList transition_list{ false, false, {} }; + + for (const String& single_transition_value : transition_values) + { + + Transition transition; + PropertyIdSet target_property_names; + + StringList arguments; + StringUtilities::ExpandString(arguments, single_transition_value, ' '); + + + bool duration_found = false; + bool delay_found = false; + bool reverse_adjustment_factor_found = false; + + for (auto& argument : arguments) + { + if (argument.empty()) + continue; + + // See if we have a or specifier as defined in keywords + auto it = keywords.find(argument); + if (it != keywords.end() && it->second.ValidTransition()) + { + if (it->second.type == Keyword::NONE) + { + if (transition_list.transitions.size() > 0) // The none keyword can not be part of multiple definitions + return false; + property = Property{ TransitionList{true, false, {}}, Property::TRANSITION }; + return true; + } + else if (it->second.type == Keyword::ALL) + { + if (transition_list.transitions.size() > 0) // The all keyword can not be part of multiple definitions + return false; + transition_list.all = true; + } + else if (it->second.type == Keyword::TWEEN) + { + transition.tween = it->second.tween; + } + } + else + { + // Either , or a + float number = 0.0f; + int count = 0; + + if (sscanf(argument.c_str(), "%fs%n", &number, &count) == 1) + { + // Found a number, if there was an 's' unit, count will be positive + if (count > 0) + { + // Duration or delay was assigned + if (!duration_found) + { + duration_found = true; + transition.duration = number; + } + else if (!delay_found) + { + delay_found = true; + transition.delay = number; + } + else + return false; + } + else + { + // No 's' unit means reverse adjustment factor was found + if (!reverse_adjustment_factor_found) + { + reverse_adjustment_factor_found = true; + transition.reverse_adjustment_factor = number; + } + else + return false; + } + } + else + { + // Must be a property name or shorthand, expand now + if (auto shorthand = StyleSheetSpecification::GetShorthand(argument)) + { + PropertyIdSet underlying_properties = StyleSheetSpecification::GetShorthandUnderlyingProperties(shorthand->id); + target_property_names |= underlying_properties; + } + else if (auto definition = StyleSheetSpecification::GetProperty(argument)) + { + // Single property + target_property_names.Insert(definition->GetId()); + } + else + { + // Unknown property name + return false; + } + } + } + } + + // Validate the parsed transition + if (target_property_names.Empty() || transition.duration <= 0.0f || transition.reverse_adjustment_factor < 0.0f || transition.reverse_adjustment_factor > 1.0f + || (transition_list.all && target_property_names.Size() != 1)) + { + return false; + } + + for (const auto& property_name : target_property_names) + { + transition.id = property_name; + transition_list.transitions.push_back(transition); + } + } + + property.value = std::move(transition_list); + property.unit = Property::TRANSITION; + + return true; +} + + +bool PropertyParserAnimation::ParseValue(Property & property, const String & value, const ParameterMap & /*parameters*/) const +{ + StringList list_of_values; + { + auto lowercase_value = StringUtilities::ToLower(value); + StringUtilities::ExpandString(list_of_values, lowercase_value, ','); + } + + bool result = false; + + if (type == ANIMATION_PARSER) + { + result = ParseAnimation(property, list_of_values); + } + else if (type == TRANSITION_PARSER) + { + result = ParseTransition(property, list_of_values); + } + + return result; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserAnimation.h b/thirdparty/RmlUi/Source/Core/PropertyParserAnimation.h new file mode 100644 index 000000000..c5e82d4d3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserAnimation.h @@ -0,0 +1,63 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2018 Michael R. P. Ragazzon + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + + +#ifndef RMLUI_CORE_PROPERTYPARSERANIMATION_H +#define RMLUI_CORE_PROPERTYPARSERANIMATION_H + + +#include "../../Include/RmlUi/Core/PropertyParser.h" + +namespace Rml { + +/** +Parses the RCSS 'animation' and 'transition' property specifications. +*/ + +class PropertyParserAnimation : public PropertyParser +{ +public: + enum Type { ANIMATION_PARSER, TRANSITION_PARSER } type; + + /// Constructs the parser for either the animation or the transition type. + PropertyParserAnimation(Type type); + + + /// Called to parse a RCSS animation or transition declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The parameters defined for this property. + /// @return True if the value was validated successfully, false otherwise. + bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override; +}; + + + +} // namespace Rml +#endif \ No newline at end of file diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserColour.cpp b/thirdparty/RmlUi/Source/Core/PropertyParserColour.cpp new file mode 100644 index 000000000..86bf42aa7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserColour.cpp @@ -0,0 +1,172 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "PropertyParserColour.h" +#include + +namespace Rml { + +PropertyParserColour::PropertyParserColour() +{ + html_colours["black"] = Colourb(0, 0, 0); + html_colours["silver"] = Colourb(192, 192, 192); + html_colours["gray"] = Colourb(128, 128, 128); + html_colours["grey"] = Colourb(128, 128, 128); + html_colours["white"] = Colourb(255, 255, 255); + html_colours["maroon"] = Colourb(128, 0, 0); + html_colours["red"] = Colourb(255, 0, 0); + html_colours["orange"] = Colourb(255, 165, 0); + html_colours["purple"] = Colourb(128, 0, 128); + html_colours["fuschia"] = Colourb(255, 0, 255); + html_colours["green"] = Colourb(0, 128, 0); + html_colours["lime"] = Colourb(0, 255, 0); + html_colours["olive"] = Colourb(128, 128, 0); + html_colours["yellow"] = Colourb(255, 255, 0); + html_colours["navy"] = Colourb(0, 0, 128); + html_colours["blue"] = Colourb(0, 0, 255); + html_colours["teal"] = Colourb(0, 128, 128); + html_colours["aqua"] = Colourb(0, 255, 255); + html_colours["transparent"] = Colourb(255, 255, 255, 0); +} + +PropertyParserColour::~PropertyParserColour() +{ +} + +// Called to parse a RCSS colour declaration. +bool PropertyParserColour::ParseValue(Property& property, const String& value, const ParameterMap& RMLUI_UNUSED_PARAMETER(parameters)) const +{ + RMLUI_UNUSED(parameters); + + if (value.empty()) + return false; + + Colourb colour; + + // Check for a hex colour. + if (value[0] == '#') + { + char hex_values[4][2] = { {'f', 'f'}, + {'f', 'f'}, + {'f', 'f'}, + {'f', 'f'} }; + + switch (value.size()) + { + // Single hex digit per channel, RGB and alpha. + case 5: hex_values[3][0] = hex_values[3][1] = value[4]; + //-fallthrough + // Single hex digit per channel, RGB only. + case 4: hex_values[0][0] = hex_values[0][1] = value[1]; + hex_values[1][0] = hex_values[1][1] = value[2]; + hex_values[2][0] = hex_values[2][1] = value[3]; + break; + + // Two hex digits per channel, RGB and alpha. + case 9: hex_values[3][0] = value[7]; + hex_values[3][1] = value[8]; + //-fallthrough + // Two hex digits per channel, RGB only. + case 7: memcpy(hex_values, &value.c_str()[1], sizeof(char) * 6); + break; + + default: + return false; + } + + // Parse each of the colour elements. + for (int i = 0; i < 4; i++) + { + int tens = Math::HexToDecimal(hex_values[i][0]); + int ones = Math::HexToDecimal(hex_values[i][1]); + if (tens == -1 || + ones == -1) + return false; + + colour[i] = (byte) (tens * 16 + ones); + } + } + else if (value.substr(0, 3) == "rgb") + { + StringList values; + values.reserve(4); + + size_t find = value.find('('); + if (find == String::npos) + return false; + + size_t begin_values = find + 1; + + StringUtilities::ExpandString(values, value.substr(begin_values, value.rfind(')') - begin_values), ','); + + // Check if we're parsing an 'rgba' or 'rgb' colour declaration. + if (value.size() > 3 && value[3] == 'a') + { + if (values.size() != 4) + return false; + } + else + { + if (values.size() != 3) + return false; + + values.push_back("255"); + } + + // Parse the three RGB values. + for (int i = 0; i < 4; ++i) + { + int component; + + // We're parsing a percentage value. + if (values[i].size() > 0 && values[i][values[i].size() - 1] == '%') + component = Math::RealToInteger((float) (atof(values[i].substr(0, values[i].size() - 1).c_str()) / 100.0f) * 255.0f); + // We're parsing a 0 -> 255 integer value. + else + component = atoi(values[i].c_str()); + + colour[i] = (byte) (Math::Clamp(component, 0, 255)); + } + } + else + { + // Check for the specification of an HTML colour. + ColourMap::const_iterator iterator = html_colours.find(StringUtilities::ToLower(value)); + if (iterator == html_colours.end()) + return false; + else + colour = (*iterator).second; + } + + property.value = Variant(colour); + property.unit = Property::COLOUR; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserColour.h b/thirdparty/RmlUi/Source/Core/PropertyParserColour.h new file mode 100644 index 000000000..fe21ed870 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserColour.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYPARSERCOLOUR_H +#define RMLUI_CORE_PROPERTYPARSERCOLOUR_H + +#include "../../Include/RmlUi/Core/PropertyParser.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +/** + A property parser that parses a colour value. + + @author Peter Curry + */ + +class PropertyParserColour : public PropertyParser +{ +public: + PropertyParserColour(); + virtual ~PropertyParserColour(); + + /// Called to parse a RCSS colour declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The parameters defined for this property; not used for this parser. + /// @return True if the value was parsed successfully, false otherwise. + bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override; + +private: + using ColourMap = UnorderedMap< String, Colourb>; + ColourMap html_colours; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserKeyword.cpp b/thirdparty/RmlUi/Source/Core/PropertyParserKeyword.cpp new file mode 100644 index 000000000..adac8bc4a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserKeyword.cpp @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "PropertyParserKeyword.h" + +namespace Rml { + +PropertyParserKeyword::PropertyParserKeyword() +{ +} + +PropertyParserKeyword::~PropertyParserKeyword() +{ +} + +// Called to parse a RCSS keyword declaration. +bool PropertyParserKeyword::ParseValue(Property& property, const String& value, const ParameterMap& parameters) const +{ + ParameterMap::const_iterator iterator = parameters.find(StringUtilities::ToLower(value)); + if (iterator == parameters.end()) + return false; + + property.value = Variant((*iterator).second); + property.unit = Property::KEYWORD; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserKeyword.h b/thirdparty/RmlUi/Source/Core/PropertyParserKeyword.h new file mode 100644 index 000000000..77578ab4c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserKeyword.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYPARSERKEYWORD_H +#define RMLUI_CORE_PROPERTYPARSERKEYWORD_H + +#include "../../Include/RmlUi/Core/PropertyParser.h" + +namespace Rml { + +/** + A property parser that validates a value is part of a specified list of keywords. + + @author Peter Curry + */ + +class PropertyParserKeyword : public PropertyParser +{ +public: + PropertyParserKeyword(); + virtual ~PropertyParserKeyword(); + + /// Called to parse a RCSS keyword declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The parameters defined for this property. + /// @return True if the value was validated successfully, false otherwise. + bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserNumber.cpp b/thirdparty/RmlUi/Source/Core/PropertyParserNumber.cpp new file mode 100644 index 000000000..ccf0ba3e8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserNumber.cpp @@ -0,0 +1,117 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "PropertyParserNumber.h" +#include + +namespace Rml { + +static const UnorderedMap g_property_unit_string_map = +{ + {"", Property::NUMBER}, + {"%", Property::PERCENT}, + {"px", Property::PX}, + {"dp", Property::DP}, + {"em", Property::EM}, + {"rem", Property::REM}, + {"in", Property::INCH}, + {"cm", Property::CM}, + {"mm", Property::MM}, + {"pt", Property::PT}, + {"pc", Property::PC}, + {"deg", Property::DEG}, + {"rad", Property::RAD}, +}; + +PropertyParserNumber::PropertyParserNumber(int units, Property::Unit zero_unit) + : units(units), zero_unit(zero_unit) +{} + +PropertyParserNumber::~PropertyParserNumber() +{} + +// Called to parse a RCSS number declaration. +bool PropertyParserNumber::ParseValue(Property& property, const String& value, const ParameterMap& RMLUI_UNUSED_PARAMETER(parameters)) const +{ + RMLUI_UNUSED(parameters); + + // Find the beginning of the unit string in 'value'. + size_t unit_pos = 0; + for (size_t i = value.size(); i--;) + { + const char c = value[i]; + if ((c >= '0' && c <= '9') || StringUtilities::IsWhitespace(c)) + { + unit_pos = i + 1; + break; + } + } + + String str_number = value.substr(0, unit_pos); + String str_unit = StringUtilities::ToLower(value.substr(unit_pos)); + + char* str_end = nullptr; + float float_value = strtof(str_number.c_str(), &str_end); + if (str_number.c_str() == str_end) + { + // Number conversion failed + return false; + } + + const auto it = g_property_unit_string_map.find(str_unit); + if (it == g_property_unit_string_map.end()) + { + // Invalid unit name + return false; + } + + const Property::Unit unit = it->second; + + if (unit & units) + { + property.value = float_value; + property.unit = unit; + return true; + } + + // Detected unit not allowed. + // However, we allow a value of "0" if zero_unit is set and no unit specified (that is, unit is a pure NUMBER). + if (unit == Property::NUMBER) + { + if (zero_unit != Property::UNKNOWN && float_value == 0.0f) + { + property.unit = zero_unit; + property.value = Variant(0.0f); + return true; + } + } + + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserNumber.h b/thirdparty/RmlUi/Source/Core/PropertyParserNumber.h new file mode 100644 index 000000000..98f6d02b6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserNumber.h @@ -0,0 +1,64 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYPARSERNUMBER_H +#define RMLUI_CORE_PROPERTYPARSERNUMBER_H + +#include "../../Include/RmlUi/Core/PropertyParser.h" + +namespace Rml { + +/** + A property parser that parses a floating-point number with an optional unit. + + @author Peter Curry + */ + +class PropertyParserNumber : public PropertyParser +{ +public: + PropertyParserNumber(int units, Property::Unit zero_unit = Property::UNKNOWN); + virtual ~PropertyParserNumber(); + + /// Called to parse a RCSS number declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The parameters defined for this property. + /// @return True if the value was validated successfully, false otherwise. + bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override; + +private: + // Stores a bit mask of allowed units. + int units; + + // If zero unit is set and pure numbers are not allowed, parsing of "0" is still allowed and assigned the given unit. + Property::Unit zero_unit; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserString.cpp b/thirdparty/RmlUi/Source/Core/PropertyParserString.cpp new file mode 100644 index 000000000..4cc3223d9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserString.cpp @@ -0,0 +1,52 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "PropertyParserString.h" + +namespace Rml { + +PropertyParserString::PropertyParserString() +{ +} + +PropertyParserString::~PropertyParserString() +{ +} + +// Called to parse a RCSS string declaration. +bool PropertyParserString::ParseValue(Property& property, const String& value, const ParameterMap& RMLUI_UNUSED_PARAMETER(parameters)) const +{ + RMLUI_UNUSED(parameters); + + property.value = Variant(value); + property.unit = Property::STRING; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserString.h b/thirdparty/RmlUi/Source/Core/PropertyParserString.h new file mode 100644 index 000000000..15c4bb987 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserString.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYPARSERSTRING_H +#define RMLUI_CORE_PROPERTYPARSERSTRING_H + +#include "../../Include/RmlUi/Core/PropertyParser.h" + +namespace Rml { + +/** + A passthrough property parser that parses a string. + + @author Peter Curry + */ + +class PropertyParserString : public PropertyParser +{ +public: + PropertyParserString(); + virtual ~PropertyParserString(); + + /// Called to parse a RCSS string declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The parameters defined for this property; not used for this parser. + /// @return True if the value was validated successfully, false otherwise. + bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserTransform.cpp b/thirdparty/RmlUi/Source/Core/PropertyParserTransform.cpp new file mode 100644 index 000000000..c05cd4768 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserTransform.cpp @@ -0,0 +1,293 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "PropertyParserTransform.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" +#include "../../Include/RmlUi/Core/Transform.h" +#include + +namespace Rml { + +PropertyParserTransform::PropertyParserTransform() + : number(Property::NUMBER), + length(Property::LENGTH_PERCENT, Property::PX), + angle(Property::ANGLE, Property::RAD) +{ +} + +PropertyParserTransform::~PropertyParserTransform() +{ +} + +// Called to parse a RCSS transform declaration. +bool PropertyParserTransform::ParseValue(Property& property, const String& value, const ParameterMap& /*parameters*/) const +{ + if(value == "none") + { + property.value = Variant(TransformPtr()); + property.unit = Property::TRANSFORM; + return true; + } + + TransformPtr transform = MakeShared(); + + char const* next = value.c_str(); + + Transforms::NumericValue args[16]; + + const PropertyParser* angle1[] = { &angle }; + const PropertyParser* angle2[] = { &angle, &angle }; + const PropertyParser* length1[] = { &length }; + const PropertyParser* length2[] = { &length, &length }; + const PropertyParser* length3[] = { &length, &length, &length }; + const PropertyParser* number3angle1[] = { &number, &number, &number, &angle }; + const PropertyParser* number1[] = { &number }; + const PropertyParser* number2[] = { &number, &number }; + const PropertyParser* number3[] = { &number, &number, &number }; + const PropertyParser* number6[] = { &number, &number, &number, &number, &number, &number }; + const PropertyParser* number16[] = { &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number }; + + while (*next) + { + using namespace Transforms; + int bytes_read = 0; + + if (Scan(bytes_read, next, "perspective", length1, args, 1)) + { + transform->AddPrimitive({ Perspective(args) }); + } + else if (Scan(bytes_read, next, "matrix", number6, args, 6)) + { + transform->AddPrimitive({ Matrix2D(args) }); + } + else if (Scan(bytes_read, next, "matrix3d", number16, args, 16)) + { + transform->AddPrimitive({ Matrix3D(args) }); + } + else if (Scan(bytes_read, next, "translateX", length1, args, 1)) + { + transform->AddPrimitive({ TranslateX(args) }); + } + else if (Scan(bytes_read, next, "translateY", length1, args, 1)) + { + transform->AddPrimitive({ TranslateY(args) }); + } + else if (Scan(bytes_read, next, "translateZ", length1, args, 1)) + { + transform->AddPrimitive({ TranslateZ(args) }); + } + else if (Scan(bytes_read, next, "translate", length2, args, 2)) + { + transform->AddPrimitive({ Translate2D(args) }); + } + else if (Scan(bytes_read, next, "translate3d", length3, args, 3)) + { + transform->AddPrimitive({ Translate3D(args) }); + } + else if (Scan(bytes_read, next, "scaleX", number1, args, 1)) + { + transform->AddPrimitive({ ScaleX(args) }); + } + else if (Scan(bytes_read, next, "scaleY", number1, args, 1)) + { + transform->AddPrimitive({ ScaleY(args) }); + } + else if (Scan(bytes_read, next, "scaleZ", number1, args, 1)) + { + transform->AddPrimitive({ ScaleZ(args) }); + } + else if (Scan(bytes_read, next, "scale", number2, args, 2)) + { + transform->AddPrimitive({ Scale2D(args) }); + } + else if (Scan(bytes_read, next, "scale", number1, args, 1)) + { + args[1] = args[0]; + transform->AddPrimitive({ Scale2D(args) }); + } + else if (Scan(bytes_read, next, "scale3d", number3, args, 3)) + { + transform->AddPrimitive({ Scale3D(args) }); + } + else if (Scan(bytes_read, next, "rotateX", angle1, args, 1)) + { + transform->AddPrimitive({ RotateX(args) }); + } + else if (Scan(bytes_read, next, "rotateY", angle1, args, 1)) + { + transform->AddPrimitive({ RotateY(args) }); + } + else if (Scan(bytes_read, next, "rotateZ", angle1, args, 1)) + { + transform->AddPrimitive({ RotateZ(args) }); + } + else if (Scan(bytes_read, next, "rotate", angle1, args, 1)) + { + transform->AddPrimitive({ Rotate2D(args) }); + } + else if (Scan(bytes_read, next, "rotate3d", number3angle1, args, 4)) + { + transform->AddPrimitive({ Rotate3D(args) }); + } + else if (Scan(bytes_read, next, "skewX", angle1, args, 1)) + { + transform->AddPrimitive({ SkewX(args) }); + } + else if (Scan(bytes_read, next, "skewY", angle1, args, 1)) + { + transform->AddPrimitive({ SkewY(args) }); + } + else if (Scan(bytes_read, next, "skew", angle2, args, 2)) + { + transform->AddPrimitive({ Skew2D(args) }); + } + + if (bytes_read > 0) + { + next += bytes_read; + } + else + { + return false; + } + } + + property.value = Variant(std::move(transform)); + property.unit = Property::TRANSFORM; + + return true; +} + +// Scan a string for a parameterized keyword with a certain number of numeric arguments. +bool PropertyParserTransform::Scan(int& out_bytes_read, const char* str, const char* keyword, const PropertyParser** parsers, Transforms::NumericValue* args, int nargs) const +{ + out_bytes_read = 0; + int total_bytes_read = 0, bytes_read = 0; + + /* use the quicker stack-based argument buffer, if possible */ + char *arg = 0; + char arg_stack[1024]; + String arg_heap; + if (strlen(str) < sizeof(arg_stack)) + { + arg = arg_stack; + } + else + { + arg_heap = str; + arg = &arg_heap[0]; + } + + /* skip leading white space */ + bytes_read = 0; + sscanf(str, " %n", &bytes_read); + str += bytes_read; + total_bytes_read += bytes_read; + + /* find the keyword */ + if (!memcmp(str, keyword, strlen(keyword))) + { + bytes_read = (int)strlen(keyword); + str += bytes_read; + total_bytes_read += bytes_read; + } + else + { + return false; + } + + /* skip any white space */ + bytes_read = 0; + sscanf(str, " %n", &bytes_read); + str += bytes_read; + total_bytes_read += bytes_read; + + /* find the opening brace */ + bytes_read = 0; + if (sscanf(str, " ( %n", &bytes_read), bytes_read) + { + str += bytes_read; + total_bytes_read += bytes_read; + } + else + { + return false; + } + + /* parse the arguments */ + for (int i = 0; i < nargs; ++i) + { + Property prop; + + bytes_read = 0; + if (sscanf(str, " %[^,)] %n", arg, &bytes_read), bytes_read + && parsers[i]->ParseValue(prop, String(arg), ParameterMap())) + { + args[i].number = prop.value.Get(); + args[i].unit = prop.unit; + str += bytes_read; + total_bytes_read += bytes_read; + } + else + { + return false; + } + + /* find the comma */ + if (i < nargs - 1) + { + bytes_read = 0; + if (sscanf(str, " , %n", &bytes_read), bytes_read) + { + str += bytes_read; + total_bytes_read += bytes_read; + } + else + { + return false; + } + } + } + + /* find the closing brace */ + bytes_read = 0; + if (sscanf(str, " ) %n", &bytes_read), bytes_read) + { + str += bytes_read; + total_bytes_read += bytes_read; + } + else + { + return false; + } + + out_bytes_read = total_bytes_read; + return total_bytes_read > 0; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/PropertyParserTransform.h b/thirdparty/RmlUi/Source/Core/PropertyParserTransform.h new file mode 100644 index 000000000..eb29a22ff --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyParserTransform.h @@ -0,0 +1,73 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYPARSERTRANSFORM_H +#define RMLUI_CORE_PROPERTYPARSERTRANSFORM_H + +#include "../../Include/RmlUi/Core/PropertyParser.h" +#include "PropertyParserNumber.h" + +namespace Rml { + +namespace Transforms { struct NumericValue; } + + +/** + A property parser that parses a RCSS transform property specification. + + @author Markus Schöngart + */ +class PropertyParserTransform : public PropertyParser +{ +public: + PropertyParserTransform(); + virtual ~PropertyParserTransform(); + + /// Called to parse a RCSS transform declaration. + /// @param[out] property The property to set the parsed value on. + /// @param[in] value The raw value defined for this property. + /// @param[in] parameters The parameters defined for this property. + /// @return True if the value was validated successfully, false otherwise. + bool ParseValue(Property& property, const String& value, const ParameterMap& parameters) const override; + +private: + /// Scan a string for a parameterized keyword with a certain number of numeric arguments. + /// @param[out] out_bytes_read The number of bytes read if the keyword occurs at the beginning of str, 0 otherwise. + /// @param[in] str The string to search for the parameterized keyword + /// @param[in] keyword The name of the keyword to search for + /// @param[in] parsers The numeric argument parsers + /// @param[out] args The numeric arguments encountered + /// @param[in] nargs The number of numeric arguments expected + /// @return True if parsed successfully, false otherwise. + bool Scan(int& out_bytes_read, const char* str, const char* keyword, const PropertyParser** parsers, Transforms::NumericValue* args, int nargs) const; + + PropertyParserNumber number, length, angle; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertyShorthandDefinition.h b/thirdparty/RmlUi/Source/Core/PropertyShorthandDefinition.h new file mode 100644 index 000000000..4e67a29bb --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertyShorthandDefinition.h @@ -0,0 +1,71 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PROPERTYSHORTHANDDEFINITION_H +#define RMLUI_CORE_PROPERTYSHORTHANDDEFINITION_H + +#include "../../Include/RmlUi/Core/ID.h" + +namespace Rml { + +enum class ShorthandType; +class PropertyDefinition; +struct ShorthandDefinition; + +enum class ShorthandItemType { Invalid, Property, Shorthand }; + +// Each entry in a shorthand points either to another shorthand or a property +struct ShorthandItem { + ShorthandItem() : type(ShorthandItemType::Invalid), property_id(PropertyId::Invalid), property_definition(nullptr), optional(false) {} + ShorthandItem(PropertyId id, const PropertyDefinition* definition, bool optional) : type(ShorthandItemType::Property), property_id(id), property_definition(definition), optional(optional) {} + ShorthandItem(ShorthandId id, const ShorthandDefinition* definition, bool optional) : type(ShorthandItemType::Shorthand), shorthand_id(id), shorthand_definition(definition), optional(optional) {} + + ShorthandItemType type; + union { + PropertyId property_id; + ShorthandId shorthand_id; + }; + union { + const PropertyDefinition* property_definition; + const ShorthandDefinition* shorthand_definition; + }; + bool optional; +}; + +// A list of shorthands or properties +using ShorthandItemList = Vector< ShorthandItem >; + +struct ShorthandDefinition +{ + ShorthandId id; + ShorthandItemList items; + ShorthandType type; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/PropertySpecification.cpp b/thirdparty/RmlUi/Source/Core/PropertySpecification.cpp new file mode 100644 index 000000000..d6c404e66 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/PropertySpecification.cpp @@ -0,0 +1,571 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/PropertySpecification.h" +#include "../../Include/RmlUi/Core/Debug.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/PropertyDictionary.h" +#include "PropertyShorthandDefinition.h" +#include "IdNameMap.h" +#include +#include + +namespace Rml { + +PropertySpecification::PropertySpecification(size_t reserve_num_properties, size_t reserve_num_shorthands) : + // Increment reserve numbers by one because the 'invalid' property occupies the first element + properties(reserve_num_properties + 1), shorthands(reserve_num_shorthands + 1), + property_map(MakeUnique(reserve_num_properties + 1)), shorthand_map(MakeUnique(reserve_num_shorthands + 1)) +{ +} + +PropertySpecification::~PropertySpecification() +{ +} + +// Registers a property with a new definition. +PropertyDefinition& PropertySpecification::RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout, PropertyId id) +{ + if (id == PropertyId::Invalid) + id = property_map->GetOrCreateId(property_name); + else + property_map->AddPair(id, property_name); + + size_t index = (size_t)id; + + if (index >= size_t(PropertyId::MaxNumIds)) + { + Log::Message(Log::LT_ERROR, "Fatal error while registering property '%s': Maximum number of allowed properties exceeded. Continuing execution may lead to crash.", property_name.c_str()); + RMLUI_ERROR; + return *properties[0]; + } + + if (index < properties.size()) + { + // We don't want to owerwrite an existing entry. + if (properties[index]) + { + Log::Message(Log::LT_ERROR, "While registering property '%s': The property is already registered.", property_name.c_str()); + return *properties[index]; + } + } + else + { + // Resize vector to hold the new index + properties.resize((index*3)/2 + 1); + } + + // Create and insert the new property + properties[index] = MakeUnique(id, default_value, inherited, forces_layout); + property_ids.Insert(id); + if (inherited) + property_ids_inherited.Insert(id); + if (forces_layout) + property_ids_forcing_layout.Insert(id); + + return *properties[index]; +} + +// Returns a property definition. +const PropertyDefinition* PropertySpecification::GetProperty(PropertyId id) const +{ + if (id == PropertyId::Invalid || (size_t)id >= properties.size()) + return nullptr; + + return properties[(size_t)id].get(); +} + +const PropertyDefinition* PropertySpecification::GetProperty(const String& property_name) const +{ + return GetProperty(property_map->GetId(property_name)); +} + +// Fetches a list of the names of all registered property definitions. +const PropertyIdSet& PropertySpecification::GetRegisteredProperties(void) const +{ + return property_ids; +} + +// Fetches a list of the names of all registered property definitions. +const PropertyIdSet& PropertySpecification::GetRegisteredInheritedProperties(void) const +{ + return property_ids_inherited; +} + +const PropertyIdSet& PropertySpecification::GetRegisteredPropertiesForcingLayout() const +{ + return property_ids_forcing_layout; +} + +// Registers a shorthand property definition. +ShorthandId PropertySpecification::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type, ShorthandId id) +{ + if (id == ShorthandId::Invalid) + id = shorthand_map->GetOrCreateId(shorthand_name); + else + shorthand_map->AddPair(id, shorthand_name); + + StringList property_list; + StringUtilities::ExpandString(property_list, StringUtilities::ToLower(property_names)); + + // Construct the new shorthand definition and resolve its properties. + UniquePtr property_shorthand(new ShorthandDefinition()); + + for (const String& raw_name : property_list) + { + ShorthandItem item; + bool optional = false; + String name = raw_name; + + if (!raw_name.empty() && raw_name.back() == '?') + { + optional = true; + name.pop_back(); + } + + PropertyId property_id = property_map->GetId(name); + if (property_id != PropertyId::Invalid) + { + // We have a valid property + if (const PropertyDefinition* property = GetProperty(property_id)) + item = ShorthandItem(property_id, property, optional); + } + else + { + // Otherwise, we must be a shorthand + ShorthandId shorthand_id = shorthand_map->GetId(name); + + // Test for valid shorthand id. The recursive types (and only those) can hold other shorthands. + if (shorthand_id != ShorthandId::Invalid && (type == ShorthandType::RecursiveRepeat || type == ShorthandType::RecursiveCommaSeparated)) + { + if (const ShorthandDefinition * shorthand = GetShorthand(shorthand_id)) + item = ShorthandItem(shorthand_id, shorthand, optional); + } + } + + if (item.type == ShorthandItemType::Invalid) + { + Log::Message(Log::LT_ERROR, "Shorthand property '%s' was registered with invalid property '%s'.", shorthand_name.c_str(), name.c_str()); + return ShorthandId::Invalid; + } + property_shorthand->items.push_back(item); + } + + property_shorthand->id = id; + property_shorthand->type = type; + + const size_t index = (size_t)id; + + if (index >= size_t(ShorthandId::MaxNumIds)) + { + Log::Message(Log::LT_ERROR, "Error while registering shorthand '%s': Maximum number of allowed shorthands exceeded.", shorthand_name.c_str()); + return ShorthandId::Invalid; + } + + if (index < shorthands.size()) + { + // We don't want to owerwrite an existing entry. + if (shorthands[index]) + { + Log::Message(Log::LT_ERROR, "The shorthand '%s' already exists, ignoring.", shorthand_name.c_str()); + return ShorthandId::Invalid; + } + } + else + { + // Resize vector to hold the new index + shorthands.resize((index * 3) / 2 + 1); + } + + shorthands[index] = std::move(property_shorthand); + return id; +} + +// Returns a shorthand definition. +const ShorthandDefinition* PropertySpecification::GetShorthand(ShorthandId id) const +{ + if (id == ShorthandId::Invalid || (size_t)id >= shorthands.size()) + return nullptr; + + return shorthands[(size_t)id].get(); +} + +const ShorthandDefinition* PropertySpecification::GetShorthand(const String& shorthand_name) const +{ + return GetShorthand(shorthand_map->GetId(shorthand_name)); +} + +bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value) const +{ + // Try as a property first + PropertyId property_id = property_map->GetId(property_name); + if (property_id != PropertyId::Invalid) + return ParsePropertyDeclaration(dictionary, property_id, property_value); + + // Then, as a shorthand + ShorthandId shorthand_id = shorthand_map->GetId(property_name); + if (shorthand_id != ShorthandId::Invalid) + return ParseShorthandDeclaration(dictionary, shorthand_id, property_value); + + return false; +} + +bool PropertySpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, PropertyId property_id, const String& property_value) const +{ + // Parse as a single property. + const PropertyDefinition* property_definition = GetProperty(property_id); + if (!property_definition) + return false; + + StringList property_values; + if (!ParsePropertyValues(property_values, property_value, false) || property_values.size() == 0) + return false; + + Property new_property; + if (!property_definition->ParseValue(new_property, property_values[0])) + return false; + + dictionary.SetProperty(property_id, new_property); + return true; +} + +// Parses a property declaration, setting any parsed and validated properties on the given dictionary. +bool PropertySpecification::ParseShorthandDeclaration(PropertyDictionary& dictionary, ShorthandId shorthand_id, const String& property_value) const +{ + StringList property_values; + if (!ParsePropertyValues(property_values, property_value, true) || property_values.size() == 0) + return false; + + // Parse as a shorthand. + const ShorthandDefinition* shorthand_definition = GetShorthand(shorthand_id); + if (!shorthand_definition) + return false; + + // If this definition is a 'box'-style shorthand (x-top, x-right, x-bottom, x-left, etc) and there are fewer + // than four values + if (shorthand_definition->type == ShorthandType::Box && + property_values.size() < 4) + { + // This array tells which property index each side is parsed from + Array box_side_to_value_index = { 0,0,0,0 }; + switch (property_values.size()) + { + case 1: + // Only one value is defined, so it is parsed onto all four sides. + box_side_to_value_index = { 0,0,0,0 }; + break; + case 2: + // Two values are defined, so the first one is parsed onto the top and bottom value, the second onto + // the left and right. + box_side_to_value_index = { 0,1,0,1 }; + break; + case 3: + // Three values are defined, so the first is parsed into the top value, the second onto the left and + // right, and the third onto the bottom. + box_side_to_value_index = { 0,1,2,1 }; + break; + default: + RMLUI_ERROR; + break; + } + + for (int i = 0; i < 4; i++) + { + RMLUI_ASSERT(shorthand_definition->items[i].type == ShorthandItemType::Property); + Property new_property; + int value_index = box_side_to_value_index[i]; + if (!shorthand_definition->items[i].property_definition->ParseValue(new_property, property_values[value_index])) + return false; + + dictionary.SetProperty(shorthand_definition->items[i].property_definition->GetId(), new_property); + } + } + else if (shorthand_definition->type == ShorthandType::RecursiveRepeat) + { + bool result = true; + + for (size_t i = 0; i < shorthand_definition->items.size(); i++) + { + const ShorthandItem& item = shorthand_definition->items[i]; + if (item.type == ShorthandItemType::Property) + result &= ParsePropertyDeclaration(dictionary, item.property_id, property_value); + else if (item.type == ShorthandItemType::Shorthand) + result &= ParseShorthandDeclaration(dictionary, item.shorthand_id, property_value); + else + result = false; + } + + if (!result) + return false; + } + else if (shorthand_definition->type == ShorthandType::RecursiveCommaSeparated) + { + StringList subvalues; + StringUtilities::ExpandString(subvalues, property_value); + + size_t num_optional = 0; + for (auto& item : shorthand_definition->items) + if (item.optional) + num_optional += 1; + + if (subvalues.size() + num_optional < shorthand_definition->items.size()) + { + // Not enough subvalues declared. + return false; + } + + size_t subvalue_i = 0; + for (size_t i = 0; i < shorthand_definition->items.size() && subvalue_i < subvalues.size(); i++) + { + bool result = false; + + const ShorthandItem& item = shorthand_definition->items[i]; + if (item.type == ShorthandItemType::Property) + result = ParsePropertyDeclaration(dictionary, item.property_id, subvalues[subvalue_i]); + else if (item.type == ShorthandItemType::Shorthand) + result = ParseShorthandDeclaration(dictionary, item.shorthand_id, subvalues[subvalue_i]); + + if (result) + subvalue_i += 1; + else if (!item.optional) + return false; + } + } + else + { + size_t value_index = 0; + size_t property_index = 0; + + for (; value_index < property_values.size() && property_index < shorthand_definition->items.size(); property_index++) + { + Property new_property; + + if (!shorthand_definition->items[property_index].property_definition->ParseValue(new_property, property_values[value_index])) + { + // This definition failed to parse; if we're falling through, try the next property. If there is no + // next property, then abort! + if (shorthand_definition->type == ShorthandType::FallThrough) + { + if (property_index + 1 < shorthand_definition->items.size()) + continue; + } + return false; + } + + dictionary.SetProperty(shorthand_definition->items[property_index].property_id, new_property); + + // Increment the value index, unless we're replicating the last value and we're up to the last value. + if (shorthand_definition->type != ShorthandType::Replicate || + value_index < property_values.size() - 1) + value_index++; + } + } + + return true; +} + +// Sets all undefined properties in the dictionary to their defaults. +void PropertySpecification::SetPropertyDefaults(PropertyDictionary& dictionary) const +{ + for (const auto& property : properties) + { + if (property && dictionary.GetProperty(property->GetId()) == nullptr) + dictionary.SetProperty(property->GetId(), *property->GetDefaultValue()); + } +} + +String PropertySpecification::PropertiesToString(const PropertyDictionary& dictionary) const +{ + String result; + for (auto& pair : dictionary.GetProperties()) + { + result += property_map->GetName(pair.first) + ": " + pair.second.ToString() + '\n'; + } + return result; +} + + +bool PropertySpecification::ParsePropertyValues(StringList& values_list, const String& values, bool split_values) const +{ + String value; + + enum ParseState { VALUE, VALUE_PARENTHESIS, VALUE_QUOTE }; + ParseState state = VALUE; + int open_parentheses = 0; + + size_t character_index = 0; + char previous_character = 0; + while (character_index < values.size()) + { + char character = values[character_index]; + character_index++; + + switch (state) + { + case VALUE: + { + if (character == ';') + { + value = StringUtilities::StripWhitespace(value); + if (value.size() > 0) + { + values_list.push_back(value); + value.clear(); + } + } + else if (StringUtilities::IsWhitespace(character)) + { + if (split_values) + { + value = StringUtilities::StripWhitespace(value); + if (value.size() > 0) + { + values_list.push_back(value); + value.clear(); + } + } + else + value += character; + } + else if (character == '"') + { + if (split_values) + { + value = StringUtilities::StripWhitespace(value); + if (value.size() > 0) + { + values_list.push_back(value); + value.clear(); + } + state = VALUE_QUOTE; + } + else + { + value += ' '; + state = VALUE_QUOTE; + } + } + else if (character == '(') + { + open_parentheses = 1; + value += character; + state = VALUE_PARENTHESIS; + } + else + { + value += character; + } + } + break; + + case VALUE_PARENTHESIS: + { + if (previous_character == '/') + { + if (character == ')' || character == '(') + value += character; + else + { + value += '/'; + value += character; + } + } + else + { + if (character == '(') + { + open_parentheses++; + value += character; + } + else if (character == ')') + { + open_parentheses--; + value += character; + if (open_parentheses == 0) + state = VALUE; + } + else if (character != '/') + { + value += character; + } + } + } + break; + + case VALUE_QUOTE: + { + if (previous_character == '/') + { + if (character == '"') + value += character; + else + { + value += '/'; + value += character; + } + } + else + { + if (character == '"') + { + if (split_values) + { + value = StringUtilities::StripWhitespace(value); + if (value.size() > 0) + { + values_list.push_back(value); + value.clear(); + } + } + else + value += ' '; + state = VALUE; + } + else if (character != '/') + { + value += character; + } + } + } + } + + previous_character = character; + } + + if (state == VALUE) + { + value = StringUtilities::StripWhitespace(value); + if (value.size() > 0) + values_list.push_back(value); + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/RenderInterface.cpp b/thirdparty/RmlUi/Source/Core/RenderInterface.cpp new file mode 100644 index 000000000..001d3fe5a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/RenderInterface.cpp @@ -0,0 +1,88 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/RenderInterface.h" +#include "TextureDatabase.h" + +namespace Rml { + +RenderInterface::RenderInterface() +{ + context = nullptr; +} + +RenderInterface::~RenderInterface() +{ + TextureDatabase::ReleaseTextures(this); +} + +// Called by RmlUi when it wants to compile geometry it believes will be static for the forseeable future. +CompiledGeometryHandle RenderInterface::CompileGeometry(Vertex* /*vertices*/, int /*num_vertices*/, int* /*indices*/, int /*num_indices*/, TextureHandle /*texture*/) +{ + return 0; +} + +// Called by RmlUi when it wants to render application-compiled geometry. +void RenderInterface::RenderCompiledGeometry(CompiledGeometryHandle /*geometry*/, const Vector2f& /*translation*/) +{ +} + +// Called by RmlUi when it wants to release application-compiled geometry. +void RenderInterface::ReleaseCompiledGeometry(CompiledGeometryHandle /*geometry*/) +{ +} + +// Called by RmlUi when a texture is required by the library. +bool RenderInterface::LoadTexture(TextureHandle& /*texture_handle*/, Vector2i& /*texture_dimensions*/, const String& /*source*/) +{ + return false; +} + +// Called by RmlUi when a texture is required to be built from an internally-generated sequence of pixels. +bool RenderInterface::GenerateTexture(TextureHandle& /*texture_handle*/, const byte* /*source*/, const Vector2i& /*source_dimensions*/) +{ + return false; +} + +// Called by RmlUi when a loaded texture is no longer required. +void RenderInterface::ReleaseTexture(TextureHandle /*texture*/) +{ +} + +// Called by RmlUi when it wants to change the current transform matrix to a new matrix. +void RenderInterface::SetTransform(const Matrix4f* /*transform*/) +{ +} + +// Get the context currently being rendered. +Context* RenderInterface::GetContext() const +{ + return context; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Spritesheet.cpp b/thirdparty/RmlUi/Source/Core/Spritesheet.cpp new file mode 100644 index 000000000..9299df46e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Spritesheet.cpp @@ -0,0 +1,155 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2019 Michael R. P. Ragazzon + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Spritesheet.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/Log.h" + +namespace Rml { + +bool SpritesheetList::AddSpriteSheet(const String& name, const String& image_source, const String& definition_source, int definition_line_number, const SpriteDefinitionList& sprite_definitions) +{ + // Load the texture + Texture texture; + texture.Set(image_source, definition_source); + + auto sprite_sheet = MakeShared(name, image_source, definition_source, definition_line_number, texture); + auto result = spritesheet_map.emplace(name, sprite_sheet); + if (!result.second) + { + Log::Message(Log::LT_WARNING, "Spritesheet '%s' has the same name as another spritesheet, ignored. See %s:%d", name.c_str(), definition_source.c_str(), definition_line_number); + return false; + } + + StringList& sprite_names = sprite_sheet->sprite_names; + + // Insert all the sprites with names not already defined in the global sprite list. + for (auto& sprite_definition : sprite_definitions) + { + const String& sprite_name = sprite_definition.first; + const Rectangle& sprite_rectangle = sprite_definition.second; + auto sprite_result = sprite_map.emplace(sprite_name, Sprite{ sprite_rectangle, sprite_sheet.get() }); + if (sprite_result.second) + { + sprite_names.push_back(sprite_name); + } + else + { + Log::Message(Log::LT_WARNING, "Sprite '%s' has the same name as an existing sprite, skipped. See %s:%d", sprite_name.c_str(), definition_source.c_str(), definition_line_number); + } + } + + return true; +} + + + +const Sprite* SpritesheetList::GetSprite(const String& name) const +{ + auto it = sprite_map.find(name); + if (it != sprite_map.end()) + return &it->second; + return nullptr; +} + + +void SpritesheetList::Merge(const SpritesheetList& other) +{ + for (auto& pair : other.spritesheet_map) + { + auto sheet_result = spritesheet_map.emplace(pair); + const String& sheet_name = sheet_result.first->first; + const Spritesheet& sheet = *sheet_result.first->second; + bool sheet_inserted = sheet_result.second; + + if (sheet_inserted) + { + // The sprite sheet was succesfully added, now try to add each sprite to the global list. + for (const String& sprite_name : sheet.sprite_names) + { + // Lookup the sprite in the other map. + auto it_sprite = other.sprite_map.find(sprite_name); + if (it_sprite != other.sprite_map.end()) + { + // Add the sprite into our map. Each sprite name must be unique. + auto sprite_result = sprite_map.emplace(sprite_name, it_sprite->second); + bool inserted = sprite_result.second; + + if (!inserted) + { + Log::Message(Log::LT_WARNING, "Duplicate sprite name '%s' found while merging style sheets, defined in %s:%d.", sprite_name.c_str(), sheet.definition_source.c_str(), sheet.definition_line_number); + } + } + else + { + RMLUI_ERRORMSG("Something went wrong while merging style sheets."); + } + } + } + else + { + Log::Message(Log::LT_WARNING, "Duplicate sprite sheet name '%s' found while merging style sheets, defined in %s:%d.", sheet_name.c_str(), sheet.definition_source.c_str(), sheet.definition_line_number); + } + } +} + +void SpritesheetList::Reserve(size_t size_sprite_sheets, size_t size_sprites) +{ + spritesheet_map.reserve(size_sprite_sheets); + sprite_map.reserve(size_sprites); +} + +size_t SpritesheetList::NumSpriteSheets() const +{ + return spritesheet_map.size(); +} + +size_t SpritesheetList::NumSprites() const +{ + return sprite_map.size(); +} + +String SpritesheetList::ToString() const +{ + String result = CreateString(100, "#SpriteSheets: %d\n", spritesheet_map.size()); + + for (auto& sheet : spritesheet_map) + { + result += CreateString(100, " Sheet '%s'. #Sprites %d.\n", sheet.first.c_str(), sheet.second->sprite_names.size()); + } + + result += CreateString(100, "\n#Sprites: %d\n", sprite_map.size()); + for (auto& sprite : sprite_map) + { + result += CreateString(100, " In '%s': %s\n", sprite.second.sprite_sheet->name.c_str(), sprite.first.c_str()); + } + + return result; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Stream.cpp b/thirdparty/RmlUi/Source/Core/Stream.cpp new file mode 100644 index 000000000..3287ab03d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Stream.cpp @@ -0,0 +1,162 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Stream.h" +#include +#include + +namespace Rml { + +const size_t READ_BLOCK_SIZE = 1024; + +Stream::Stream() +{ + stream_mode = 0; +} + +Stream::~Stream() +{ + Close(); +} + +void Stream::Close() +{ + stream_mode = 0; +} + +// Returns the mode the stream was opened in. +int Stream::GetStreamMode() const +{ + return stream_mode; +} + +// Returns the source url (if available) +const URL& Stream::GetSourceURL() const +{ + return url; +} + +bool Stream::IsEOS() const +{ + return Tell() >= Length(); +} + +size_t Stream::Peek(void* buffer, size_t bytes) const +{ + size_t pos = Tell(); + size_t read = Read( buffer, bytes ); + Seek( (long)pos, SEEK_SET ); + return read; +} + +// Read from one stream into another +size_t Stream::Read(Stream* stream, size_t bytes) const +{ + byte buffer[ READ_BLOCK_SIZE ]; + size_t total_bytes_read = 0; + while (total_bytes_read < bytes) + { + size_t bytes_read = this->Read(buffer, Math::Min(READ_BLOCK_SIZE, bytes - total_bytes_read)); + if (bytes_read < 1) + return total_bytes_read; + stream->Write(buffer, bytes_read); + total_bytes_read += bytes_read; + } + return total_bytes_read; +} + +// Read from one stream into another +size_t Stream::Read(String& string, size_t bytes) const +{ + size_t string_size = string.size(); + string.resize(string_size + bytes + 1); + size_t read = Read(&string[string_size], bytes); + string[string_size + read] = '\0'; + string.resize(string_size + read); + return read; +} + +/// Write to this stream from another stream +size_t Stream::Write(const Stream* stream, size_t bytes) +{ + return stream->Read(this, bytes); +} + +size_t Stream::Write(const char* string) +{ + return Write(string, strlen(string)); +} + +size_t Stream::Write(const String& string) +{ + return Write(string.c_str(), string.size()); +} + +// Push onto the front of the stream +size_t Stream::PushFront(const void* RMLUI_UNUSED_PARAMETER(buffer), size_t RMLUI_UNUSED_PARAMETER(bytes)) +{ + RMLUI_UNUSED(buffer); + RMLUI_UNUSED(bytes); + + RMLUI_ERRORMSG("No generic way to PushFront to a stream."); + return false; +} + +// Push onto the back of the stream +size_t Stream::PushBack(const void* buffer, size_t bytes) +{ + size_t pos = Tell(); + Seek(0, SEEK_END); + size_t wrote = Write(buffer, bytes); + Seek((long)pos, SEEK_SET); + return wrote; +} + +// Push onto the front of the stream +size_t Stream::PopFront(size_t RMLUI_UNUSED_PARAMETER(bytes)) +{ + RMLUI_UNUSED(bytes); + + RMLUI_ERRORMSG("No generic way to PopFront from a stream."); + return 0; +} + +// Push onto the back of the stream +size_t Stream::PopBack(size_t bytes) +{ + return Truncate(Length() - bytes); +} + +// Sets the mode on the stream; should be called by a stream when it is opened. +void Stream::SetStreamDetails(const URL& _url, int _stream_mode) +{ + url = _url; + stream_mode = _stream_mode; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StreamFile.cpp b/thirdparty/RmlUi/Source/Core/StreamFile.cpp new file mode 100644 index 000000000..926a8b597 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StreamFile.cpp @@ -0,0 +1,143 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StreamFile.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/FileInterface.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" + +namespace Rml { + +StreamFile::StreamFile() +{ + file_handle = 0; + length = 0; +} + +StreamFile::~StreamFile() +{ + if (file_handle) + Close(); +} + +/// Attempts to open the stream pointing at a given URL. +bool StreamFile::Open(const String& path) +{ + String url_safe_path = StringUtilities::Replace(path, ':', '|'); + SetStreamDetails(URL(url_safe_path), Stream::MODE_READ); + + if (file_handle) + Close(); + + // Fix the path if a leading colon has been replaced with a pipe. + String fixed_path = StringUtilities::Replace(path, '|', ':'); + file_handle = GetFileInterface()->Open(fixed_path); + if (!file_handle) + { + Log::Message(Log::LT_WARNING, "Unable to open file %s.", fixed_path.c_str()); + return false; + } + + GetLength(); + + return true; +} + +// Closes the stream. +void StreamFile::Close() +{ + if (file_handle) + { + GetFileInterface()->Close(file_handle); + file_handle = 0; + } + + length = 0; +} + +/// Returns the size of this stream (in bytes). +size_t StreamFile::Length() const +{ + return length; +} + +// Returns the position of the stream pointer (in bytes). +size_t StreamFile::Tell() const +{ + return GetFileInterface()->Tell(file_handle); +} + +// Sets the stream position (in bytes). +bool StreamFile::Seek(long offset, int origin) const +{ + return GetFileInterface()->Seek(file_handle, offset, origin); +} + +// Read from the stream. +size_t StreamFile::Read(void* buffer, size_t bytes) const +{ + return GetFileInterface()->Read(buffer, bytes, file_handle); +} + +// Write to the stream at the current position. +size_t StreamFile::Write(const void* RMLUI_UNUSED_PARAMETER(buffer), size_t RMLUI_UNUSED_PARAMETER(bytes)) +{ + RMLUI_UNUSED(buffer); + RMLUI_UNUSED(bytes); + + RMLUI_ERROR; + return 0; +} + +// Truncate the stream to the specified length. +size_t StreamFile::Truncate(size_t RMLUI_UNUSED_PARAMETER(bytes)) +{ + RMLUI_UNUSED(bytes); + + RMLUI_ERROR; + return 0; +} + +// Returns true if the stream is ready for reading, false otherwise. +bool StreamFile::IsReadReady() +{ + return Tell() < Length(); +} + +// Returns true if the stream is ready for writing, false otherwise. +bool StreamFile::IsWriteReady() +{ + return false; +} +// Determines the length of the stream. +void StreamFile::GetLength() +{ + length = GetFileInterface()->Length(file_handle); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StreamFile.h b/thirdparty/RmlUi/Source/Core/StreamFile.h new file mode 100644 index 000000000..a2b9ace32 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StreamFile.h @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STREAMFILE_H +#define RMLUI_CORE_STREAMFILE_H + +#include "../../Include/RmlUi/Core/Stream.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +/** + @author Peter Curry + */ + +class StreamFile : public Stream +{ +public: + StreamFile(); + virtual ~StreamFile(); + + /// Attempts to open the stream pointing at a given location. + bool Open(const String& path); + /// Closes the stream. + void Close() override; + + /// Returns the size of this stream (in bytes). + size_t Length() const override; + + /// Returns the position of the stream pointer (in bytes). + size_t Tell() const override; + /// Sets the stream position (in bytes). + bool Seek(long offset, int origin) const override; + + /// Read from the stream. + size_t Read(void* buffer, size_t bytes) const override; + using Stream::Read; + + /// Write to the stream at the current position. + size_t Write(const void* buffer, size_t bytes) override; + using Stream::Write; + + /// Truncate the stream to the specified length. + size_t Truncate(size_t bytes) override; + + /// Returns true if the stream is ready for reading, false otherwise. + bool IsReadReady() override; + /// Returns false. + bool IsWriteReady() override; + +private: + // Determines the length of the stream. + void GetLength(); + + FileHandle file_handle; + size_t length; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StreamMemory.cpp b/thirdparty/RmlUi/Source/Core/StreamMemory.cpp new file mode 100644 index 000000000..e53bb8366 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StreamMemory.cpp @@ -0,0 +1,236 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include +#include + +namespace Rml { + +const int DEFAULT_BUFFER_SIZE = 256; +const int BUFFER_INCREMENTS = 256; + +StreamMemory::StreamMemory() +{ + buffer = nullptr; + buffer_ptr = nullptr; + buffer_size = 0; + buffer_used = 0; + owns_buffer = true; + Reallocate(DEFAULT_BUFFER_SIZE); +} + +StreamMemory::StreamMemory(size_t initial_size) +{ + buffer = nullptr; + buffer_ptr = nullptr; + buffer_size = 0; + buffer_used = 0; + owns_buffer = true; + Reallocate(initial_size); +} + +StreamMemory::StreamMemory(const byte* _buffer, size_t _buffer_size) +{ + buffer = (byte*)_buffer; + buffer_size = _buffer_size; + buffer_used = _buffer_size; + owns_buffer = false; + buffer_ptr = buffer; +} + +StreamMemory::~StreamMemory() +{ + if ( owns_buffer ) + free( buffer ); +} + +void StreamMemory::Close() +{ + Stream::Close(); +} + +bool StreamMemory::IsEOS() const +{ + return buffer_ptr >= buffer + buffer_used; +} + +// Get current offset +size_t StreamMemory::Tell() const +{ + return buffer_ptr - buffer; +} + +size_t StreamMemory::Length() const +{ + return buffer_used; +} + +// Read bytes from the buffer, advancing the internal pointer +size_t StreamMemory::Read(void *_buffer, size_t bytes) const +{ + bytes = Math::ClampUpper(bytes, (size_t) (buffer + buffer_used - buffer_ptr)); + + memcpy(_buffer, buffer_ptr, bytes); + + buffer_ptr += bytes; + + return bytes; +} + +// Read bytes from the buffer, not advancing the internal pointer +size_t StreamMemory::Peek( void *_buffer, size_t bytes ) const +{ + bytes = Math::ClampUpper(bytes, (size_t) (buffer + buffer_used - buffer_ptr)); + + memcpy(_buffer, buffer_ptr, bytes); + + return bytes; +} + +// Read bytes from the buffer, advancing the internal pointer +size_t StreamMemory::Write( const void *_buffer, size_t bytes ) +{ + if ( buffer_ptr + bytes > buffer + buffer_size ) + if ( !Reallocate( bytes + BUFFER_INCREMENTS ) ) + return 0; + + memcpy( buffer_ptr, _buffer, bytes ); + + buffer_ptr += bytes; + buffer_used = Math::Max( (size_t)(buffer_ptr - buffer), buffer_used ); + + return bytes; +} + +// Truncate the stream to the specified length +size_t StreamMemory::Truncate( size_t bytes ) +{ + if ( bytes > buffer_used ) + return 0; + + size_t old_size = buffer_used; + buffer_used = bytes; + buffer_ptr = buffer + bytes; + return old_size - buffer_used; +} + +// Set pointer to the specified offset +bool StreamMemory::Seek( long offset, int origin ) const +{ + byte* new_ptr = nullptr; + + switch ( origin ) + { + case SEEK_SET: + new_ptr = buffer + offset; + break; + case SEEK_END: + new_ptr = buffer + ( buffer_used - offset ); + break; + case SEEK_CUR: + new_ptr = buffer_ptr + offset; + } + + // Check of overruns + if ( new_ptr < buffer || new_ptr > buffer + buffer_used ) + return false; + + buffer_ptr = new_ptr; + + return true; +} + +size_t StreamMemory::PushFront( const void* _buffer, size_t bytes ) +{ + if ( buffer_used + bytes > buffer_size ) + if ( !Reallocate( bytes + BUFFER_INCREMENTS ) ) + return 0; + + memmove( &buffer[ bytes ], &buffer[ 0 ], buffer_used ); + memcpy( buffer, _buffer, bytes ); + buffer_used += bytes; + buffer_ptr += bytes; + return bytes; +} + +size_t StreamMemory::PopFront( size_t bytes ) +{ + Erase( 0, bytes ); + buffer_ptr -= bytes; + buffer_ptr = Math::ClampLower(buffer_ptr, buffer); + return bytes; +} + +const byte* StreamMemory::RawStream() const +{ + return buffer; +} + +void StreamMemory::Erase( size_t offset, size_t bytes ) +{ + bytes = Math::ClampUpper(bytes, buffer_used - offset); + memmove(&buffer[offset], &buffer[offset + bytes], buffer_used - offset - bytes); + buffer_used -= bytes; +} + +bool StreamMemory::IsReadReady() +{ + return !IsEOS(); +} + +bool StreamMemory::IsWriteReady() +{ + return true; +} + +void StreamMemory::SetSourceURL(const URL& url) +{ + SetStreamDetails(url, Stream::MODE_READ | (owns_buffer ? Stream::MODE_WRITE : 0)); +} + +// Resize the buffer +bool StreamMemory::Reallocate( size_t size ) +{ + RMLUI_ASSERT( owns_buffer ); + if ( !owns_buffer ) + return false; + + byte *new_buffer = (byte*)realloc( buffer, buffer_size + size ); + if ( new_buffer == nullptr ) + return false; + + buffer_ptr = new_buffer + ( buffer_ptr - buffer ); + + buffer = new_buffer; + buffer_size += size; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StringUtilities.cpp b/thirdparty/RmlUi/Source/Core/StringUtilities.cpp new file mode 100644 index 000000000..08dc0a879 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StringUtilities.cpp @@ -0,0 +1,607 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/Log.h" +#include +#include +#include +#include + +namespace Rml { + +static int FormatString(String& string, size_t max_size, const char* format, va_list argument_list) +{ + const int INTERNAL_BUFFER_SIZE = 1024; + static char buffer[INTERNAL_BUFFER_SIZE]; + char* buffer_ptr = buffer; + + if (max_size + 1 > INTERNAL_BUFFER_SIZE) + buffer_ptr = new char[max_size + 1]; + + int length = vsnprintf(buffer_ptr, max_size, format, argument_list); + buffer_ptr[length >= 0 ? length : max_size] = '\0'; +#ifdef RMLUI_DEBUG + if (length == -1) + { + Log::Message(Log::LT_WARNING, "FormatString: String truncated to %d bytes when processing %s", max_size, format); + } +#endif + + string = buffer_ptr; + + if (buffer_ptr != buffer) + delete[] buffer_ptr; + + return length; +} + +int FormatString(String& string, size_t max_size, const char* format, ...) +{ + va_list argument_list; + va_start(argument_list, format); + int result = FormatString(string, (int)max_size, format, argument_list); + va_end(argument_list); + return result; +} +String CreateString(size_t max_size, const char* format, ...) +{ + String result; + result.reserve(max_size); + va_list argument_list; + va_start(argument_list, format); + FormatString(result, max_size, format, argument_list); + va_end(argument_list); + return result; +} + +static inline char CharToLower(char c) { + if (c >= 'A' && c <= 'Z') + c += char('a' - 'A'); + return c; +} + +String StringUtilities::ToLower(const String& string) { + String str_lower = string; + std::transform(str_lower.begin(), str_lower.end(), str_lower.begin(), &CharToLower); + return str_lower; +} + +String StringUtilities::ToUpper(const String& string) +{ + String str_upper = string; + std::transform(str_upper.begin(), str_upper.end(), str_upper.begin(), [](char c) { + if (c >= 'a' && c <= 'z') + c -= char('a' - 'A'); + return c; + } + ); + return str_upper; +} + +RMLUICORE_API String StringUtilities::EncodeRml(const String& string) +{ + String result; + result.reserve(string.size()); + for (char c : string) + { + switch (c) + { + case '<': result += "<"; break; + case '>': result += ">"; break; + case '&': result += "&"; break; + case '"': result += """; break; + default: result += c; break; + } + } + return result; +} + +String StringUtilities::Replace(String subject, const String& search, const String& replace) +{ + size_t pos = 0; + while ((pos = subject.find(search, pos)) != String::npos) { + subject.replace(pos, search.length(), replace); + pos += replace.length(); + } + return subject; +} + +String StringUtilities::Replace(String subject, char search, char replace) +{ + const size_t size = subject.size(); + for (size_t i = 0; i < size; i++) + { + if (subject[i] == search) + subject[i] = replace; + } + return subject; +} + + +// Expands character-delimited list of values in a single string to a whitespace-trimmed list of values. +void StringUtilities::ExpandString(StringList& string_list, const String& string, const char delimiter) +{ + char quote = 0; + bool last_char_delimiter = true; + const char* ptr = string.c_str(); + const char* start_ptr = nullptr; + const char* end_ptr = ptr; + + size_t num_delimiter_values = std::count(string.begin(), string.end(), delimiter); + if (num_delimiter_values == 0) + { + string_list.push_back(StripWhitespace(string)); + return; + } + string_list.reserve(string_list.size() + num_delimiter_values + 1); + + while (*ptr) + { + // Switch into quote mode if the last char was a delimeter ( excluding whitespace ) + // and we're not already in quote mode + if (last_char_delimiter && !quote && (*ptr == '"' || *ptr == '\'')) + { + quote = *ptr; + } + // Switch out of quote mode if we encounter a quote that hasn't been escaped + else if (*ptr == quote && *(ptr-1) != '\\') + { + quote = 0; + } + // If we encounter a delimiter while not in quote mode, add the item to the list + else if (*ptr == delimiter && !quote) + { + if (start_ptr) + string_list.emplace_back(start_ptr, end_ptr + 1); + else + string_list.emplace_back(); + last_char_delimiter = true; + start_ptr = nullptr; + } + // Otherwise if its not white space or we're in quote mode, advance the pointers + else if (!IsWhitespace(*ptr) || quote) + { + if (!start_ptr) + start_ptr = ptr; + end_ptr = ptr; + last_char_delimiter = false; + } + + ptr++; + } + + // If there's data pending, add it. + if (start_ptr) + string_list.emplace_back(start_ptr, end_ptr + 1); +} + + +void StringUtilities::ExpandString(StringList& string_list, const String& string, const char delimiter, char quote_character, char unquote_character, bool ignore_repeated_delimiters) +{ + int quote_mode_depth = 0; + const char* ptr = string.c_str(); + const char* start_ptr = nullptr; + const char* end_ptr = ptr; + + while (*ptr) + { + // Increment the quote depth for each quote character encountered + if (*ptr == quote_character) + { + ++quote_mode_depth; + } + // And decrement it for every unquote character + else if (*ptr == unquote_character) + { + --quote_mode_depth; + } + + // If we encounter a delimiter while not in quote mode, add the item to the list + if (*ptr == delimiter && quote_mode_depth == 0) + { + if (start_ptr) + string_list.emplace_back(start_ptr, end_ptr + 1); + else if(!ignore_repeated_delimiters) + string_list.emplace_back(); + start_ptr = nullptr; + } + // Otherwise if its not white space or we're in quote mode, advance the pointers + else if (!IsWhitespace(*ptr) || quote_mode_depth > 0) + { + if (!start_ptr) + start_ptr = ptr; + end_ptr = ptr; + } + + ptr++; + } + + // If there's data pending, add it. + if (start_ptr) + string_list.emplace_back(start_ptr, end_ptr + 1); +} + +// Joins a list of string values into a single string separated by a character delimiter. +void StringUtilities::JoinString(String& string, const StringList& string_list, const char delimiter) +{ + for (size_t i = 0; i < string_list.size(); i++) + { + string += string_list[i]; + if (delimiter != '\0' && i < string_list.size() - 1) + string += delimiter; + } +} + +String StringUtilities::StripWhitespace(const String& string) +{ + return StripWhitespace(StringView(string)); +} + +RMLUICORE_API String StringUtilities::StripWhitespace(StringView string) +{ + const char* start = string.begin(); + const char* end = string.end(); + + while (start < end && IsWhitespace(*start)) + start++; + + while (end > start&& IsWhitespace(*(end - 1))) + end--; + + if (start < end) + return String(start, end); + + return String(); +} + +void StringUtilities::TrimTrailingDotZeros(String& string) +{ + RMLUI_ASSERTMSG(string.find('.') != String::npos, "This function probably does not do what you want if the string is not a number with a decimal point.") + + size_t new_size = string.size(); + for (size_t i = string.size() - 1; i < string.size(); i--) + { + if (string[i] == '.') + { + new_size = i; + break; + } + else if (string[i] == '0') + new_size = i; + else + break; + } + + if (new_size < string.size()) + string.resize(new_size); +} + +#ifdef RMLUI_DEBUG +static struct TestTrimTrailingDotZeros { + TestTrimTrailingDotZeros() { + auto test = [](const String test_string, const String expected) { + String result = test_string; + StringUtilities::TrimTrailingDotZeros(result); + RMLUI_ASSERT(result == expected); + }; + + test("0.1", "0.1"); + test("0.10", "0.1"); + test("0.1000", "0.1"); + test("0.01", "0.01"); + test("0.", "0"); + test("5.", "5"); + test("5.5", "5.5"); + test("5.50", "5.5"); + test("5.501", "5.501"); + test("10.0", "10"); + test("11.0", "11"); + + // Some test cases for behavior that are probably not what you want. + //test("test0", "test"); + //test("1000", "1"); + //test(".", ""); + //test("0", ""); + //test(".0", ""); + //test(" 11 2121 3.00", " 11 2121 3"); + //test("11", "11"); + } +} test_trim_trailing_dot_zeros; +#endif + +bool StringUtilities::StringCompareCaseInsensitive(const StringView lhs, const StringView rhs) +{ + if (lhs.size() != rhs.size()) + return false; + + const char* left = lhs.begin(); + const char* right = rhs.begin(); + const char* const left_end = lhs.end(); + + for (; left != left_end; ++left, ++right) + { + if (CharToLower(*left) != CharToLower(*right)) + return false; + } + + return true; +} + +Character StringUtilities::ToCharacter(const char* p) +{ + if ((*p & (1 << 7)) == 0) + return static_cast(*p); + + int num_bytes = 0; + int code = 0; + + if ((*p & 0b1110'0000) == 0b1100'0000) + { + num_bytes = 2; + code = (*p & 0b0001'1111); + } + else if ((*p & 0b1111'0000) == 0b1110'0000) + { + num_bytes = 3; + code = (*p & 0b0000'1111); + } + else if ((*p & 0b1111'1000) == 0b1111'0000) + { + num_bytes = 4; + code = (*p & 0b0000'0111); + } + else + { + // Invalid begin byte + return Character::Null; + } + + for (int i = 1; i < num_bytes; i++) + { + const char byte = *(p + i); + if ((byte & 0b1100'0000) != 0b1000'0000) + { + // Invalid continuation byte + ++p; + return Character::Null; + } + + code = ((code << 6) | (byte & 0b0011'1111)); + } + + return static_cast(code); +} + +String StringUtilities::ToUTF8(Character character) +{ + return ToUTF8(&character, 1); +} + +String StringUtilities::ToUTF8(const Character* characters, int num_characters) +{ + String result; + result.reserve(num_characters); + + bool invalid_character = false; + + for (int i = 0; i < num_characters; i++) + { + char32_t c = (char32_t)characters[i]; + + constexpr int l3 = 0b0000'0111; + constexpr int l4 = 0b0000'1111; + constexpr int l5 = 0b0001'1111; + constexpr int l6 = 0b0011'1111; + constexpr int h1 = 0b1000'0000; + constexpr int h2 = 0b1100'0000; + constexpr int h3 = 0b1110'0000; + constexpr int h4 = 0b1111'0000; + + if (c < 0x80) + result += (char)c; + else if (c < 0x800) + result += { char(((c >> 6) & l5) | h2), char((c & l6) | h1) }; + else if (c < 0x10000) + result += { char(((c >> 12) & l4) | h3), char(((c >> 6) & l6) | h1), char((c & l6) | h1) }; + else if (c <= 0x10FFFF) + result += { char(((c >> 18) & l3) | h4), char(((c >> 12) & l6) | h1), char(((c >> 6) & l6) | h1), char((c & l6) | h1) }; + else + invalid_character = true; + } + + if (invalid_character) + Log::Message(Log::LT_WARNING, "One or more invalid code points encountered while encoding to UTF-8."); + + return result; +} + + +size_t StringUtilities::LengthUTF8(StringView string_view) +{ + const char* const p_end = string_view.end(); + + // Skip any continuation bytes at the beginning + const char* p = string_view.begin(); + + size_t num_continuation_bytes = 0; + + while (p != p_end) + { + if ((*p & 0b1100'0000) == 0b1000'0000) + ++num_continuation_bytes; + ++p; + } + + return string_view.size() - num_continuation_bytes; +} + +U16String StringUtilities::ToUTF16(const String& input) +{ + U16String result; + + if (input.empty()) + return result; + + Vector characters; + characters.reserve(input.size()); + + for (auto it = StringIteratorU8(input); it; ++it) + characters.push_back(*it); + + result.reserve(input.size()); + + bool valid_characters = true; + + for (Character character : characters) + { + char32_t c = (char32_t)character; + + if (c <= 0xD7FF || (c >= 0xE000 && c <= 0xFFFF)) + { + // Single 16-bit code unit. + result += (char16_t)c; + } + else if (c >= 0x10000 && c <= 0x10FFFF) + { + // Encode as two 16-bit code units. + char32_t c_shift = c - 0x10000; + char16_t w1 = (0xD800 | ((c_shift >> 10) & 0x3FF)); + char16_t w2 = (0xDC00 | (c_shift & 0x3FF)); + result += {w1, w2}; + } + else + { + valid_characters = false; + } + } + + if (!valid_characters) + Log::Message(Log::LT_WARNING, "Invalid characters encountered while converting UTF-8 string to UTF-16."); + + return result; +} + +String StringUtilities::ToUTF8(const U16String& input) +{ + Vector characters; + characters.reserve(input.size()); + + bool valid_input = true; + char16_t w1 = 0; + + for (char16_t w : input) + { + if (w <= 0xD7FF || w >= 0xE000) + { + // Single 16-bit code unit. + characters.push_back((Character)(w)); + } + else + { + // Two 16-bit code units. + if (!w1 && w < 0xDC00) + { + w1 = w; + } + else if (w1 && w >= 0xDC00) + { + characters.push_back((Character)(((((char32_t)w1 & 0x3FF) << 10) | ((char32_t)(w) & 0x3FF)) + 0x10000u)); + w1 = 0; + } + else + { + valid_input = false; + } + } + } + + String result; + + if (characters.size() > 0) + result = StringUtilities::ToUTF8(characters.data(), (int)characters.size()); + + if (!valid_input) + Log::Message(Log::LT_WARNING, "Invalid characters encountered while converting UTF-16 string to UTF-8."); + + return result; +} + + +StringView::StringView() +{ + const char* empty_string = ""; + p_begin = empty_string; + p_end = empty_string; +} + +StringView::StringView(const char* p_begin, const char* p_end) : p_begin(p_begin), p_end(p_end) +{ + RMLUI_ASSERT(p_end >= p_begin); +} +StringView::StringView(const String& string) : p_begin(string.data()), p_end(string.data() + string.size()) +{} +StringView::StringView(const String& string, size_t offset) : p_begin(string.data() + offset), p_end(string.data() + string.size()) +{} +StringView::StringView(const String& string, size_t offset, size_t count) : p_begin(string.data() + offset), p_end(string.data() + std::min(offset + count, string.size())) +{} + +bool StringView::operator==(const StringView& other) const { + return size() == other.size() && strncmp(p_begin, other.p_begin, size()) == 0; +} + + +StringIteratorU8::StringIteratorU8(const char* p_begin, const char* p, const char* p_end) : view(p_begin, p_end), p(p) +{} +StringIteratorU8::StringIteratorU8(const String& string) : view(string), p(string.data()) +{} +StringIteratorU8::StringIteratorU8(const String& string, size_t offset) : view(string), p(string.data() + offset) +{} +StringIteratorU8::StringIteratorU8(const String& string, size_t offset, size_t count) : view(string, 0, offset + count), p(string.data() + offset) +{} +StringIteratorU8& StringIteratorU8::operator++() { + RMLUI_ASSERT(p < view.end()); + ++p; + SeekForward(); + return *this; +} +StringIteratorU8& StringIteratorU8::operator--() { + RMLUI_ASSERT(p >= view.begin()); + --p; + SeekBack(); + return *this; +} +inline void StringIteratorU8::SeekBack() { + p = StringUtilities::SeekBackwardUTF8(p, view.begin()); +} + +inline void StringIteratorU8::SeekForward() { + p = StringUtilities::SeekForwardUTF8(p, view.end()); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheet.cpp b/thirdparty/RmlUi/Source/Core/StyleSheet.cpp new file mode 100644 index 000000000..343d9a4c3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheet.cpp @@ -0,0 +1,399 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "ElementDefinition.h" +#include "StyleSheetFactory.h" +#include "StyleSheetNode.h" +#include "StyleSheetParser.h" +#include "Utilities.h" +#include "../../Include/RmlUi/Core/DecoratorInstancer.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/FontEffect.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/FontEffectInstancer.h" +#include + +namespace Rml { + +// Sorts style nodes based on specificity. +inline static bool StyleSheetNodeSort(const StyleSheetNode* lhs, const StyleSheetNode* rhs) +{ + return lhs->GetSpecificity() < rhs->GetSpecificity(); +} + +StyleSheet::StyleSheet() +{ + root = MakeUnique(); + specificity_offset = 0; +} + +StyleSheet::~StyleSheet() +{ +} + +bool StyleSheet::LoadStyleSheet(Stream* stream, int begin_line_number) +{ + StyleSheetParser parser; + specificity_offset = parser.Parse(root.get(), stream, *this, keyframes, decorator_map, spritesheet_list, begin_line_number); + return specificity_offset >= 0; +} + +/// Combines this style sheet with another one, producing a new sheet +SharedPtr StyleSheet::CombineStyleSheet(const StyleSheet& other_sheet) const +{ + RMLUI_ZoneScoped; + + SharedPtr new_sheet = MakeShared(); + if (!new_sheet->root->MergeHierarchy(root.get()) || + !new_sheet->root->MergeHierarchy(other_sheet.root.get(), specificity_offset)) + { + return nullptr; + } + + // Any matching @keyframe names are overridden as per CSS rules + new_sheet->keyframes.reserve(keyframes.size() + other_sheet.keyframes.size()); + new_sheet->keyframes = keyframes; + for (auto& other_keyframes : other_sheet.keyframes) + { + new_sheet->keyframes[other_keyframes.first] = other_keyframes.second; + } + + // Copy over the decorators, and replace any matching decorator names from other_sheet + new_sheet->decorator_map.reserve(decorator_map.size() + other_sheet.decorator_map.size()); + new_sheet->decorator_map = decorator_map; + for (auto& other_decorator: other_sheet.decorator_map) + { + new_sheet->decorator_map[other_decorator.first] = other_decorator.second; + } + + new_sheet->spritesheet_list.Reserve( + spritesheet_list.NumSpriteSheets() + other_sheet.spritesheet_list.NumSpriteSheets(), + spritesheet_list.NumSprites() + other_sheet.spritesheet_list.NumSprites() + ); + new_sheet->spritesheet_list = other_sheet.spritesheet_list; + new_sheet->spritesheet_list.Merge(spritesheet_list); + + new_sheet->specificity_offset = specificity_offset + other_sheet.specificity_offset; + return new_sheet; +} + +// Builds the node index for a combined style sheet. +void StyleSheet::BuildNodeIndexAndOptimizeProperties() +{ + RMLUI_ZoneScoped; + styled_node_index.clear(); + root->BuildIndexAndOptimizeProperties(styled_node_index, *this); + root->SetStructurallyVolatileRecursive(false); +} + +// Returns the Keyframes of the given name, or null if it does not exist. +Keyframes * StyleSheet::GetKeyframes(const String & name) +{ + auto it = keyframes.find(name); + if (it != keyframes.end()) + return &(it->second); + return nullptr; +} + +SharedPtr StyleSheet::GetDecorator(const String& name) const +{ + auto it = decorator_map.find(name); + if (it == decorator_map.end()) + return nullptr; + return it->second.decorator; +} + +const Sprite* StyleSheet::GetSprite(const String& name) const +{ + return spritesheet_list.GetSprite(name); +} + +DecoratorsPtr StyleSheet::InstanceDecoratorsFromString(const String& decorator_string_value, const SharedPtr& source) const +{ + // Decorators are declared as + // decorator: [, ...]; + // Where is either a @decorator name: + // decorator: invader-theme-background, ...; + // or is an anonymous decorator with inline properties + // decorator: tiled-box( ), ...; + + Decorators decorators; + if (decorator_string_value.empty() || decorator_string_value == "none") + return nullptr; + + const char* source_path = (source ? source->path.c_str() : ""); + const int source_line_number = (source ? source->line_number : 0); + + // Make sure we don't split inside the parenthesis since they may appear in decorator shorthands. + StringList decorator_string_list; + StringUtilities::ExpandString(decorator_string_list, decorator_string_value, ',', '(', ')'); + + decorators.value = decorator_string_value; + decorators.list.reserve(decorator_string_list.size()); + + // Get or instance each decorator in the comma-separated string list + for (const String& decorator_string : decorator_string_list) + { + const size_t shorthand_open = decorator_string.find('('); + const size_t shorthand_close = decorator_string.rfind(')'); + const bool invalid_parenthesis = (shorthand_open == String::npos || shorthand_close == String::npos || shorthand_open >= shorthand_close); + + if (invalid_parenthesis) + { + // We found no parenthesis, that means the value must be a name of a @decorator rule, look it up + SharedPtr decorator = GetDecorator(decorator_string); + if (decorator) + decorators.list.emplace_back(std::move(decorator)); + else + Log::Message(Log::LT_WARNING, "Decorator name '%s' could not be found in any @decorator rule, declared at %s:%d", decorator_string.c_str(), source_path, source_line_number); + } + else + { + // Since we have parentheses it must be an anonymous decorator with inline properties + const String type = StringUtilities::StripWhitespace(decorator_string.substr(0, shorthand_open)); + + // Check for valid decorator type + DecoratorInstancer* instancer = Factory::GetDecoratorInstancer(type); + if (!instancer) + { + Log::Message(Log::LT_WARNING, "Decorator type '%s' not found, declared at %s:%d", type.c_str(), source_path, source_line_number); + continue; + } + + const String shorthand = decorator_string.substr(shorthand_open + 1, shorthand_close - shorthand_open - 1); + const PropertySpecification& specification = instancer->GetPropertySpecification(); + + // Parse the shorthand properties given by the 'decorator' shorthand property + PropertyDictionary properties; + if (!specification.ParsePropertyDeclaration(properties, "decorator", shorthand)) + { + Log::Message(Log::LT_WARNING, "Could not parse decorator value '%s' at %s:%d", decorator_string.c_str(), source_path, source_line_number); + continue; + } + + // Set unspecified values to their defaults + specification.SetPropertyDefaults(properties); + + properties.SetSourceOfAllProperties(source); + + SharedPtr decorator = instancer->InstanceDecorator(type, properties, DecoratorInstancerInterface(*this)); + + if (decorator) + decorators.list.emplace_back(std::move(decorator)); + else + { + Log::Message(Log::LT_WARNING, "Decorator '%s' could not be instanced, declared at %s:%d", decorator_string.c_str(), source_path, source_line_number); + continue; + } + } + } + + return MakeShared(std::move(decorators)); +} + +FontEffectsPtr StyleSheet::InstanceFontEffectsFromString(const String& font_effect_string_value, const SharedPtr& source) const +{ + // Font-effects are declared as + // font-effect: [, ...]; + // Where is declared with inline properties, e.g. + // font-effect: outline( 1px black ), ...; + + if (font_effect_string_value.empty() || font_effect_string_value == "none") + return nullptr; + + const char* source_path = (source ? source->path.c_str() : ""); + const int source_line_number = (source ? source->line_number : 0); + + FontEffects font_effects; + + // Make sure we don't split inside the parenthesis since they may appear in decorator shorthands. + StringList font_effect_string_list; + StringUtilities::ExpandString(font_effect_string_list, font_effect_string_value, ',', '(', ')'); + + font_effects.value = font_effect_string_value; + font_effects.list.reserve(font_effect_string_list.size()); + + // Get or instance each decorator in the comma-separated string list + for (const String& font_effect_string : font_effect_string_list) + { + const size_t shorthand_open = font_effect_string.find('('); + const size_t shorthand_close = font_effect_string.rfind(')'); + const bool invalid_parenthesis = (shorthand_open == String::npos || shorthand_close == String::npos || shorthand_open >= shorthand_close); + + if (invalid_parenthesis) + { + // We found no parenthesis, font-effects can only be declared anonymously for now. + Log::Message(Log::LT_WARNING, "Invalid syntax for font-effect '%s', declared at %s:%d", font_effect_string.c_str(), source_path, source_line_number); + } + else + { + // Since we have parentheses it must be an anonymous decorator with inline properties + const String type = StringUtilities::StripWhitespace(font_effect_string.substr(0, shorthand_open)); + + // Check for valid font-effect type + FontEffectInstancer* instancer = Factory::GetFontEffectInstancer(type); + if (!instancer) + { + Log::Message(Log::LT_WARNING, "Font-effect type '%s' not found, declared at %s:%d", type.c_str(), source_path, source_line_number); + continue; + } + + const String shorthand = font_effect_string.substr(shorthand_open + 1, shorthand_close - shorthand_open - 1); + const PropertySpecification& specification = instancer->GetPropertySpecification(); + + // Parse the shorthand properties given by the 'font-effect' shorthand property + PropertyDictionary properties; + if (!specification.ParsePropertyDeclaration(properties, "font-effect", shorthand)) + { + Log::Message(Log::LT_WARNING, "Could not parse font-effect value '%s' at %s:%d", font_effect_string.c_str(), source_path, source_line_number); + continue; + } + + // Set unspecified values to their defaults + specification.SetPropertyDefaults(properties); + + properties.SetSourceOfAllProperties(source); + + SharedPtr font_effect = instancer->InstanceFontEffect(type, properties); + if (font_effect) + { + // Create a unique hash value for the given type and values + size_t fingerprint = Hash{}(type); + for (const auto& id_value : properties.GetProperties()) + Utilities::HashCombine(fingerprint, id_value.second.Get()); + + font_effect->SetFingerprint(fingerprint); + + font_effects.list.emplace_back(std::move(font_effect)); + } + else + { + Log::Message(Log::LT_WARNING, "Font-effect '%s' could not be instanced, declared at %s:%d", font_effect_string.c_str(), source_path, source_line_number); + continue; + } + } + } + + // Partition the list such that the back layer effects appear before the front layer effects + std::stable_partition(font_effects.list.begin(), font_effects.list.end(), + [](const SharedPtr& effect) { return effect->GetLayer() == FontEffect::Layer::Back; } + ); + + return MakeShared(std::move(font_effects)); +} + +size_t StyleSheet::NodeHash(const String& tag, const String& id) +{ + size_t seed = 0; + if (!tag.empty()) + seed = Hash()(tag); + if(!id.empty()) + Utilities::HashCombine(seed, id); + return seed; +} + +// Returns the compiled element definition for a given element hierarchy. +SharedPtr StyleSheet::GetElementDefinition(const Element* element) const +{ + RMLUI_ASSERT_NONRECURSIVE; + + // See if there are any styles defined for this element. + // Using static to avoid allocations. Make sure we don't call this function recursively. + static Vector< const StyleSheetNode* > applicable_nodes; + applicable_nodes.clear(); + + const String& tag = element->GetTagName(); + const String& id = element->GetId(); + + // The styled_node_index is hashed with the tag and id of the RCSS rule. However, we must also check + // the rules which don't have them defined, because they apply regardless of tag and id. + Array node_hash; + int num_hashes = 2; + + node_hash[0] = 0; + node_hash[1] = NodeHash(tag, String()); + + // If we don't have an id, we can safely skip nodes that define an id. Otherwise, we also check the id nodes. + if (!id.empty()) + { + num_hashes = 4; + node_hash[2] = NodeHash(String(), id); + node_hash[3] = NodeHash(tag, id); + } + + // The hashes are keys into a set of applicable nodes (given tag and id). + for (int i = 0; i < num_hashes; i++) + { + auto it_nodes = styled_node_index.find(node_hash[i]); + if (it_nodes != styled_node_index.end()) + { + const NodeList& nodes = it_nodes->second; + + // Now see if we satisfy all of the requirements not yet tested: classes, pseudo classes, structural selectors, + // and the full requirements of parent nodes. What this involves is traversing the style nodes backwards, + // trying to match nodes in the element's hierarchy to nodes in the style hierarchy. + for (StyleSheetNode* node : nodes) + { + if (node->IsApplicable(element, true)) + { + applicable_nodes.push_back(node); + } + } + } + } + + std::sort(applicable_nodes.begin(), applicable_nodes.end(), StyleSheetNodeSort); + + // If this element definition won't actually store any information, don't bother with it. + if (applicable_nodes.empty()) + return nullptr; + + // Check if this puppy has already been cached in the node index. + size_t seed = 0; + for (const StyleSheetNode* node : applicable_nodes) + Utilities::HashCombine(seed, node); + + auto cache_iterator = node_cache.find(seed); + if (cache_iterator != node_cache.end()) + { + SharedPtr& definition = (*cache_iterator).second; + return definition; + } + + // Create the new definition and add it to our cache. + auto new_definition = MakeShared(applicable_nodes); + node_cache[seed] = new_definition; + + return new_definition; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetFactory.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetFactory.cpp new file mode 100644 index 000000000..b817d854c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetFactory.cpp @@ -0,0 +1,261 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetFactory.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "StyleSheetNode.h" +#include "StreamFile.h" +#include "StyleSheetNodeSelectorNthChild.h" +#include "StyleSheetNodeSelectorNthLastChild.h" +#include "StyleSheetNodeSelectorNthOfType.h" +#include "StyleSheetNodeSelectorNthLastOfType.h" +#include "StyleSheetNodeSelectorFirstChild.h" +#include "StyleSheetNodeSelectorLastChild.h" +#include "StyleSheetNodeSelectorFirstOfType.h" +#include "StyleSheetNodeSelectorLastOfType.h" +#include "StyleSheetNodeSelectorOnlyChild.h" +#include "StyleSheetNodeSelectorOnlyOfType.h" +#include "StyleSheetNodeSelectorEmpty.h" +#include "../../Include/RmlUi/Core/Log.h" + +namespace Rml { + +static StyleSheetFactory* instance = nullptr; + +StyleSheetFactory::StyleSheetFactory() +{ + RMLUI_ASSERT(instance == nullptr); + instance = this; +} + +StyleSheetFactory::~StyleSheetFactory() +{ + instance = nullptr; +} + +bool StyleSheetFactory::Initialise() +{ + new StyleSheetFactory(); + + instance->selectors["nth-child"] = new StyleSheetNodeSelectorNthChild(); + instance->selectors["nth-last-child"] = new StyleSheetNodeSelectorNthLastChild(); + instance->selectors["nth-of-type"] = new StyleSheetNodeSelectorNthOfType(); + instance->selectors["nth-last-of-type"] = new StyleSheetNodeSelectorNthLastOfType(); + instance->selectors["first-child"] = new StyleSheetNodeSelectorFirstChild(); + instance->selectors["last-child"] = new StyleSheetNodeSelectorLastChild(); + instance->selectors["first-of-type"] = new StyleSheetNodeSelectorFirstOfType(); + instance->selectors["last-of-type"] = new StyleSheetNodeSelectorLastOfType(); + instance->selectors["only-child"] = new StyleSheetNodeSelectorOnlyChild(); + instance->selectors["only-of-type"] = new StyleSheetNodeSelectorOnlyOfType(); + instance->selectors["empty"] = new StyleSheetNodeSelectorEmpty(); + + return true; +} + +void StyleSheetFactory::Shutdown() +{ + if (instance != nullptr) + { + ClearStyleSheetCache(); + + for (SelectorMap::iterator i = instance->selectors.begin(); i != instance->selectors.end(); ++i) + delete (*i).second; + + delete instance; + } +} + +SharedPtr StyleSheetFactory::GetStyleSheet(const String& sheet_name) +{ + // Look up the sheet definition in the cache + StyleSheets::iterator itr = instance->stylesheets.find(sheet_name); + if (itr != instance->stylesheets.end()) + { + return (*itr).second; + } + + // Don't currently have the sheet, attempt to load it + SharedPtr sheet = instance->LoadStyleSheet(sheet_name); + if (!sheet) + return nullptr; + + // Add it to the cache, and add a reference count so the cache will keep hold of it. + instance->stylesheets[sheet_name] = sheet; + + return sheet; +} + +SharedPtr StyleSheetFactory::GetStyleSheet(const StringList& sheets) +{ + // Generate a unique key for these sheets + String combined_key; + for (size_t i = 0; i < sheets.size(); i++) + { + URL path(sheets[i]); + combined_key += path.GetFileName(); + } + + // Look up the sheet definition in the cache. + StyleSheets::iterator itr = instance->stylesheet_cache.find(combined_key); + if (itr != instance->stylesheet_cache.end()) + { + return (*itr).second; + } + + // Load and combine the sheets. + SharedPtr sheet; + for (size_t i = 0; i < sheets.size(); i++) + { + SharedPtr sub_sheet = GetStyleSheet(sheets[i]); + if (sub_sheet) + { + if (sheet) + { + SharedPtr new_sheet = sheet->CombineStyleSheet(*sub_sheet); + sheet = new_sheet; + } + else + sheet = sub_sheet; + } + else + Log::Message(Log::LT_ERROR, "Failed to load style sheet %s.", sheets[i].c_str()); + } + + if (!sheet) + return nullptr; + + // Add to cache, and a reference to the sheet to hold it in the cache. + instance->stylesheet_cache[combined_key] = sheet; + return sheet; +} + +// Clear the style sheet cache. +void StyleSheetFactory::ClearStyleSheetCache() +{ + instance->stylesheets.clear(); + instance->stylesheet_cache.clear(); +} + +// Returns one of the available node selectors. +StructuralSelector StyleSheetFactory::GetSelector(const String& name) +{ + SelectorMap::const_iterator it; + const size_t parameter_start = name.find('('); + + if (parameter_start == String::npos) + it = instance->selectors.find(name); + else + it = instance->selectors.find(name.substr(0, parameter_start)); + + if (it == instance->selectors.end()) + return StructuralSelector(nullptr, 0, 0); + + // Parse the 'a' and 'b' values. + int a = 1; + int b = 0; + + const size_t parameter_end = name.find(')', parameter_start + 1); + if (parameter_start != String::npos && + parameter_end != String::npos) + { + String parameters = StringUtilities::StripWhitespace(name.substr(parameter_start + 1, parameter_end - (parameter_start + 1))); + + // Check for 'even' or 'odd' first. + if (parameters == "even") + { + a = 2; + b = 0; + } + else if (parameters == "odd") + { + a = 2; + b = 1; + } + else + { + // Alrighty; we've got an equation in the form of [[+/-]an][(+/-)b]. So, foist up, we split on 'n'. + const size_t n_index = parameters.find('n'); + if (n_index == String::npos) + { + // The equation is 0n + b. So a = 0, and we only have to parse b. + a = 0; + b = atoi(parameters.c_str()); + } + else + { + if (n_index == 0) + a = 1; + else + { + const String a_parameter = parameters.substr(0, n_index); + if (StringUtilities::StripWhitespace(a_parameter) == "-") + a = -1; + else + a = atoi(a_parameter.c_str()); + } + + size_t pm_index = parameters.find('+', n_index + 1); + if (pm_index != String::npos) + b = 1; + else + { + pm_index = parameters.find('-', n_index + 1); + if (pm_index != String::npos) + b = -1; + } + + if (n_index == parameters.size() - 1 || pm_index == String::npos) + b = 0; + else + b = b * atoi(parameters.data() + pm_index + 1); + } + } + } + + return StructuralSelector(it->second, a, b); +} + +SharedPtr StyleSheetFactory::LoadStyleSheet(const String& sheet) +{ + SharedPtr new_style_sheet; + + // Open stream, construct new sheet and pass the stream into the sheet + // TODO: Make this support ASYNC + auto stream = MakeUnique(); + if (stream->Open(sheet)) + { + new_style_sheet = MakeShared(); + if (!new_style_sheet->LoadStyleSheet(stream.get())) + { + new_style_sheet = nullptr; + } + } + return new_style_sheet; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetFactory.h b/thirdparty/RmlUi/Source/Core/StyleSheetFactory.h new file mode 100644 index 000000000..b9e86b6b3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetFactory.h @@ -0,0 +1,91 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETFACTORY_H +#define RMLUI_CORE_STYLESHEETFACTORY_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class StyleSheet; +class StyleSheetNodeSelector; +struct StructuralSelector; + +/** + Creates stylesheets on the fly as needed. The factory keeps a cache of built sheets for optimisation. + + @author Lloyd Weehuizen + */ + +class StyleSheetFactory +{ +public: + /// Initialise the style factory + static bool Initialise(); + /// Shutdown style manager + static void Shutdown(); + + /// Gets the named sheet, retrieving it from the cache if its already been loaded + /// @param sheet name of sheet to load + static SharedPtr GetStyleSheet(const String& sheet); + + /// Builds and returns a stylesheet based on the list of input sheets + /// Generated sheets will be cached for later use + /// @param sheets List of sheets to combine into one + static SharedPtr GetStyleSheet(const StringList& sheets); + + /// Clear the style sheet cache. + static void ClearStyleSheetCache(); + + /// Returns one of the available node selectors. + /// @param name[in] The name of the desired selector. + /// @return The selector registered with the given name, or nullptr if none exists. + static StructuralSelector GetSelector(const String& name); + +private: + StyleSheetFactory(); + ~StyleSheetFactory(); + + // Loads an individual style sheet + SharedPtr LoadStyleSheet(const String& sheet); + + // Individual loaded stylesheets + typedef UnorderedMap> StyleSheets; + StyleSheets stylesheets; + + // Cache of combined style sheets + StyleSheets stylesheet_cache; + + // Custom complex selectors available for style sheets. + typedef UnorderedMap< String, StyleSheetNodeSelector* > SelectorMap; + SelectorMap selectors; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNode.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNode.cpp new file mode 100644 index 000000000..85cc87d99 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNode.cpp @@ -0,0 +1,341 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNode.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "StyleSheetFactory.h" +#include "StyleSheetNodeSelector.h" +#include + +namespace Rml { + +StyleSheetNode::StyleSheetNode() +{ + CalculateAndSetSpecificity(); +} + +StyleSheetNode::StyleSheetNode(StyleSheetNode* parent, const String& tag, const String& id, const StringList& classes, const StringList& pseudo_classes, const StructuralSelectorList& structural_selectors, bool child_combinator) + : parent(parent), tag(tag), id(id), class_names(classes), pseudo_class_names(pseudo_classes), structural_selectors(structural_selectors), child_combinator(child_combinator) +{ + CalculateAndSetSpecificity(); +} + +StyleSheetNode::StyleSheetNode(StyleSheetNode* parent, String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes, StructuralSelectorList&& structural_selectors, bool child_combinator) + : parent(parent), tag(std::move(tag)), id(std::move(id)), class_names(std::move(classes)), pseudo_class_names(std::move(pseudo_classes)), structural_selectors(std::move(structural_selectors)), child_combinator(child_combinator) +{ + CalculateAndSetSpecificity(); +} + +StyleSheetNode* StyleSheetNode::GetOrCreateChildNode(const StyleSheetNode& other) +{ + // See if we match the target child + for (const auto& child : children) + { + if (child->EqualRequirements(other.tag, other.id, other.class_names, other.pseudo_class_names, other.structural_selectors, other.child_combinator)) + return child.get(); + } + + // We don't, so create a new child + auto child = MakeUnique(this, other.tag, other.id, other.class_names, other.pseudo_class_names, other.structural_selectors, other.child_combinator); + StyleSheetNode* result = child.get(); + + children.push_back(std::move(child)); + + return result; +} + +StyleSheetNode* StyleSheetNode::GetOrCreateChildNode(String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes, StructuralSelectorList&& structural_pseudo_classes, bool child_combinator) +{ + // See if we match an existing child + for (const auto& child : children) + { + if (child->EqualRequirements(tag, id, classes, pseudo_classes, structural_pseudo_classes, child_combinator)) + return child.get(); + } + + // We don't, so create a new child + auto child = MakeUnique(this, std::move(tag), std::move(id), std::move(classes), std::move(pseudo_classes), std::move(structural_pseudo_classes), child_combinator); + StyleSheetNode* result = child.get(); + + children.push_back(std::move(child)); + + return result; +} + +// Merges an entire tree hierarchy into our hierarchy. +bool StyleSheetNode::MergeHierarchy(StyleSheetNode* node, int specificity_offset) +{ + // Merge the other node's properties into ours. + properties.Merge(node->properties, specificity_offset); + + for (const auto& other_child : node->children) + { + StyleSheetNode* local_node = GetOrCreateChildNode(*other_child); + local_node->MergeHierarchy(other_child.get(), specificity_offset); + } + + return true; +} + +// Builds up a style sheet's index recursively. +void StyleSheetNode::BuildIndexAndOptimizeProperties(StyleSheet::NodeIndex& styled_node_index, const StyleSheet& style_sheet) +{ + RMLUI_ZoneScoped; + + // If this has properties defined, then we insert it into the styled node index. + if(properties.GetNumProperties() > 0) + { + // The keys of the node index is a hashed combination of tag and id. These are used for fast lookup of applicable nodes. + size_t node_hash = StyleSheet::NodeHash(tag, id); + StyleSheet::NodeList& nodes = styled_node_index[node_hash]; + auto it = std::find(nodes.begin(), nodes.end(), this); + if(it == nodes.end()) + nodes.push_back(this); + } + + // Turn any decorator and font-effect properties from String to DecoratorList / FontEffectList. + // This is essentially an optimization, it will work fine to skip this step and let ElementStyle::ComputeValues() do all the work. + // However, when we do it here, we only need to do it once. + // Note, since the user may set a new decorator through its style, we still do the conversion as necessary again in ComputeValues. + if (properties.GetNumProperties() > 0) + { + // Decorators + if (const Property* property = properties.GetProperty(PropertyId::Decorator)) + { + if (property->unit == Property::STRING) + { + const String string_value = property->Get(); + + if(DecoratorsPtr decorators = style_sheet.InstanceDecoratorsFromString(string_value, property->source)) + { + Property new_property = *property; + new_property.value = std::move(decorators); + new_property.unit = Property::DECORATOR; + properties.SetProperty(PropertyId::Decorator, new_property); + } + } + } + + // Font-effects + if (const Property * property = properties.GetProperty(PropertyId::FontEffect)) + { + if (property->unit == Property::STRING) + { + const String string_value = property->Get(); + FontEffectsPtr font_effects = style_sheet.InstanceFontEffectsFromString(string_value, property->source); + + Property new_property = *property; + new_property.value = std::move(font_effects); + new_property.unit = Property::FONTEFFECT; + properties.SetProperty(PropertyId::FontEffect, new_property); + } + } + } + + for (auto& child : children) + { + child->BuildIndexAndOptimizeProperties(styled_node_index, style_sheet); + } +} + + +bool StyleSheetNode::SetStructurallyVolatileRecursive(bool ancestor_is_structural_pseudo_class) +{ + // If any ancestor or descendant is a structural pseudo class, then we are structurally volatile. + bool self_is_structural_pseudo_class = (!structural_selectors.empty()); + + // Check our children for structural pseudo-classes. + bool descendant_is_structural_pseudo_class = false; + for (auto& child : children) + { + if (child->SetStructurallyVolatileRecursive(self_is_structural_pseudo_class || ancestor_is_structural_pseudo_class)) + descendant_is_structural_pseudo_class = true; + } + + is_structurally_volatile = (self_is_structural_pseudo_class || ancestor_is_structural_pseudo_class || descendant_is_structural_pseudo_class); + + return (self_is_structural_pseudo_class || descendant_is_structural_pseudo_class); +} + +bool StyleSheetNode::EqualRequirements(const String& _tag, const String& _id, const StringList& _class_names, const StringList& _pseudo_class_names, const StructuralSelectorList& _structural_selectors, bool _child_combinator) const +{ + if (tag != _tag) + return false; + if (id != _id) + return false; + if (class_names != _class_names) + return false; + if (pseudo_class_names != _pseudo_class_names) + return false; + if (structural_selectors != _structural_selectors) + return false; + if (child_combinator != _child_combinator) + return false; + + return true; +} + +// Returns the specificity of this node. +int StyleSheetNode::GetSpecificity() const +{ + return specificity; +} + +// Imports properties from a single rule definition (ie, with a shared specificity) into the node's +// properties. +void StyleSheetNode::ImportProperties(const PropertyDictionary& _properties, int rule_specificity) +{ + properties.Import(_properties, specificity + rule_specificity); +} + +// Returns the node's default properties. +const PropertyDictionary& StyleSheetNode::GetProperties() const +{ + return properties; +} + +inline bool StyleSheetNode::Match(const Element* element) const +{ + if (!tag.empty() && tag != element->GetTagName()) + return false; + + if (!id.empty() && id != element->GetId()) + return false; + + if (!MatchClassPseudoClass(element)) + return false; + + if (!MatchStructuralSelector(element)) + return false; + + return true; +} + +inline bool StyleSheetNode::MatchClassPseudoClass(const Element* element) const +{ + for (auto& name : class_names) + { + if (!element->IsClassSet(name)) + return false; + } + + for (auto& name : pseudo_class_names) + { + if (!element->IsPseudoClassSet(name)) + return false; + } + + return true; +} + +inline bool StyleSheetNode::MatchStructuralSelector(const Element* element) const +{ + for (auto& node_selector : structural_selectors) + { + if (!node_selector.selector->IsApplicable(element, node_selector.a, node_selector.b)) + return false; + } + + return true; +} + +// Returns true if this node is applicable to the given element, given its IDs, classes and heritage. +bool StyleSheetNode::IsApplicable(const Element* const in_element, bool skip_id_tag) const +{ + // Determine whether the element matches the current node and its entire lineage. The entire hierarchy of + // the element's document will be considered during the match as necessary. + + if (skip_id_tag) + { + // Id and tag have already been checked, only check class and pseudo class. + if (!MatchClassPseudoClass(in_element)) + return false; + } + else + { + // Id and tag have not already been matched, match everything. + if (!Match(in_element)) + return false; + } + + const Element* element = in_element; + + // Walk up through all our parent nodes, each one of them must be matched by some ancestor element. + for(const StyleSheetNode* node = parent; node && node->parent; node = node->parent) + { + // Try a match on every element ancestor. If it succeeds, we continue on to the next node. + for(element = element->GetParentNode(); element; element = element->GetParentNode()) + { + if (node->Match(element)) + break; + // If we have a child combinator on the node, we must match this first ancestor. + else if (node->child_combinator) + return false; + } + + // We have run out of element ancestors before we matched every node. Bail out. + if (!element) + return false; + } + + // Finally, check the structural selector requirements last as they can be quite slow. + if (!MatchStructuralSelector(in_element)) + return false; + + return true; +} + +bool StyleSheetNode::IsStructurallyVolatile() const +{ + return is_structurally_volatile; +} + + +void StyleSheetNode::CalculateAndSetSpecificity() +{ + // Calculate the specificity of just this node; tags are worth 10,000, IDs 1,000,000 and other specifiers (classes + // and pseudo-classes) 100,000. + specificity = 0; + + if (!tag.empty()) + specificity += 10'000; + + if (!id.empty()) + specificity += 1'000'000; + + specificity += 100'000*(int)class_names.size(); + specificity += 100'000*(int)pseudo_class_names.size(); + specificity += 100'000*(int)structural_selectors.size(); + + // Add our parent's specificity onto ours. + if (parent) + specificity += parent->specificity; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNode.h b/thirdparty/RmlUi/Source/Core/StyleSheetNode.h new file mode 100644 index 000000000..c11946d78 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNode.h @@ -0,0 +1,133 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODE_H +#define RMLUI_CORE_STYLESHEETNODE_H + +#include "../../Include/RmlUi/Core/PropertyDictionary.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/Types.h" +#include + +namespace Rml { + +class StyleSheetNodeSelector; + +struct StructuralSelector { + StructuralSelector(StyleSheetNodeSelector* selector, int a, int b) : selector(selector), a(a), b(b) {} + StyleSheetNodeSelector* selector; + int a; + int b; +}; +inline bool operator==(const StructuralSelector& a, const StructuralSelector& b) { return a.selector == b.selector && a.a == b.a && a.b == b.b; } +inline bool operator<(const StructuralSelector& a, const StructuralSelector& b) { return std::tie(a.selector, a.a, a.b) < std::tie(b.selector, b.a, b.b); } + +using StructuralSelectorList = Vector< StructuralSelector >; +using StyleSheetNodeList = Vector< UniquePtr >; + + +/** + A style sheet is composed of a tree of nodes. + + @author Pete / Lloyd + */ + +class StyleSheetNode +{ +public: + StyleSheetNode(); + StyleSheetNode(StyleSheetNode* parent, const String& tag, const String& id, const StringList& classes, const StringList& pseudo_classes, const StructuralSelectorList& structural_selectors, bool child_combinator); + StyleSheetNode(StyleSheetNode* parent, String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes, StructuralSelectorList&& structural_selectors, bool child_combinator); + + /// Retrieves a child node with the given requirements if they match an existing node, or else creates a new one. + StyleSheetNode* GetOrCreateChildNode(String&& tag, String&& id, StringList&& classes, StringList&& pseudo_classes, StructuralSelectorList&& structural_selectors, bool child_combinator); + /// Retrieves or creates a child node with requirements equivalent to the 'other' node. + StyleSheetNode* GetOrCreateChildNode(const StyleSheetNode& other); + + /// Merges an entire tree hierarchy into our hierarchy. + bool MergeHierarchy(StyleSheetNode* node, int specificity_offset = 0); + /// Recursively set structural volatility. + bool SetStructurallyVolatileRecursive(bool ancestor_is_structurally_volatile); + /// Builds up a style sheet's index recursively and optimizes some properties for faster retrieval. + void BuildIndexAndOptimizeProperties(StyleSheet::NodeIndex& styled_node_index, const StyleSheet& style_sheet); + + /// Imports properties from a single rule definition into the node's properties and sets the + /// appropriate specificity on them. Any existing attributes sharing a key with a new attribute + /// will be overwritten if they are of a lower specificity. + /// @param[in] properties The properties to import. + /// @param[in] rule_specificity The specificity of the importing rule. + void ImportProperties(const PropertyDictionary& properties, int rule_specificity); + /// Returns the node's default properties. + const PropertyDictionary& GetProperties() const; + + /// Returns true if this node is applicable to the given element, given its IDs, classes and heritage. + bool IsApplicable(const Element* element, bool skip_id_tag) const; + + /// Returns the specificity of this node. + int GetSpecificity() const; + /// Returns true if this node employs a structural selector, and therefore generates element definitions that are + /// sensitive to sibling changes. + /// @warning Result is only valid if structural volatility is set since any changes to the node tree. + bool IsStructurallyVolatile() const; + +private: + // Returns true if the requirements of this node equals the given arguments. + bool EqualRequirements(const String& tag, const String& id, const StringList& classes, const StringList& pseudo_classes, const StructuralSelectorList& structural_pseudo_classes, bool child_combinator) const; + + void CalculateAndSetSpecificity(); + + // Match an element to the local node requirements. + inline bool Match(const Element* element) const; + inline bool MatchClassPseudoClass(const Element* element) const; + inline bool MatchStructuralSelector(const Element* element) const; + + // The parent of this node; is nullptr for the root node. + StyleSheetNode* parent = nullptr; + + // Node requirements + String tag; + String id; + StringList class_names; + StringList pseudo_class_names; + StructuralSelectorList structural_selectors; // Represents structural pseudo classes + bool child_combinator = false; // The '>' combinator: This node only matches if the element is a parent of the previous matching element. + + // True if any ancestor, descendent, or self is a structural pseudo class. + bool is_structurally_volatile = true; + + // A measure of specificity of this node; the attribute in a node with a higher value will override those of a + // node with a lower value. + int specificity = 0; + + PropertyDictionary properties; + + StyleSheetNodeList children; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelector.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelector.cpp new file mode 100644 index 000000000..6d87daa23 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelector.cpp @@ -0,0 +1,52 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +StyleSheetNodeSelector::StyleSheetNodeSelector() +{ +} + +StyleSheetNodeSelector::~StyleSheetNodeSelector() +{ +} + +// Returns true if a positive integer can be found for n in the equation an + b = count. +bool StyleSheetNodeSelector::IsNth(int a, int b, int count) +{ + int x = count; + x -= b; + if (a != 0) + x /= a; + + return (x >= 0 && x * a + b == count); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelector.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelector.h new file mode 100644 index 000000000..9c9d83a50 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelector.h @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTOR_H +#define RMLUI_CORE_STYLESHEETNODESELECTOR_H + +namespace Rml { + +class Element; + +/** + The ABC for any complex node selector, such as structural selectors. + + @author Peter Curry + */ + +class StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelector(); + virtual ~StyleSheetNodeSelector(); + + /// Returns true if the the node this selector is discriminating for is applicable to a given element. + /// @param element[in] The element to determine node applicability for. + /// @param a[in] For counting selectors, this is the 'a' variable of an + b. + /// @param b[in] For counting selectors, this is the 'b' variable of an + b. + virtual bool IsApplicable(const Element* element, int a, int b) = 0; + +protected: + /// Returns true if a positive integer can be found for n in the equation an + b = count. + bool IsNth(int a, int b, int count); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorEmpty.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorEmpty.cpp new file mode 100644 index 000000000..f58cec11c --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorEmpty.cpp @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorEmpty.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorEmpty::StyleSheetNodeSelectorEmpty() +{ +} + +StyleSheetNodeSelectorEmpty::~StyleSheetNodeSelectorEmpty() +{ +} + +// Returns true if the element has no DOM children. +bool StyleSheetNodeSelectorEmpty::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + for (int i = 0; i < element->GetNumChildren(); ++i) + { + if (element->GetChild(i)->GetDisplay() != Style::Display::None) + return false; + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorEmpty.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorEmpty.h new file mode 100644 index 000000000..dc28e6d9d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorEmpty.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTOREMPTY_H +#define RMLUI_CORE_STYLESHEETNODESELECTOREMPTY_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for an empty node. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorEmpty : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorEmpty(); + virtual ~StyleSheetNodeSelectorEmpty(); + + // Returns true if the element has no DOM children. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstChild.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstChild.cpp new file mode 100644 index 000000000..9c62d92fe --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstChild.cpp @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorFirstChild.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorFirstChild::StyleSheetNodeSelectorFirstChild() +{ +} + +StyleSheetNodeSelectorFirstChild::~StyleSheetNodeSelectorFirstChild() +{ +} + +// Returns true if the element is the first DOM child in its parent. +bool StyleSheetNodeSelectorFirstChild::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + int child_index = 0; + while (child_index < parent->GetNumChildren()) + { + // If this child (the first non-text child) is our element, then the selector succeeds. + Element* child = parent->GetChild(child_index); + if (child == element) + return true; + + // If this child is not a text element, then the selector fails; this element is non-trivial. + if (rmlui_dynamic_cast< ElementText* >(child) == nullptr && + child->GetDisplay() != Style::Display::None) + return false; + + // Otherwise, skip over the text element to find the last non-trivial element. + child_index++; + } + + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstChild.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstChild.h new file mode 100644 index 000000000..ab752248f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstChild.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORFIRSTCHILD_H +#define RMLUI_CORE_STYLESHEETNODESELECTORFIRSTCHILD_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the first generic child. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorFirstChild : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorFirstChild(); + virtual ~StyleSheetNodeSelectorFirstChild(); + + // Returns true if the element is the first DOM child in its parent. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstOfType.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstOfType.cpp new file mode 100644 index 000000000..73dc70cc3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstOfType.cpp @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorFirstOfType.h" +#include "../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +StyleSheetNodeSelectorFirstOfType::StyleSheetNodeSelectorFirstOfType() +{ +} + +StyleSheetNodeSelectorFirstOfType::~StyleSheetNodeSelectorFirstOfType() +{ +} + +// Returns true if the element is the first DOM child in its parent of its type. +bool StyleSheetNodeSelectorFirstOfType::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + int child_index = 0; + while (child_index < parent->GetNumChildren()) + { + // If this child is our element, then it's the first one we've found with our tag; the selector succeeds. + Element* child = parent->GetChild(child_index); + if (child == element) + return true; + + // Otherwise, if this child shares our element's tag, then our element is not the first tagged child; the + // selector fails. + if (child->GetTagName() == element->GetTagName() && + child->GetDisplay() != Style::Display::None) + return false; + + child_index++; + } + + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstOfType.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstOfType.h new file mode 100644 index 000000000..eb7af45b4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorFirstOfType.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORFIRSTOFTYPE_H +#define RMLUI_CORE_STYLESHEETNODESELECTORFIRSTOFTYPE_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the first child of its type. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorFirstOfType : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorFirstOfType(); + virtual ~StyleSheetNodeSelectorFirstOfType(); + + /// Returns true if the element is the first DOM child in its parent of its type. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastChild.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastChild.cpp new file mode 100644 index 000000000..29f436324 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastChild.cpp @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorLastChild.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorLastChild::StyleSheetNodeSelectorLastChild() +{ +} + +StyleSheetNodeSelectorLastChild::~StyleSheetNodeSelectorLastChild() +{ +} + +// Returns true if the element is the last DOM child in its parent. +bool StyleSheetNodeSelectorLastChild::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + int child_index = parent->GetNumChildren() - 1; + while (child_index >= 0) + { + // If this child (the last non-text child) is our element, then the selector succeeds. + Element* child = parent->GetChild(child_index); + if (child == element) + return true; + + // If this child is not a text element, then the selector fails; this element is non-trivial. + if (rmlui_dynamic_cast< ElementText* >(child) == nullptr && + child->GetDisplay() != Style::Display::None) + return false; + + // Otherwise, skip over the text element to find the last non-trivial element. + child_index--; + } + + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastChild.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastChild.h new file mode 100644 index 000000000..06a110560 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastChild.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORLASTCHILD_H +#define RMLUI_CORE_STYLESHEETNODESELECTORLASTCHILD_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the last generic child. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorLastChild : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorLastChild(); + virtual ~StyleSheetNodeSelectorLastChild(); + + // Returns true if the element is the last DOM child in its parent. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastOfType.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastOfType.cpp new file mode 100644 index 000000000..0044f63a6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastOfType.cpp @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorLastOfType.h" +#include "../../Include/RmlUi/Core/Element.h" + +namespace Rml { + +StyleSheetNodeSelectorLastOfType::StyleSheetNodeSelectorLastOfType() +{ +} + +StyleSheetNodeSelectorLastOfType::~StyleSheetNodeSelectorLastOfType() +{ +} + +// Returns true if the element is the last DOM child in its parent. +bool StyleSheetNodeSelectorLastOfType::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + int child_index = parent->GetNumChildren() - 1; + while (child_index >= 0) + { + // If this child is our element, then it's the first one we've found with our tag; the selector succeeds. + Element* child = parent->GetChild(child_index); + if (child == element) + return true; + + // Otherwise, if this child shares our element's tag, then our element is not the first tagged child; the + // selector fails. + if (child->GetTagName() == element->GetTagName() && + child->GetDisplay() != Style::Display::None) + return false; + + child_index--; + } + + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastOfType.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastOfType.h new file mode 100644 index 000000000..3837f3d19 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorLastOfType.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORLASTOFTYPE_H +#define RMLUI_CORE_STYLESHEETNODESELECTORLASTOFTYPE_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the first child of its type. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorLastOfType : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorLastOfType(); + virtual ~StyleSheetNodeSelectorLastOfType(); + + // Returns true if the element is the last DOM child in its parent. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthChild.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthChild.cpp new file mode 100644 index 000000000..2facbad70 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthChild.cpp @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorNthChild.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Log.h" + +namespace Rml { + +StyleSheetNodeSelectorNthChild::StyleSheetNodeSelectorNthChild() +{ +} + +StyleSheetNodeSelectorNthChild::~StyleSheetNodeSelectorNthChild() +{ +} + +// Returns true if the element index is (n * a) + b for a given integer value of n. +bool StyleSheetNodeSelectorNthChild::IsApplicable(const Element* element, int a, int b) +{ + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + // Start counting elements until we find this one. + int element_index = 1; + for (int i = 0; i < parent->GetNumChildren(); i++) + { + Element* child = parent->GetChild(i); + + // Skip text nodes. + if (rmlui_dynamic_cast< ElementText* >(child) != nullptr) + continue; + + // If we've found our element, then break; the current index is our element's index. + if (child == element) + break; + + // Skip nodes without a display type. + if (child->GetDisplay() == Style::Display::None) + continue; + + element_index++; + } + + return IsNth(a, b, element_index); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthChild.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthChild.h new file mode 100644 index 000000000..925358fb8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthChild.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORNTHCHILD_H +#define RMLUI_CORE_STYLESHEETNODESELECTORNTHCHILD_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the nth generic child. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorNthChild : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorNthChild(); + virtual ~StyleSheetNodeSelectorNthChild(); + + // Returns true if the element index is (n * a) + b for a given integer value of n. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastChild.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastChild.cpp new file mode 100644 index 000000000..bb1a8e926 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastChild.cpp @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorNthLastChild.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorNthLastChild::StyleSheetNodeSelectorNthLastChild() +{ +} + +StyleSheetNodeSelectorNthLastChild::~StyleSheetNodeSelectorNthLastChild() +{ +} + +// Returns true if the element's reverse index is (n * a) + b for a given integer value of n. +bool StyleSheetNodeSelectorNthLastChild::IsApplicable(const Element* element, int a, int b) +{ + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + // Start counting elements until we find this one. + int element_index = 1; + for (int i = parent->GetNumChildren() - 1; i >= 0; --i) + { + Element* child = parent->GetChild(i); + + // Skip text nodes. + if (rmlui_dynamic_cast< ElementText* >(child) != nullptr) + continue; + + // If we've found our element, then break; the current index is our element's index. + if (child == element) + break; + + if (child->GetDisplay() == Style::Display::None) + continue; + + element_index++; + } + + return IsNth(a, b, element_index); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastChild.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastChild.h new file mode 100644 index 000000000..f31124c54 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastChild.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORNTHLASTCHILD_H +#define RMLUI_CORE_STYLESHEETNODESELECTORNTHLASTCHILD_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the nth-last generic child. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorNthLastChild : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorNthLastChild(); + virtual ~StyleSheetNodeSelectorNthLastChild(); + + // Returns true if the element's reverse index is (n * a) + b for a given integer value of n. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp new file mode 100644 index 000000000..cd8b1a01e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastOfType.cpp @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorNthLastOfType.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorNthLastOfType::StyleSheetNodeSelectorNthLastOfType() +{ +} + +StyleSheetNodeSelectorNthLastOfType::~StyleSheetNodeSelectorNthLastOfType() +{ +} + +// Returns true if the element index is (n * a) + b for a given integer value of n. +bool StyleSheetNodeSelectorNthLastOfType::IsApplicable(const Element* element, int a, int b) +{ + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + // Start counting elements until we find this one. + int element_index = 1; + for (int i = parent->GetNumChildren() - 1; i >= 0; --i) + { + Element* child = parent->GetChild(i); + + // If we've found our element, then break; the current index is our element's index. + if (child == element) + break; + + // Skip nodes that don't share our tag. + if (child->GetTagName() != element->GetTagName() || + child->GetDisplay() == Style::Display::None) + continue; + + element_index++; + } + + return IsNth(a, b, element_index); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastOfType.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastOfType.h new file mode 100644 index 000000000..88ba28363 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthLastOfType.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORNTHLASTOFTYPE_H +#define RMLUI_CORE_STYLESHEETNODESELECTORNTHLASTOFTYPE_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the nth-last generic child of its type. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorNthLastOfType : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorNthLastOfType(); + virtual ~StyleSheetNodeSelectorNthLastOfType(); + + // Returns true if the element index is (n * a) + b for a given integer value of n. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthOfType.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthOfType.cpp new file mode 100644 index 000000000..dd1ee52f5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthOfType.cpp @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorNthOfType.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorNthOfType::StyleSheetNodeSelectorNthOfType() +{ +} + +StyleSheetNodeSelectorNthOfType::~StyleSheetNodeSelectorNthOfType() +{ +} + +// Returns true if the element index is (n * a) + b for a given integer value of n. +bool StyleSheetNodeSelectorNthOfType::IsApplicable(const Element* element, int a, int b) +{ + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + // Start counting elements until we find this one. + int element_index = 1; + for (int i = 0; i < parent->GetNumChildren(); ++i) + { + Element* child = parent->GetChild(i); + + // If we've found our element, then break; the current index is our element's index. + if (child == element) + break; + + // Skip nodes that don't share our tag. + if (child->GetTagName() != element->GetTagName() || + child->GetDisplay() == Style::Display::None) + continue; + + element_index++; + } + + return IsNth(a, b, element_index); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthOfType.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthOfType.h new file mode 100644 index 000000000..93da73b37 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorNthOfType.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORNTHOFTYPE_H +#define RMLUI_CORE_STYLESHEETNODESELECTORNTHOFTYPE_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the nth generic child. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorNthOfType : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorNthOfType(); + virtual ~StyleSheetNodeSelectorNthOfType(); + + // Returns true if the element index is (n * a) + b for a given integer value of n. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyChild.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyChild.cpp new file mode 100644 index 000000000..6e9b42f99 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyChild.cpp @@ -0,0 +1,71 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorOnlyChild.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorOnlyChild::StyleSheetNodeSelectorOnlyChild() +{ +} + +StyleSheetNodeSelectorOnlyChild::~StyleSheetNodeSelectorOnlyChild() +{ +} + +// Returns true if the element is the only non-trivial DOM child of its parent. +bool StyleSheetNodeSelectorOnlyChild::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + for (int i = 0; i < parent->GetNumChildren(); ++i) + { + Element* child = parent->GetChild(i); + + // Skip the child if it is our element. + if (child == element) + continue; + + // Skip the child if it is trivial. + if (rmlui_dynamic_cast< const ElementText* >(element) != nullptr || + child->GetDisplay() == Style::Display::None) + continue; + + return false; + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyChild.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyChild.h new file mode 100644 index 000000000..c12f53f66 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyChild.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORONLYCHILD_H +#define RMLUI_CORE_STYLESHEETNODESELECTORONLYCHILD_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for an only child. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorOnlyChild : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorOnlyChild(); + virtual ~StyleSheetNodeSelectorOnlyChild(); + + // Returns true if the element is the only non-trivial DOM child of its parent. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp new file mode 100644 index 000000000..133f30dc2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyOfType.cpp @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetNodeSelectorOnlyOfType.h" +#include "../../Include/RmlUi/Core/ElementText.h" + +namespace Rml { + +StyleSheetNodeSelectorOnlyOfType::StyleSheetNodeSelectorOnlyOfType() +{ +} + +StyleSheetNodeSelectorOnlyOfType::~StyleSheetNodeSelectorOnlyOfType() +{ +} + +// Returns true if the element is the only DOM child of its parent of its type. +bool StyleSheetNodeSelectorOnlyOfType::IsApplicable(const Element* element, int RMLUI_UNUSED_PARAMETER(a), int RMLUI_UNUSED_PARAMETER(b)) +{ + RMLUI_UNUSED(a); + RMLUI_UNUSED(b); + + Element* parent = element->GetParentNode(); + if (parent == nullptr) + return false; + + for (int i = 0; i < parent->GetNumChildren(); ++i) + { + Element* child = parent->GetChild(i); + + // Skip the child if it is our element. + if (child == element) + continue; + + // Skip the child if it does not share our tag. + if (child->GetTagName() != element->GetTagName() || + child->GetDisplay() == Style::Display::None) + continue; + + // We've found a similarly-tagged child to our element; selector fails. + return false; + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyOfType.h b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyOfType.h new file mode 100644 index 000000000..fea17e8b6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetNodeSelectorOnlyOfType.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETNODESELECTORONLYOFTYPE_H +#define RMLUI_CORE_STYLESHEETNODESELECTORONLYOFTYPE_H + +#include "StyleSheetNodeSelector.h" + +namespace Rml { + +/** + A node selector for the only child of its type. + + @author Peter Curry + */ + +class StyleSheetNodeSelectorOnlyOfType : public StyleSheetNodeSelector +{ +public: + StyleSheetNodeSelectorOnlyOfType(); + virtual ~StyleSheetNodeSelectorOnlyOfType(); + + // Returns true if the element is the only DOM child of its parent of its type. + bool IsApplicable(const Element* element, int a, int b) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetParser.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetParser.cpp new file mode 100644 index 000000000..5f67f8da5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetParser.cpp @@ -0,0 +1,830 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "StyleSheetParser.h" +#include "ComputeProperty.h" +#include "StyleSheetFactory.h" +#include "StyleSheetNode.h" +#include "../../Include/RmlUi/Core/DecoratorInstancer.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "../../Include/RmlUi/Core/PropertySpecification.h" +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include +#include + +namespace Rml { + +class AbstractPropertyParser { +public: + virtual bool Parse(const String& name, const String& value) = 0; +}; + +/* + * PropertySpecificationParser just passes the parsing to a property specification. Usually + * the main stylesheet specification, except for e.g. @decorator blocks. +*/ +class PropertySpecificationParser : public AbstractPropertyParser { +private: + PropertyDictionary& properties; + const PropertySpecification& specification; + +public: + PropertySpecificationParser(PropertyDictionary& properties, const PropertySpecification& specification) : properties(properties), specification(specification) {} + + bool Parse(const String& name, const String& value) override + { + return specification.ParsePropertyDeclaration(properties, name, value); + } +}; + +/* + * Spritesheets need a special parser because its property names are arbitrary keys, + * while its values are always rectangles. Thus, it must be parsed with a special "rectangle" parser + * for every name-value pair. We can probably optimize this for @performance. +*/ +class SpritesheetPropertyParser : public AbstractPropertyParser { +private: + String image_source; + SpriteDefinitionList sprite_definitions; + + PropertyDictionary properties; + PropertySpecification specification; + PropertyId id_rx, id_ry, id_rw, id_rh; + ShorthandId id_rectangle; + +public: + SpritesheetPropertyParser() : specification(4, 1) + { + id_rx = specification.RegisterProperty("rectangle-x", "", false, false).AddParser("length").GetId(); + id_ry = specification.RegisterProperty("rectangle-y", "", false, false).AddParser("length").GetId(); + id_rw = specification.RegisterProperty("rectangle-w", "", false, false).AddParser("length").GetId(); + id_rh = specification.RegisterProperty("rectangle-h", "", false, false).AddParser("length").GetId(); + id_rectangle = specification.RegisterShorthand("rectangle", "rectangle-x, rectangle-y, rectangle-w, rectangle-h", ShorthandType::FallThrough); + } + + const String& GetImageSource() const + { + return image_source; + } + const SpriteDefinitionList& GetSpriteDefinitions() const + { + return sprite_definitions; + } + + void Clear() { + image_source.clear(); + sprite_definitions.clear(); + } + + bool Parse(const String& name, const String& value) override + { + static const String str_src = "src"; + if (name == str_src) + { + image_source = value; + } + else + { + if (!specification.ParseShorthandDeclaration(properties, id_rectangle, value)) + return false; + + Rectangle rectangle; + if (auto property = properties.GetProperty(id_rx)) + rectangle.x = ComputeAbsoluteLength(*property, 1.f); + if (auto property = properties.GetProperty(id_ry)) + rectangle.y = ComputeAbsoluteLength(*property, 1.f); + if (auto property = properties.GetProperty(id_rw)) + rectangle.width = ComputeAbsoluteLength(*property, 1.f); + if (auto property = properties.GetProperty(id_rh)) + rectangle.height = ComputeAbsoluteLength(*property, 1.f); + + sprite_definitions.emplace_back(name, rectangle); + } + + return true; + } +}; + + + +StyleSheetParser::StyleSheetParser() +{ + line_number = 0; + stream = nullptr; + parse_buffer_pos = 0; +} + +StyleSheetParser::~StyleSheetParser() +{ +} + +static bool IsValidIdentifier(const String& str) +{ + if (str.empty()) + return false; + + for (size_t i = 0; i < str.size(); i++) + { + char c = str[i]; + bool valid = ( + (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || (c == '-') + || (c == '_') + ); + if (!valid) + return false; + } + + return true; +} + + +static void PostprocessKeyframes(KeyframesMap& keyframes_map) +{ + for (auto& keyframes_pair : keyframes_map) + { + Keyframes& keyframes = keyframes_pair.second; + auto& blocks = keyframes.blocks; + auto& property_ids = keyframes.property_ids; + + // Sort keyframes on selector value. + std::sort(blocks.begin(), blocks.end(), [](const KeyframeBlock& a, const KeyframeBlock& b) { return a.normalized_time < b.normalized_time; }); + + // Add all property names specified by any block + if(blocks.size() > 0) property_ids.reserve(blocks.size() * blocks[0].properties.GetNumProperties()); + for(auto& block : blocks) + { + for (auto& property : block.properties.GetProperties()) + property_ids.push_back(property.first); + } + // Remove duplicate property names + std::sort(property_ids.begin(), property_ids.end()); + property_ids.erase(std::unique(property_ids.begin(), property_ids.end()), property_ids.end()); + property_ids.shrink_to_fit(); + } + +} + + +bool StyleSheetParser::ParseKeyframeBlock(KeyframesMap& keyframes_map, const String& identifier, const String& rules, const PropertyDictionary& properties) +{ + if (!IsValidIdentifier(identifier)) + { + Log::Message(Log::LT_WARNING, "Invalid keyframes identifier '%s' at %s:%d", identifier.c_str(), stream_file_name.c_str(), line_number); + return false; + } + if (properties.GetNumProperties() == 0) + return true; + + StringList rule_list; + StringUtilities::ExpandString(rule_list, rules); + + Vector rule_values; + rule_values.reserve(rule_list.size()); + + for (auto rule : rule_list) + { + float value = 0.0f; + int count = 0; + rule = StringUtilities::ToLower(rule); + if (rule == "from") + rule_values.push_back(0.0f); + else if (rule == "to") + rule_values.push_back(1.0f); + else if(sscanf(rule.c_str(), "%f%%%n", &value, &count) == 1) + if(count > 0 && value >= 0.0f && value <= 100.0f) + rule_values.push_back(0.01f * value); + } + + if (rule_values.empty()) + { + Log::Message(Log::LT_WARNING, "Invalid keyframes rule(s) '%s' at %s:%d", rules.c_str(), stream_file_name.c_str(), line_number); + return false; + } + + Keyframes& keyframes = keyframes_map[identifier]; + + for(float selector : rule_values) + { + auto it = std::find_if(keyframes.blocks.begin(), keyframes.blocks.end(), [selector](const KeyframeBlock& keyframe_block) { return Math::AbsoluteValue(keyframe_block.normalized_time - selector) < 0.0001f; }); + if (it == keyframes.blocks.end()) + { + keyframes.blocks.emplace_back(selector); + it = (keyframes.blocks.end() - 1); + } + else + { + // In case of duplicate keyframes, we only use the latest definition as per CSS rules + it->properties = PropertyDictionary(); + } + + it->properties.Import(properties); + } + + return true; +} + +bool StyleSheetParser::ParseDecoratorBlock(const String& at_name, DecoratorSpecificationMap& decorator_map, const StyleSheet& style_sheet, const SharedPtr& source) +{ + StringList name_type; + StringUtilities::ExpandString(name_type, at_name, ':'); + + if (name_type.size() != 2 || name_type[0].empty() || name_type[1].empty()) + { + Log::Message(Log::LT_WARNING, "Decorator syntax error at %s:%d. Use syntax: '@decorator name : type { ... }'.", stream_file_name.c_str(), line_number); + return false; + } + + const String& name = name_type[0]; + String decorator_type = name_type[1]; + + auto it_find = decorator_map.find(name); + if (it_find != decorator_map.end()) + { + Log::Message(Log::LT_WARNING, "Decorator with name '%s' already declared, ignoring decorator at %s:%d.", name.c_str(), stream_file_name.c_str(), line_number); + return false; + } + + // Get the instancer associated with the decorator type + DecoratorInstancer* decorator_instancer = Factory::GetDecoratorInstancer(decorator_type); + PropertyDictionary properties; + + if(!decorator_instancer) + { + // Type is not a declared decorator type, instead, see if it is another decorator name, then we inherit its properties. + auto it = decorator_map.find(decorator_type); + if (it != decorator_map.end()) + { + // Yes, try to retrieve the instancer from the parent type, and add its property values. + decorator_instancer = Factory::GetDecoratorInstancer(it->second.decorator_type); + properties = it->second.properties; + decorator_type = it->second.decorator_type; + } + + // If we still don't have an instancer, we cannot continue. + if (!decorator_instancer) + { + Log::Message(Log::LT_WARNING, "Invalid decorator type '%s' declared at %s:%d.", decorator_type.c_str(), stream_file_name.c_str(), line_number); + return false; + } + } + + const PropertySpecification& property_specification = decorator_instancer->GetPropertySpecification(); + + PropertySpecificationParser parser(properties, property_specification); + if (!ReadProperties(parser)) + return false; + + // Set non-defined properties to their defaults + property_specification.SetPropertyDefaults(properties); + properties.SetSourceOfAllProperties(source); + + SharedPtr decorator = decorator_instancer->InstanceDecorator(decorator_type, properties, DecoratorInstancerInterface(style_sheet)); + if (!decorator) + { + Log::Message(Log::LT_WARNING, "Could not instance decorator of type '%s' declared at %s:%d.", decorator_type.c_str(), stream_file_name.c_str(), line_number); + return false; + } + + decorator_map.emplace(name, DecoratorSpecification{ std::move(decorator_type), std::move(properties), std::move(decorator) }); + + return true; +} + +int StyleSheetParser::Parse(StyleSheetNode* node, Stream* _stream, const StyleSheet& style_sheet, KeyframesMap& keyframes, DecoratorSpecificationMap& decorator_map, SpritesheetList& spritesheet_list, int begin_line_number) +{ + RMLUI_ZoneScoped; + + int rule_count = 0; + line_number = begin_line_number; + stream = _stream; + stream_file_name = StringUtilities::Replace(stream->GetSourceURL().GetURL(), '|', ':'); + + enum class State { Global, AtRuleIdentifier, KeyframeBlock, Invalid }; + State state = State::Global; + + // At-rules given by the following syntax in global space: @identifier name { block } + String at_rule_name; + + // Look for more styles while data is available + while (FillBuffer()) + { + String pre_token_str; + + while (char token = FindToken(pre_token_str, "{@}", true)) + { + switch (state) + { + case State::Global: + { + if (token == '{') + { + const int rule_line_number = (int)line_number; + + // Read the attributes + PropertyDictionary properties; + PropertySpecificationParser parser(properties, StyleSheetSpecification::GetPropertySpecification()); + if (!ReadProperties(parser)) + continue; + + StringList rule_name_list; + StringUtilities::ExpandString(rule_name_list, pre_token_str); + + // Add style nodes to the root of the tree + for (size_t i = 0; i < rule_name_list.size(); i++) + { + auto source = MakeShared(stream_file_name, rule_line_number, rule_name_list[i]); + properties.SetSourceOfAllProperties(source); + ImportProperties(node, rule_name_list[i], properties, rule_count); + } + + rule_count++; + } + else if (token == '@') + { + state = State::AtRuleIdentifier; + } + else + { + Log::Message(Log::LT_WARNING, "Invalid character '%c' found while parsing stylesheet at %s:%d. Trying to proceed.", token, stream_file_name.c_str(), line_number); + } + } + break; + case State::AtRuleIdentifier: + { + if (token == '{') + { + String at_rule_identifier = pre_token_str.substr(0, pre_token_str.find(' ')); + at_rule_name = StringUtilities::StripWhitespace(pre_token_str.substr(at_rule_identifier.size())); + + if (at_rule_identifier == "keyframes") + { + state = State::KeyframeBlock; + } + else if (at_rule_identifier == "decorator") + { + auto source = MakeShared(stream_file_name, (int)line_number, pre_token_str); + ParseDecoratorBlock(at_rule_name, decorator_map, style_sheet, source); + + at_rule_name.clear(); + state = State::Global; + } + else if (at_rule_identifier == "spritesheet") + { + // This is reasonably heavy to initialize, so we make it static + static SpritesheetPropertyParser spritesheet_property_parser; + spritesheet_property_parser.Clear(); + + ReadProperties(spritesheet_property_parser); + + const String& image_source = spritesheet_property_parser.GetImageSource(); + const SpriteDefinitionList& sprite_definitions = spritesheet_property_parser.GetSpriteDefinitions(); + + if (at_rule_name.empty()) + { + Log::Message(Log::LT_WARNING, "No name given for @spritesheet at %s:%d", stream_file_name.c_str(), line_number); + } + else if (sprite_definitions.empty()) + { + Log::Message(Log::LT_WARNING, "Spritesheet with name '%s' has no sprites defined, ignored. At %s:%d", at_rule_name.c_str(), stream_file_name.c_str(), line_number); + } + else if (image_source.empty()) + { + Log::Message(Log::LT_WARNING, "No image source (property 'src') specified for spritesheet '%s'. At %s:%d", at_rule_name.c_str(), stream_file_name.c_str(), line_number); + } + else + { + spritesheet_list.AddSpriteSheet(at_rule_name, image_source, stream_file_name, (int)line_number, sprite_definitions); + } + + spritesheet_property_parser.Clear(); + at_rule_name.clear(); + state = State::Global; + } + else + { + // Invalid identifier, should ignore + at_rule_name.clear(); + state = State::Global; + Log::Message(Log::LT_WARNING, "Invalid at-rule identifier '%s' found in stylesheet at %s:%d", at_rule_identifier.c_str(), stream_file_name.c_str(), line_number); + } + + } + else + { + Log::Message(Log::LT_WARNING, "Invalid character '%c' found while parsing at-rule identifier in stylesheet at %s:%d", token, stream_file_name.c_str(), line_number); + state = State::Invalid; + } + } + break; + case State::KeyframeBlock: + { + if (token == '{') + { + // Each keyframe in keyframes has its own block which is processed here + PropertyDictionary properties; + PropertySpecificationParser parser(properties, StyleSheetSpecification::GetPropertySpecification()); + if(!ReadProperties(parser)) + continue; + + if (!ParseKeyframeBlock(keyframes, at_rule_name, pre_token_str, properties)) + continue; + } + else if (token == '}') + { + at_rule_name.clear(); + state = State::Global; + } + else + { + Log::Message(Log::LT_WARNING, "Invalid character '%c' found while parsing keyframe block in stylesheet at %s:%d", token, stream_file_name.c_str(), line_number); + state = State::Invalid; + } + } + break; + default: + RMLUI_ERROR; + state = State::Invalid; + break; + } + + if (state == State::Invalid) + break; + } + + if (state == State::Invalid) + break; + } + + PostprocessKeyframes(keyframes); + + return rule_count; +} + +bool StyleSheetParser::ParseProperties(PropertyDictionary& parsed_properties, const String& properties) +{ + RMLUI_ASSERT(!stream); + StreamMemory stream_owner((const byte*)properties.c_str(), properties.size()); + stream = &stream_owner; + PropertySpecificationParser parser(parsed_properties, StyleSheetSpecification::GetPropertySpecification()); + bool success = ReadProperties(parser, false); + stream = nullptr; + return success; +} + +StyleSheetNodeListRaw StyleSheetParser::ConstructNodes(StyleSheetNode& root_node, const String& selectors) +{ + const PropertyDictionary empty_properties; + + StringList selector_list; + StringUtilities::ExpandString(selector_list, selectors); + + StyleSheetNodeListRaw leaf_nodes; + + for (const String& selector : selector_list) + { + StyleSheetNode* leaf_node = ImportProperties(&root_node, selector, empty_properties, 0); + + if (leaf_node != &root_node) + leaf_nodes.push_back(leaf_node); + } + + return leaf_nodes; +} + + +bool StyleSheetParser::ReadProperties(AbstractPropertyParser& property_parser, bool require_end_semicolon) +{ + String name; + String value; + + enum ParseState { NAME, VALUE, QUOTE }; + ParseState state = NAME; + + char character; + char previous_character = 0; + while (ReadCharacter(character)) + { + parse_buffer_pos++; + + switch (state) + { + case NAME: + { + if (character == ';') + { + name = StringUtilities::StripWhitespace(name); + if (!name.empty()) + { + Log::Message(Log::LT_WARNING, "Found name with no value while parsing property declaration '%s' at %s:%d", name.c_str(), stream_file_name.c_str(), line_number); + name.clear(); + } + } + else if (character == '}') + { + name = StringUtilities::StripWhitespace(name); + if (!StringUtilities::StripWhitespace(name).empty()) + Log::Message(Log::LT_WARNING, "End of rule encountered while parsing property declaration '%s' at %s:%d", name.c_str(), stream_file_name.c_str(), line_number); + return true; + } + else if (character == ':') + { + name = StringUtilities::StripWhitespace(name); + state = VALUE; + } + else + name += character; + } + break; + + case VALUE: + { + if (character == ';') + { + value = StringUtilities::StripWhitespace(value); + + if (!property_parser.Parse(name, value)) + Log::Message(Log::LT_WARNING, "Syntax error parsing property declaration '%s: %s;' in %s: %d.", name.c_str(), value.c_str(), stream_file_name.c_str(), line_number); + + name.clear(); + value.clear(); + state = NAME; + } + else if (character == '}') + { + Log::Message(Log::LT_WARNING, "End of rule encountered while parsing property declaration '%s: %s;' in %s: %d.", name.c_str(), value.c_str(), stream_file_name.c_str(), line_number); + return true; + } + else + { + value += character; + if (character == '"') + state = QUOTE; + } + } + break; + + case QUOTE: + { + value += character; + if (character == '"' && previous_character != '/') + state = VALUE; + } + break; + } + + previous_character = character; + } + + if (!require_end_semicolon && !name.empty() && !value.empty()) + { + value = StringUtilities::StripWhitespace(value); + + if (!property_parser.Parse(name, value)) + Log::Message(Log::LT_WARNING, "Syntax error parsing property declaration '%s: %s;' in %s: %d.", name.c_str(), value.c_str(), stream_file_name.c_str(), line_number); + } + else if (!name.empty() || !value.empty()) + { + Log::Message(Log::LT_WARNING, "Invalid property declaration '%s':'%s' at %s:%d", name.c_str(), value.c_str(), stream_file_name.c_str(), line_number); + } + + return true; +} + +StyleSheetNode* StyleSheetParser::ImportProperties(StyleSheetNode* node, String rule_name, const PropertyDictionary& properties, int rule_specificity) +{ + StyleSheetNode* leaf_node = node; + + StringList nodes; + + // Find child combinators, the RCSS '>' rule. + size_t i_child = rule_name.find('>'); + while (i_child != String::npos) + { + // So we found one! Next, we want to format the rule such that the '>' is located at the + // end of the left-hand-side node, and that there is a space to the right-hand-side. This ensures that + // the selector is applied to the "parent", and that parent and child are expanded properly below. + size_t i_begin = i_child; + while (i_begin > 0 && rule_name[i_begin - 1] == ' ') + i_begin--; + + const size_t i_end = i_child + 1; + rule_name.replace(i_begin, i_end - i_begin, "> "); + i_child = rule_name.find('>', i_begin + 1); + } + + // Expand each individual node separated by spaces. Don't expand inside parenthesis because of structural selectors. + StringUtilities::ExpandString(nodes, rule_name, ' ', '(', ')', true); + + // Create each node going down the tree + for (size_t i = 0; i < nodes.size(); i++) + { + const String& name = nodes[i]; + + String tag; + String id; + StringList classes; + StringList pseudo_classes; + StructuralSelectorList structural_pseudo_classes; + bool child_combinator = false; + + size_t index = 0; + while (index < name.size()) + { + size_t start_index = index; + size_t end_index = index + 1; + + // Read until we hit the next identifier. + while (end_index < name.size() && + name[end_index] != '#' && + name[end_index] != '.' && + name[end_index] != ':' && + name[end_index] != '>') + end_index++; + + String identifier = name.substr(start_index, end_index - start_index); + if (!identifier.empty()) + { + switch (identifier[0]) + { + case '#': id = identifier.substr(1); break; + case '.': classes.push_back(identifier.substr(1)); break; + case ':': + { + String pseudo_class_name = identifier.substr(1); + StructuralSelector node_selector = StyleSheetFactory::GetSelector(pseudo_class_name); + if (node_selector.selector) + structural_pseudo_classes.push_back(node_selector); + else + pseudo_classes.push_back(pseudo_class_name); + } + break; + case '>': child_combinator = true; break; + + default: if(identifier != "*") tag = identifier; + } + } + + index = end_index; + } + + // Sort the classes and pseudo-classes so they are consistent across equivalent declarations that shuffle the order around. + std::sort(classes.begin(), classes.end()); + std::sort(pseudo_classes.begin(), pseudo_classes.end()); + std::sort(structural_pseudo_classes.begin(), structural_pseudo_classes.end()); + + // Get the named child node. + leaf_node = leaf_node->GetOrCreateChildNode(std::move(tag), std::move(id), std::move(classes), std::move(pseudo_classes), std::move(structural_pseudo_classes), child_combinator); + } + + // Merge the new properties with those already on the leaf node. + leaf_node->ImportProperties(properties, rule_specificity); + + return leaf_node; +} + +char StyleSheetParser::FindToken(String& buffer, const char* tokens, bool remove_token) +{ + buffer.clear(); + char character; + while (ReadCharacter(character)) + { + if (strchr(tokens, character) != nullptr) + { + if (remove_token) + parse_buffer_pos++; + return character; + } + else + { + buffer += character; + parse_buffer_pos++; + } + } + + return 0; +} + +// Attempts to find the next character in the active stream. +bool StyleSheetParser::ReadCharacter(char& buffer) +{ + bool comment = false; + + // Continuously fill the buffer until either we run out of + // stream or we find the requested token + do + { + while (parse_buffer_pos < parse_buffer.size()) + { + if (parse_buffer[parse_buffer_pos] == '\n') + line_number++; + else if (comment) + { + // Check for closing comment + if (parse_buffer[parse_buffer_pos] == '*') + { + parse_buffer_pos++; + if (parse_buffer_pos >= parse_buffer.size()) + { + if (!FillBuffer()) + return false; + } + + if (parse_buffer[parse_buffer_pos] == '/') + comment = false; + } + } + else + { + // Check for an opening comment + if (parse_buffer[parse_buffer_pos] == '/') + { + parse_buffer_pos++; + if (parse_buffer_pos >= parse_buffer.size()) + { + if (!FillBuffer()) + { + buffer = '/'; + parse_buffer = "/"; + return true; + } + } + + if (parse_buffer[parse_buffer_pos] == '*') + comment = true; + else + { + buffer = '/'; + if (parse_buffer_pos == 0) + parse_buffer.insert(parse_buffer_pos, 1, '/'); + else + parse_buffer_pos--; + return true; + } + } + + if (!comment) + { + // If we find a character, return it + buffer = parse_buffer[parse_buffer_pos]; + return true; + } + } + + parse_buffer_pos++; + } + } + while (FillBuffer()); + + return false; +} + +// Fills the internal buffer with more content +bool StyleSheetParser::FillBuffer() +{ + // If theres no data to process, abort + if (stream->IsEOS()) + return false; + + // Read in some data (4092 instead of 4096 to avoid the buffer growing when we have to add back + // a character after a failed comment parse.) + parse_buffer.clear(); + bool read = stream->Read(parse_buffer, 4092) > 0; + parse_buffer_pos = 0; + + return read; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetParser.h b/thirdparty/RmlUi/Source/Core/StyleSheetParser.h new file mode 100644 index 000000000..6de3917c1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetParser.h @@ -0,0 +1,124 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_STYLESHEETPARSER_H +#define RMLUI_CORE_STYLESHEETPARSER_H + +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class PropertyDictionary; +class Stream; +class StyleSheetNode; +class AbstractPropertyParser; +struct PropertySource; +using StyleSheetNodeListRaw = Vector; + +/** + Helper class for parsing a style sheet into its memory representation. + + @author Lloyd Weehuizen + */ + +class StyleSheetParser +{ +public: + StyleSheetParser(); + ~StyleSheetParser(); + + /// Parses the given stream into the style sheet + /// @param node The root node the stream will be parsed into + /// @param stream The stream to read + /// @return The number of parsed rules, or -1 if an error occured. + int Parse(StyleSheetNode* node, Stream* stream, const StyleSheet& style_sheet, KeyframesMap& keyframes, DecoratorSpecificationMap& decorator_map, SpritesheetList& spritesheet_list, int begin_line_number); + + /// Parses the given string into the property dictionary + /// @param parsed_properties The properties dictionary the properties will be read into + /// @param properties The properties to parse + /// @return True if the parse was successful, or false if an error occured. + bool ParseProperties(PropertyDictionary& parsed_properties, const String& properties); + + // Converts a selector query to a tree of nodes. + // @param root_node Node to construct into. + // @param selectors The selector rules as a string value. + // @return The list of leaf nodes in the constructed tree, which are all owned by the root node. + static StyleSheetNodeListRaw ConstructNodes(StyleSheetNode& root_node, const String& selectors); + +private: + // Stream we're parsing from. + Stream* stream; + // Parser memory buffer. + String parse_buffer; + // How far we've read through the buffer. + size_t parse_buffer_pos; + + // The name of the file we're parsing. + String stream_file_name; + // Current line number we're parsing. + size_t line_number; + + // Parses properties from the parse buffer into the dictionary + // @param properties The dictionary to store the properties in + // @param property_specification The specification used to parse the values. Normally the default stylesheet specification, but not for e.g. all at-rules such as decorators. + // @param require_end_semicolon True to require a ';' character after the final property. + bool ReadProperties(AbstractPropertyParser& property_parser, bool require_end_semicolon = true); + + // Import properties into the stylesheet node + // @param node Node to import into + // @param names The names of the nodes + // @param properties The dictionary of properties + // @param rule_specificity The specifity of the rule + // @return The leaf node of the rule + static StyleSheetNode* ImportProperties(StyleSheetNode* node, String rule_name, const PropertyDictionary& properties, int rule_specificity); + + // Attempts to parse a @keyframes block + bool ParseKeyframeBlock(KeyframesMap & keyframes_map, const String & identifier, const String & rules, const PropertyDictionary & properties); + + // Attempts to parse a @decorator block + bool ParseDecoratorBlock(const String& at_name, DecoratorSpecificationMap& decorator_map, const StyleSheet& style_sheet, const SharedPtr& source); + + // Attempts to find one of the given character tokens in the active stream + // If it's found, buffer is filled with all content up until the token + // @param buffer The buffer that receives the content + // @param characters The character tokens to find + // @param remove_token If the token that caused the find to stop should be removed from the stream + char FindToken(String& buffer, const char* tokens, bool remove_token); + + // Attempts to find the next character in the active stream. + // If it's found, buffer is filled with the character + // @param buffer The buffer that receives the character, if read. + bool ReadCharacter(char& buffer); + + // Fill the internal parse buffer + bool FillBuffer(); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/StyleSheetSpecification.cpp b/thirdparty/RmlUi/Source/Core/StyleSheetSpecification.cpp new file mode 100644 index 000000000..a4342ecd2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/StyleSheetSpecification.cpp @@ -0,0 +1,403 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/PropertyIdSet.h" +#include "../../Include/RmlUi/Core/PropertyDefinition.h" +#include "PropertyParserNumber.h" +#include "PropertyParserAnimation.h" +#include "PropertyParserColour.h" +#include "PropertyParserKeyword.h" +#include "PropertyParserString.h" +#include "PropertyParserTransform.h" +#include "PropertyShorthandDefinition.h" +#include "IdNameMap.h" + +namespace Rml { + +static StyleSheetSpecification* instance = nullptr; + + +struct DefaultStyleSheetParsers { + PropertyParserNumber number = PropertyParserNumber(Property::NUMBER); + PropertyParserNumber length = PropertyParserNumber(Property::LENGTH, Property::PX); + PropertyParserNumber length_percent = PropertyParserNumber(Property::LENGTH_PERCENT, Property::PX); + PropertyParserNumber number_length_percent = PropertyParserNumber(Property::NUMBER_LENGTH_PERCENT, Property::PX); + PropertyParserNumber angle = PropertyParserNumber(Property::ANGLE, Property::RAD); + PropertyParserKeyword keyword = PropertyParserKeyword(); + PropertyParserString string = PropertyParserString(); + PropertyParserAnimation animation = PropertyParserAnimation(PropertyParserAnimation::ANIMATION_PARSER); + PropertyParserAnimation transition = PropertyParserAnimation(PropertyParserAnimation::TRANSITION_PARSER); + PropertyParserColour color = PropertyParserColour(); + PropertyParserTransform transform = PropertyParserTransform(); +}; + +StyleSheetSpecification::StyleSheetSpecification() : + // Reserve space for all defined ids and some more for custom properties + properties((size_t)PropertyId::MaxNumIds, 2 * (size_t)ShorthandId::NumDefinedIds) +{ + RMLUI_ASSERT(instance == nullptr); + instance = this; + + default_parsers.reset(new DefaultStyleSheetParsers); +} + +StyleSheetSpecification::~StyleSheetSpecification() +{ + RMLUI_ASSERT(instance == this); + instance = nullptr; +} + +PropertyDefinition& StyleSheetSpecification::RegisterProperty(PropertyId id, const String& property_name, const String& default_value, bool inherited, bool forces_layout) +{ + return properties.RegisterProperty(property_name, default_value, inherited, forces_layout, id); +} + +ShorthandId StyleSheetSpecification::RegisterShorthand(ShorthandId id, const String& shorthand_name, const String& property_names, ShorthandType type) +{ + return properties.RegisterShorthand(shorthand_name, property_names, type, id); +} + +bool StyleSheetSpecification::Initialise() +{ + if (instance == nullptr) + { + new StyleSheetSpecification(); + + instance->RegisterDefaultParsers(); + instance->RegisterDefaultProperties(); + } + + return true; +} + +void StyleSheetSpecification::Shutdown() +{ + if (instance != nullptr) + { + delete instance; + } +} + +// Registers a parser for use in property definitions. +bool StyleSheetSpecification::RegisterParser(const String& parser_name, PropertyParser* parser) +{ + ParserMap::iterator iterator = instance->parsers.find(parser_name); + if (iterator != instance->parsers.end()) + { + Log::Message(Log::LT_WARNING, "Parser with name %s already exists!", parser_name.c_str()); + return false; + } + + instance->parsers[parser_name] = parser; + return true; +} + +// Returns the parser registered with a specific name. +PropertyParser* StyleSheetSpecification::GetParser(const String& parser_name) +{ + ParserMap::iterator iterator = instance->parsers.find(parser_name); + if (iterator == instance->parsers.end()) + return nullptr; + + return (*iterator).second; +} + +// Registers a property with a new definition. +PropertyDefinition& StyleSheetSpecification::RegisterProperty(const String& property_name, const String& default_value, bool inherited, bool forces_layout) +{ + RMLUI_ASSERTMSG((size_t)instance->properties.property_map->GetId(property_name) < (size_t)PropertyId::FirstCustomId, "Custom property name matches an internal property, please make a unique name for the given property."); + return instance->RegisterProperty(PropertyId::Invalid, property_name, default_value, inherited, forces_layout); +} + +// Returns a property definition. +const PropertyDefinition* StyleSheetSpecification::GetProperty(const String& property_name) +{ + return instance->properties.GetProperty(property_name); +} + +const PropertyDefinition* StyleSheetSpecification::GetProperty(PropertyId id) +{ + return instance->properties.GetProperty(id); +} + +const PropertyIdSet& StyleSheetSpecification::GetRegisteredProperties() +{ + return instance->properties.GetRegisteredProperties(); +} + +const PropertyIdSet & StyleSheetSpecification::GetRegisteredInheritedProperties() +{ + return instance->properties.GetRegisteredInheritedProperties(); +} + +const PropertyIdSet& StyleSheetSpecification::GetRegisteredPropertiesForcingLayout() +{ + return instance->properties.GetRegisteredPropertiesForcingLayout(); +} + +// Registers a shorthand property definition. +ShorthandId StyleSheetSpecification::RegisterShorthand(const String& shorthand_name, const String& property_names, ShorthandType type) +{ + RMLUI_ASSERTMSG(instance->properties.property_map->GetId(shorthand_name) == PropertyId::Invalid, "Custom shorthand name matches a property name, please make a unique name."); + RMLUI_ASSERTMSG((size_t)instance->properties.shorthand_map->GetId(shorthand_name) < (size_t)ShorthandId::FirstCustomId, "Custom shorthand name matches an internal shorthand, please make a unique name for the given shorthand property."); + return instance->properties.RegisterShorthand(shorthand_name, property_names, type); +} + +// Returns a shorthand definition. +const ShorthandDefinition* StyleSheetSpecification::GetShorthand(const String& shorthand_name) +{ + return instance->properties.GetShorthand(shorthand_name); +} + +const ShorthandDefinition* StyleSheetSpecification::GetShorthand(ShorthandId id) +{ + return instance->properties.GetShorthand(id); +} + +// Parses a property declaration, setting any parsed and validated properties on the given dictionary. +bool StyleSheetSpecification::ParsePropertyDeclaration(PropertyDictionary& dictionary, const String& property_name, const String& property_value) +{ + return instance->properties.ParsePropertyDeclaration(dictionary, property_name, property_value); +} + +PropertyId StyleSheetSpecification::GetPropertyId(const String& property_name) +{ + return instance->properties.property_map->GetId(property_name); +} + +ShorthandId StyleSheetSpecification::GetShorthandId(const String& shorthand_name) +{ + return instance->properties.shorthand_map->GetId(shorthand_name); +} + +const String& StyleSheetSpecification::GetPropertyName(PropertyId id) +{ + return instance->properties.property_map->GetName(id); +} + +const String& StyleSheetSpecification::GetShorthandName(ShorthandId id) +{ + return instance->properties.shorthand_map->GetName(id); +} + +PropertyIdSet StyleSheetSpecification::GetShorthandUnderlyingProperties(ShorthandId id) +{ + PropertyIdSet result; + const ShorthandDefinition* shorthand = instance->properties.GetShorthand(id); + if (!shorthand) + return result; + + for (auto& item : shorthand->items) + { + if (item.type == ShorthandItemType::Property) + { + result.Insert(item.property_id); + } + else if (item.type == ShorthandItemType::Shorthand) + { + // When we have a shorthand pointing to another shorthands, call us recursively. Add the union of the previous result and new properties. + result |= GetShorthandUnderlyingProperties(item.shorthand_id); + } + } + return result; +} + +const PropertySpecification& StyleSheetSpecification::GetPropertySpecification() +{ + return instance->properties; +} + +// Registers RmlUi's default parsers. +void StyleSheetSpecification::RegisterDefaultParsers() +{ + RegisterParser("number", &default_parsers->number); + RegisterParser("length", &default_parsers->length); + RegisterParser("length_percent", &default_parsers->length_percent); + RegisterParser("number_length_percent", &default_parsers->number_length_percent); + RegisterParser("angle", &default_parsers->angle); + RegisterParser("keyword", &default_parsers->keyword); + RegisterParser("string", &default_parsers->string); + RegisterParser("animation", &default_parsers->animation); + RegisterParser("transition", &default_parsers->transition); + RegisterParser("color", &default_parsers->color); + RegisterParser("transform", &default_parsers->transform); +} + + +// Registers RmlUi's default style properties. +void StyleSheetSpecification::RegisterDefaultProperties() +{ + /* + Style property specifications (ala RCSS). + + Note: Whenever keywords or default values are changed, make sure its computed value is + changed correspondingly, see `ComputedValues.h`. + + When adding new properties, it may be desirable to add it to the computed values as well. + Then, make sure to resolve it as appropriate in `ElementStyle.cpp`. + + */ + + RegisterProperty(PropertyId::MarginTop, "margin-top", "0px", false, true) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::MarginRight, "margin-right", "0px", false, true) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::MarginBottom, "margin-bottom", "0px", false, true) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::MarginLeft, "margin-left", "0px", false, true) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterShorthand(ShorthandId::Margin, "margin", "margin-top, margin-right, margin-bottom, margin-left", ShorthandType::Box); + + RegisterProperty(PropertyId::PaddingTop, "padding-top", "0px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::PaddingRight, "padding-right", "0px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::PaddingBottom, "padding-bottom", "0px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::PaddingLeft, "padding-left", "0px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterShorthand(ShorthandId::Padding, "padding", "padding-top, padding-right, padding-bottom, padding-left", ShorthandType::Box); + + RegisterProperty(PropertyId::BorderTopWidth, "border-top-width", "0px", false, true).AddParser("length"); + RegisterProperty(PropertyId::BorderRightWidth, "border-right-width", "0px", false, true).AddParser("length"); + RegisterProperty(PropertyId::BorderBottomWidth, "border-bottom-width", "0px", false, true).AddParser("length"); + RegisterProperty(PropertyId::BorderLeftWidth, "border-left-width", "0px", false, true).AddParser("length"); + RegisterShorthand(ShorthandId::BorderWidth, "border-width", "border-top-width, border-right-width, border-bottom-width, border-left-width", ShorthandType::Box); + + RegisterProperty(PropertyId::BorderTopColor, "border-top-color", "black", false, false).AddParser("color"); + RegisterProperty(PropertyId::BorderRightColor, "border-right-color", "black", false, false).AddParser("color"); + RegisterProperty(PropertyId::BorderBottomColor, "border-bottom-color", "black", false, false).AddParser("color"); + RegisterProperty(PropertyId::BorderLeftColor, "border-left-color", "black", false, false).AddParser("color"); + RegisterShorthand(ShorthandId::BorderColor, "border-color", "border-top-color, border-right-color, border-bottom-color, border-left-color", ShorthandType::Box); + + RegisterShorthand(ShorthandId::BorderTop, "border-top", "border-top-width, border-top-color", ShorthandType::FallThrough); + RegisterShorthand(ShorthandId::BorderRight, "border-right", "border-right-width, border-right-color", ShorthandType::FallThrough); + RegisterShorthand(ShorthandId::BorderBottom, "border-bottom", "border-bottom-width, border-bottom-color", ShorthandType::FallThrough); + RegisterShorthand(ShorthandId::BorderLeft, "border-left", "border-left-width, border-left-color", ShorthandType::FallThrough); + RegisterShorthand(ShorthandId::Border, "border", "border-top, border-right, border-bottom, border-left", ShorthandType::RecursiveRepeat); + + RegisterProperty(PropertyId::Display, "display", "inline", false, true).AddParser("keyword", "none, block, inline, inline-block"); + RegisterProperty(PropertyId::Position, "position", "static", false, true).AddParser("keyword", "static, relative, absolute, fixed"); + RegisterProperty(PropertyId::Top, "top", "auto", false, false) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockHeight); + RegisterProperty(PropertyId::Right, "right", "auto", false, false) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::Bottom, "bottom", "auto", false, false) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockHeight); + RegisterProperty(PropertyId::Left, "left", "auto", false, false) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + + RegisterProperty(PropertyId::Float, "float", "none", false, true).AddParser("keyword", "none, left, right"); + RegisterProperty(PropertyId::Clear, "clear", "none", false, true).AddParser("keyword", "none, left, right, both"); + + RegisterProperty(PropertyId::ZIndex, "z-index", "auto", false, false) + .AddParser("keyword", "auto") + .AddParser("number"); + + RegisterProperty(PropertyId::Width, "width", "auto", false, true) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::MinWidth, "min-width", "0px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + RegisterProperty(PropertyId::MaxWidth, "max-width", "-1px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockWidth); + + RegisterProperty(PropertyId::Height, "height", "auto", false, true) + .AddParser("keyword", "auto") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockHeight); + RegisterProperty(PropertyId::MinHeight, "min-height", "0px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockHeight); + RegisterProperty(PropertyId::MaxHeight, "max-height", "-1px", false, true).AddParser("length_percent").SetRelativeTarget(RelativeTarget::ContainingBlockHeight); + + RegisterProperty(PropertyId::LineHeight, "line-height", "1.2", true, true).AddParser("number_length_percent").SetRelativeTarget(RelativeTarget::FontSize); + RegisterProperty(PropertyId::VerticalAlign, "vertical-align", "baseline", false, true) + .AddParser("keyword", "baseline, middle, sub, super, text-top, text-bottom, top, bottom") + .AddParser("length_percent").SetRelativeTarget(RelativeTarget::LineHeight); + + RegisterProperty(PropertyId::OverflowX, "overflow-x", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll"); + RegisterProperty(PropertyId::OverflowY, "overflow-y", "visible", false, true).AddParser("keyword", "visible, hidden, auto, scroll"); + RegisterShorthand(ShorthandId::Overflow, "overflow", "overflow-x, overflow-y", ShorthandType::Replicate); + RegisterProperty(PropertyId::Clip, "clip", "auto", true, false).AddParser("keyword", "auto, none").AddParser("number"); + RegisterProperty(PropertyId::Visibility, "visibility", "visible", false, false).AddParser("keyword", "visible, hidden"); + + // Need some work on this if we are to include images. + RegisterProperty(PropertyId::BackgroundColor, "background-color", "transparent", false, false).AddParser("color"); + RegisterShorthand(ShorthandId::Background, "background", "background-color", ShorthandType::FallThrough); + + RegisterProperty(PropertyId::Color, "color", "white", true, false).AddParser("color"); + + RegisterProperty(PropertyId::ImageColor, "image-color", "white", false, false).AddParser("color"); + RegisterProperty(PropertyId::Opacity, "opacity", "1", true, false).AddParser("number"); + + RegisterProperty(PropertyId::FontFamily, "font-family", "", true, true).AddParser("string"); + RegisterProperty(PropertyId::FontStyle, "font-style", "normal", true, true).AddParser("keyword", "normal, italic"); + RegisterProperty(PropertyId::FontWeight, "font-weight", "normal", true, true).AddParser("keyword", "normal, bold"); + RegisterProperty(PropertyId::FontSize, "font-size", "12px", true, true).AddParser("length").AddParser("length_percent").SetRelativeTarget(RelativeTarget::ParentFontSize); + RegisterShorthand(ShorthandId::Font, "font", "font-style, font-weight, font-size, font-family", ShorthandType::FallThrough); + + RegisterProperty(PropertyId::TextAlign, "text-align", "left", true, true).AddParser("keyword", "left, right, center, justify"); + RegisterProperty(PropertyId::TextDecoration, "text-decoration", "none", true, false).AddParser("keyword", "none, underline, overline, line-through"); + RegisterProperty(PropertyId::TextTransform, "text-transform", "none", true, true).AddParser("keyword", "none, capitalize, uppercase, lowercase"); + RegisterProperty(PropertyId::WhiteSpace, "white-space", "normal", true, true).AddParser("keyword", "normal, pre, nowrap, pre-wrap, pre-line"); + + RegisterProperty(PropertyId::Cursor, "cursor", "", true, false).AddParser("string"); + + // Functional property specifications. + RegisterProperty(PropertyId::Drag, "drag", "none", false, false).AddParser("keyword", "none, drag, drag-drop, block, clone"); + RegisterProperty(PropertyId::TabIndex, "tab-index", "none", false, false).AddParser("keyword", "none, auto"); + RegisterProperty(PropertyId::Focus, "focus", "auto", true, false).AddParser("keyword", "none, auto"); + RegisterProperty(PropertyId::ScrollbarMargin, "scrollbar-margin", "0", false, false).AddParser("length"); + RegisterProperty(PropertyId::PointerEvents, "pointer-events", "auto", true, false).AddParser("keyword", "none, auto"); + + // Perspective and Transform specifications + RegisterProperty(PropertyId::Perspective, "perspective", "none", false, false).AddParser("keyword", "none").AddParser("length"); + RegisterProperty(PropertyId::PerspectiveOriginX, "perspective-origin-x", "50%", false, false).AddParser("keyword", "left, center, right").AddParser("length_percent"); + RegisterProperty(PropertyId::PerspectiveOriginY, "perspective-origin-y", "50%", false, false).AddParser("keyword", "top, center, bottom").AddParser("length_percent"); + RegisterShorthand(ShorthandId::PerspectiveOrigin, "perspective-origin", "perspective-origin-x, perspective-origin-y", ShorthandType::FallThrough); + RegisterProperty(PropertyId::Transform, "transform", "none", false, false).AddParser("transform"); + RegisterProperty(PropertyId::TransformOriginX, "transform-origin-x", "50%", false, false).AddParser("keyword", "left, center, right").AddParser("length_percent"); + RegisterProperty(PropertyId::TransformOriginY, "transform-origin-y", "50%", false, false).AddParser("keyword", "top, center, bottom").AddParser("length_percent"); + RegisterProperty(PropertyId::TransformOriginZ, "transform-origin-z", "0", false, false).AddParser("length"); + RegisterShorthand(ShorthandId::TransformOrigin, "transform-origin", "transform-origin-x, transform-origin-y, transform-origin-z", ShorthandType::FallThrough); + + RegisterProperty(PropertyId::Transition, "transition", "none", false, false).AddParser("transition"); + RegisterProperty(PropertyId::Animation, "animation", "none", false, false).AddParser("animation"); + + RegisterProperty(PropertyId::Decorator, "decorator", "", false, false).AddParser("string"); + RegisterProperty(PropertyId::FontEffect, "font-effect", "", true, false).AddParser("string"); + + // Rare properties (not added to computed values) + RegisterProperty(PropertyId::FillImage, "fill-image", "", false, false).AddParser("string"); + + instance->properties.property_map->AssertAllInserted(PropertyId::NumDefinedIds); + instance->properties.shorthand_map->AssertAllInserted(ShorthandId::NumDefinedIds); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/SystemInterface.cpp b/thirdparty/RmlUi/Source/Core/SystemInterface.cpp new file mode 100644 index 000000000..f91ee5f19 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/SystemInterface.cpp @@ -0,0 +1,143 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/SystemInterface.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/URL.h" + +#ifdef RMLUI_PLATFORM_WIN32 +#include +#endif + +namespace Rml { + +static String clipboard_text; + +SystemInterface::SystemInterface() +{ +} + +SystemInterface::~SystemInterface() +{ +} + +#ifdef RMLUI_PLATFORM_WIN32 +bool SystemInterface::LogMessage(Log::Type logtype, const String& message) +{ + // By default we just send a platform message + if (logtype == Log::LT_ASSERT) + { + String message_user = CreateString(1024, "%s\nWould you like to interrupt execution?", message.c_str()); + + // Return TRUE if the user presses NO (continue execution) + return (IDNO == MessageBoxA(nullptr, message_user.c_str(), "Assertion Failure", MB_YESNO | MB_ICONSTOP | MB_DEFBUTTON2 | MB_TASKMODAL)); + } + else + { + OutputDebugStringA(message.c_str()); + OutputDebugStringA("\r\n"); + } + return true; +} +#else +bool SystemInterface::LogMessage(Log::Type /*logtype*/, const String& message) +{ + fprintf(stderr,"%s\n", message.c_str()); + return true; +} +#endif + +void SystemInterface::SetMouseCursor(const String& /*cursor_name*/) +{ +} + +void SystemInterface::SetClipboardText(const String& text) +{ + // The default implementation will only copy and paste within the application + clipboard_text = text; +} + +void SystemInterface::GetClipboardText(String& text) +{ + text = clipboard_text; +} + +int SystemInterface::TranslateString(String& translated, const String& input) +{ + translated = input; + return 0; +} + +// Joins the path of an RML or RCSS file with the path of a resource specified within the file. +void SystemInterface::JoinPath(String& translated_path, const String& document_path, const String& path) +{ + // If the path is absolute, strip the leading / and return it. + if (path.size() > 0 && path[0] == '/') + { + translated_path = path.substr(1); + return; + } + + // If the path is a Windows-style absolute path, return it directly. + size_t drive_pos = path.find(':'); + size_t slash_pos = Math::Min(path.find('/'), path.find('\\')); + if (drive_pos != String::npos && + drive_pos < slash_pos) + { + translated_path = path; + return; + } + + using StringUtilities::Replace; + + // Strip off the referencing document name. + translated_path = document_path; + translated_path = Replace(translated_path, '\\', '/'); + size_t file_start = translated_path.rfind('/'); + if (file_start != String::npos) + translated_path.resize(file_start + 1); + else + translated_path.clear(); + + // Append the paths and send through URL to removing any '..'. + URL url(Replace(translated_path, ':', '|') + Replace(path, '\\', '/')); + translated_path = Replace(url.GetPathedFileName(), '|', ':'); +} + +// Activate keyboard (for touchscreen devices) +void SystemInterface::ActivateKeyboard() +{ +} + +// Deactivate keyboard (for touchscreen devices) +void SystemInterface::DeactivateKeyboard() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Template.cpp b/thirdparty/RmlUi/Source/Core/Template.cpp new file mode 100644 index 000000000..163e3b28b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Template.cpp @@ -0,0 +1,138 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Template.h" +#include "XMLParseTools.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/XMLParser.h" +#include + +namespace Rml { + +Template::Template() +{ +} + +Template::~Template() +{ +} + +const String& Template::GetName() const +{ + return name; +} + +bool Template::Load(Stream* stream) +{ + // Load the entire template into memory so we can pull out + // the header and body tags + String buffer; + stream->Read(buffer, stream->Length()); + + // Pull out the header + const char* head_start = XMLParseTools::FindTag("head", buffer.c_str()); + if (!head_start) + return false; + + const char* head_end = XMLParseTools::FindTag("head", head_start, true); + if (!head_end) + return false; + // Advance to the end of the tag + head_end = strchr(head_end, '>') + 1; + + // Pull out the body + const char* body_start = XMLParseTools::FindTag("body", head_end); + if (!body_start) + return false; + + const char* body_end = XMLParseTools::FindTag("body", body_start, true); + if (!body_end) + return false; + // Advance to the end of the tag + body_end = strchr(body_end, '>') + 1; + + // Find the RML tag, skip over it and read the attributes, + // storing the ones we're interested in. + String attribute_name; + String attribute_value; + const char* ptr = XMLParseTools::FindTag("template", buffer.c_str()); + if (!ptr) + return false; + + while (XMLParseTools::ReadAttribute(++ptr, attribute_name, attribute_value)) + { + if (attribute_name == "name") + name = attribute_value; + if (attribute_name == "content") + content = attribute_value; + } + + // Create a stream around the header, parse it and store it + auto header_stream = MakeUnique((const byte*) head_start,head_end - head_start); + header_stream->SetSourceURL(stream->GetSourceURL()); + + XMLParser parser(nullptr); + parser.Parse(header_stream.get()); + + header_stream.reset(); + + header = *parser.GetDocumentHeader(); + + // Store the body in stream form + body = MakeUnique(body_end - body_start); + body->SetSourceURL(stream->GetSourceURL()); + body->PushBack(body_start, body_end - body_start); + + return true; +} + +Element* Template::ParseTemplate(Element* element) +{ + body->Seek(0, SEEK_SET); + + XMLParser parser(element); + parser.Parse(body.get()); + + // If theres an inject attribute on the template, + // attempt to find the required element + if (!content.empty()) + { + Element* content_element = ElementUtilities::GetElementById(element, content); + if (content_element) + element = content_element; + } + + return element; +} + +const DocumentHeader* Template::GetHeader() +{ + return &header; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Template.h b/thirdparty/RmlUi/Source/Core/Template.h new file mode 100644 index 000000000..d86741856 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Template.h @@ -0,0 +1,73 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TEMPLATE_H +#define RMLUI_CORE_TEMPLATE_H + +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "DocumentHeader.h" + +namespace Rml { + +class Element; + +/** + Contains a RML template. The Header is stored in parsed form, body in an unparsed stream. + + @author Lloyd Weehuizen + */ + +class Template +{ +public: + Template(); + ~Template(); + + /// Load a template from the given stream + bool Load(Stream* stream); + + /// Get the ID of the template + const String& GetName() const; + + /// Parse the template into the given element + /// @param element Element to parse into + /// @returns The element to continue the parse from + Element* ParseTemplate(Element* element); + + /// Get the template header + const DocumentHeader* GetHeader(); + +private: + String name; + String content; + DocumentHeader header; + UniquePtr body; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TemplateCache.cpp b/thirdparty/RmlUi/Source/Core/TemplateCache.cpp new file mode 100644 index 000000000..b93ba75c7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TemplateCache.cpp @@ -0,0 +1,124 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TemplateCache.h" +#include "StreamFile.h" +#include "Template.h" +#include "../../Include/RmlUi/Core/Log.h" + +namespace Rml { + +static TemplateCache* instance = nullptr; + +TemplateCache::TemplateCache() +{ + RMLUI_ASSERT(instance == nullptr); + instance = this; +} + +TemplateCache::~TemplateCache() +{ + for (Templates::iterator itr = instance->templates.begin(); itr != instance->templates.end(); ++itr) + { + delete (*itr).second; + } + + instance = nullptr; +} + +bool TemplateCache::Initialise() +{ + new TemplateCache(); + + return true; +} + +void TemplateCache::Shutdown() +{ + delete instance; +} + +Template* TemplateCache::LoadTemplate(const String& name) +{ + // Check if the template is already loaded + Templates::iterator itr = instance->templates.find(name); + if (itr != instance->templates.end()) + return (*itr).second; + + // Nope, we better load it + Template* new_template = nullptr; + auto stream = MakeUnique(); + if (stream->Open(name)) + { + new_template = new Template(); + if (!new_template->Load(stream.get())) + { + Log::Message(Log::LT_ERROR, "Failed to load template %s.", name.c_str()); + delete new_template; + new_template = nullptr; + } + else if (new_template->GetName().empty()) + { + Log::Message(Log::LT_ERROR, "Failed to load template %s, template is missing its name.", name.c_str()); + delete new_template; + new_template = nullptr; + } + else + { + instance->templates[name] = new_template; + instance->template_ids[new_template->GetName()] = new_template; + } + } + else + { + Log::Message(Log::LT_ERROR, "Failed to open template file %s.", name.c_str()); + } + + return new_template; +} + +Template* TemplateCache::GetTemplate(const String& name) +{ + // Check if the template is already loaded + Templates::iterator itr = instance->template_ids.find(name); + if (itr != instance->template_ids.end()) + return (*itr).second; + + return nullptr; +} + +void TemplateCache::Clear() +{ + for (Templates::iterator i = instance->templates.begin(); i != instance->templates.end(); ++i) + delete (*i).second; + + instance->templates.clear(); + instance->template_ids.clear(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TemplateCache.h b/thirdparty/RmlUi/Source/Core/TemplateCache.h new file mode 100644 index 000000000..bf1124ad9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TemplateCache.h @@ -0,0 +1,69 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TEMPLATECACHE_H +#define RMLUI_CORE_TEMPLATECACHE_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class Template; + +/** + Manages requests for loading templates, caching as it goes. + + @author Lloyd Weehuizen + */ + +class TemplateCache +{ +public: + /// Initialisation and Shutdown + static bool Initialise(); + static void Shutdown(); + + /// Load the named template from the given path, if its already loaded get the cached copy + static Template* LoadTemplate(const String& path); + /// Get the template by id + static Template* GetTemplate(const String& id); + + /// Clear the template cache. + static void Clear(); + +private: + TemplateCache(); + ~TemplateCache(); + + using Templates = UnorderedMap; + Templates templates; + Templates template_ids; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Texture.cpp b/thirdparty/RmlUi/Source/Core/Texture.cpp new file mode 100644 index 000000000..01c5a11f8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Texture.cpp @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Texture.h" +#include "TextureDatabase.h" +#include "TextureResource.h" + +namespace Rml { + +// Attempts to load a texture. +void Texture::Set(const String& source, const String& source_path) +{ + resource = TextureDatabase::Fetch(source, source_path); +} + +void Texture::Set(const String& name, const TextureCallback& callback) +{ + resource = MakeShared(); + resource->Set(name, callback); +} + +// Returns the texture's source name. This is usually the name of the file the texture was loaded from. +const String& Texture::GetSource() const +{ + static String empty_string; + if (!resource) + return empty_string; + + return resource->GetSource(); +} + +// Returns the texture's handle. +TextureHandle Texture::GetHandle(RenderInterface* render_interface) const +{ + if (!resource) + return 0; + + return resource->GetHandle(render_interface); +} + +// Returns the texture's dimensions. +Vector2i Texture::GetDimensions(RenderInterface* render_interface) const +{ + if (!resource) + return Vector2i(0, 0); + + return resource->GetDimensions(render_interface); +} + +bool Texture::operator==(const Texture& other) const +{ + return resource == other.resource; +} + +Texture::operator bool() const +{ + return static_cast(resource); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureDatabase.cpp b/thirdparty/RmlUi/Source/Core/TextureDatabase.cpp new file mode 100644 index 000000000..4b45a449e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureDatabase.cpp @@ -0,0 +1,108 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TextureDatabase.h" +#include "TextureResource.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" + +namespace Rml { + +static TextureDatabase* texture_database = nullptr; + +TextureDatabase::TextureDatabase() +{ + RMLUI_ASSERT(texture_database == nullptr); + texture_database = this; +} + +TextureDatabase::~TextureDatabase() +{ + RMLUI_ASSERT(texture_database == this); + texture_database = nullptr; +} + +void TextureDatabase::Initialise() +{ + new TextureDatabase(); +} + +void TextureDatabase::Shutdown() +{ + delete texture_database; +} + +// If the requested texture is already in the database, it will be returned with an extra reference count. If not, it +// will be loaded through the application's render interface. +SharedPtr TextureDatabase::Fetch(const String& source, const String& source_directory) +{ + String path; + if (source.size() > 0 && source[0] == '?') + path = source; + else + GetSystemInterface()->JoinPath(path, StringUtilities::Replace(source_directory, '|', ':'), source); + + TextureMap::iterator iterator = texture_database->textures.find(path); + if (iterator != texture_database->textures.end()) + { + return iterator->second; + } + + auto resource = MakeShared(); + resource->Set(path); + + texture_database->textures[resource->GetSource()] = resource; + return resource; +} + +void TextureDatabase::AddCallbackTexture(TextureResource* texture) +{ + if (texture_database) + texture_database->callback_textures.insert(texture); +} + +void TextureDatabase::RemoveCallbackTexture(TextureResource* texture) +{ + if (texture_database) + texture_database->callback_textures.erase(texture); +} + +void TextureDatabase::ReleaseTextures(RenderInterface* render_interface) +{ + if (texture_database) + { + for (const auto& texture : texture_database->textures) + texture.second->Release(render_interface); + + for (const auto& texture : texture_database->callback_textures) + texture->Release(render_interface); + } +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureDatabase.h b/thirdparty/RmlUi/Source/Core/TextureDatabase.h new file mode 100644 index 000000000..92b0c8d21 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureDatabase.h @@ -0,0 +1,76 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TEXTUREDATABASE_H +#define RMLUI_CORE_TEXTUREDATABASE_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class RenderInterface; +class TextureResource; + +/** + @author Peter Curry + */ + +class TextureDatabase +{ +public: + static void Initialise(); + static void Shutdown(); + + /// Fetch a texture resource from file. + /// If the requested texture is already in the database, it will be returned with an extra + /// reference count. If not, it will be loaded through the application's render interface. + static SharedPtr Fetch(const String& source, const String& source_directory); + + /// Release all textures bound through a render interface. + /// Pass nullptr to release all textures in the database. + static void ReleaseTextures(RenderInterface* render_interface = nullptr); + + /// Adds a texture resource with a callback function and stores it as a weak (raw) pointer in the database. + static void AddCallbackTexture(TextureResource* texture); + + /// Removes a callback texture from the database. + static void RemoveCallbackTexture(TextureResource* texture); + +private: + TextureDatabase(); + ~TextureDatabase(); + + using TextureMap = UnorderedMap< String, SharedPtr >; + TextureMap textures; + + using CallbackTextureMap = UnorderedSet< TextureResource* >; + CallbackTextureMap callback_textures; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TextureLayout.cpp b/thirdparty/RmlUi/Source/Core/TextureLayout.cpp new file mode 100644 index 000000000..d6af24939 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayout.cpp @@ -0,0 +1,109 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TextureLayout.h" +#include "TextureLayoutRectangle.h" +#include "TextureLayoutTexture.h" +#include + +namespace Rml { + +struct RectangleSort +{ + bool operator()(const TextureLayoutRectangle& lhs, const TextureLayoutRectangle& rhs) const + { + return lhs.GetDimensions().y > rhs.GetDimensions().y; + } +}; + +TextureLayout::TextureLayout() +{ +} + +TextureLayout::~TextureLayout() +{ +} + +// Adds a rectangle to the list of rectangles to be laid out. +void TextureLayout::AddRectangle(int id, const Vector2i& dimensions) +{ + rectangles.push_back(TextureLayoutRectangle(id, dimensions)); +} + +// Returns one of the layout's rectangles. +TextureLayoutRectangle& TextureLayout::GetRectangle(int index) +{ + RMLUI_ASSERT(index >= 0); + RMLUI_ASSERT(index < GetNumRectangles()); + + return rectangles[index]; +} + +// Returns the number of rectangles in the layout. +int TextureLayout::GetNumRectangles() const +{ + return (int) rectangles.size(); +} + +// Returns one of the layout's textures. +TextureLayoutTexture& TextureLayout::GetTexture(int index) +{ + RMLUI_ASSERT(index >= 0); + RMLUI_ASSERT(index < GetNumTextures()); + + return textures[index]; +} + +// Returns the number of textures in the layout. +int TextureLayout::GetNumTextures() const +{ + return (int) textures.size(); +} + +// Attempts to generate an efficient texture layout for the rectangles. +bool TextureLayout::GenerateLayout(int max_texture_dimensions) +{ + // Sort the rectangles by height. + std::sort(rectangles.begin(), rectangles.end(), RectangleSort()); + + int num_placed_rectangles = 0; + while (num_placed_rectangles != GetNumRectangles()) + { + TextureLayoutTexture texture; + int texture_size = texture.Generate(*this, max_texture_dimensions); + if (texture_size == 0) + return false; + + textures.push_back(texture); + num_placed_rectangles += texture_size; + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureLayout.h b/thirdparty/RmlUi/Source/Core/TextureLayout.h new file mode 100644 index 000000000..aed6789e3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayout.h @@ -0,0 +1,86 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef TEXTURELAYOUT_H +#define TEXTURELAYOUT_H + +#include "TextureLayoutRectangle.h" +#include "TextureLayoutTexture.h" + +namespace Rml { + +/** + A texture layout generates and stores a layout of rectangles within a series of textures. It is + used primarily by the font system for generating font textures. + + @author Peter + */ + +class TextureLayout +{ +public: + TextureLayout(); + ~TextureLayout(); + + /// Adds a rectangle to the list of rectangles to be laid out. All rectangles must be added to + /// the layout before the layout is generated. + /// @param[in] id The id of the rectangle; used to identify the rectangle after it has been positioned. + /// @param[in] dimensions The dimensions of the rectangle. + void AddRectangle(int id, const Vector2i& dimensions); + + /// Returns one of the layout's rectangles. + /// @param[in] index The index of the desired rectangle. + /// @return The desired rectangle. + TextureLayoutRectangle& GetRectangle(int index); + /// Returns the number of rectangles in the layout. + /// @return The layout's rectangle count. + int GetNumRectangles() const; + + /// Returns one of the layout's textures. + /// @param[in] index The index of the desired texture. + /// @return The desired texture. + TextureLayoutTexture& GetTexture(int index); + /// Returns the number of textures in the layout. + /// @return The layout's texture count. + int GetNumTextures() const; + + /// Attempts to generate an efficient texture layout for the rectangles. + /// @param[in] max_texture_dimensions The maximum dimensions allowed for any single texture. + /// @return True if the layout was generated successfully, false if not. + bool GenerateLayout(int max_texture_dimensions); + +private: + using RectangleList = Vector< TextureLayoutRectangle >; + using TextureList = Vector< TextureLayoutTexture >; + + TextureList textures; + RectangleList rectangles; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TextureLayoutRectangle.cpp b/thirdparty/RmlUi/Source/Core/TextureLayoutRectangle.cpp new file mode 100644 index 000000000..e9b983224 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayoutRectangle.cpp @@ -0,0 +1,108 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TextureLayoutRectangle.h" + +namespace Rml { + +TextureLayoutRectangle::TextureLayoutRectangle(int _id, const Vector2i& dimensions) : dimensions(dimensions), texture_position(0, 0) +{ + id = _id; + texture_index = -1; + + texture_data = nullptr; + texture_stride = 0; +} + +TextureLayoutRectangle::~TextureLayoutRectangle() +{ +} + +// Returns the rectangle's id. +int TextureLayoutRectangle::GetId() const +{ + return id; +} + +// Returns the rectangle's position; this is only valid if it has been placed. +const Vector2i& TextureLayoutRectangle::GetPosition() const +{ + return texture_position; +} + +// Returns the rectangle's dimensions. +const Vector2i& TextureLayoutRectangle::GetDimensions() const +{ + return dimensions; +} + +// Places the rectangle within a texture. +void TextureLayoutRectangle::Place(int _texture_index, const Vector2i& position) +{ + texture_index = _texture_index; + texture_position = position; +} + +// Unplaces the rectangle. +void TextureLayoutRectangle::Unplace() +{ + texture_index = -1; +} + +// Returns the rectangle's placed state. +bool TextureLayoutRectangle::IsPlaced() const +{ + return texture_index > -1; +} + +// Sets the rectangle's texture data and stride. +void TextureLayoutRectangle::Allocate(byte* _texture_data, int _texture_stride) +{ + texture_data = _texture_data + ((texture_position.y * _texture_stride) + texture_position.x * 4); + texture_stride = _texture_stride; +} + +// Returns the index of the texture this rectangle is placed on. +int TextureLayoutRectangle::GetTextureIndex() +{ + return texture_index; +} + +// Returns the rectangle's allocated texture data. +byte* TextureLayoutRectangle::GetTextureData() +{ + return texture_data; +} + +// Returns the stride of the rectangle's texture data. +int TextureLayoutRectangle::GetTextureStride() const +{ + return texture_stride; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureLayoutRectangle.h b/thirdparty/RmlUi/Source/Core/TextureLayoutRectangle.h new file mode 100644 index 000000000..83073b5d7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayoutRectangle.h @@ -0,0 +1,95 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef TEXTURELAYOUTRECTANGLE_H +#define TEXTURELAYOUTRECTANGLE_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +/** + A texture layout rectangle is an area positioned with a texture layout. + + @author Peter + */ + +class TextureLayoutRectangle +{ +public: + TextureLayoutRectangle(int id, const Vector2i& dimensions); + ~TextureLayoutRectangle(); + + /// Returns the rectangle's id. + /// @return The rectangle's id. + int GetId() const; + /// Returns the rectangle's position; this is only valid if it has been placed. + /// @return The rectangle's position within its texture. + const Vector2i& GetPosition() const; + /// Returns the rectangle's dimensions. + /// @return The rectangle's dimensions. + const Vector2i& GetDimensions() const; + + /// Places the rectangle within a texture. + /// @param[in] texture_index The index of the texture this rectangle is placed on. + /// @param[in] position The position within the texture of this rectangle's top-left corner. + void Place(int texture_index, const Vector2i& position); + /// Unplaces the rectangle. + void Unplace(); + /// Returns the rectangle's placed state. + /// @return True if the rectangle has been placed, false if not. + bool IsPlaced() const; + + /// Sets the rectangle's texture data and stride. + /// @param[in] texture_data The pointer to the top-left corner of the texture's data. + /// @param[in] texture_stride The stride of the texture data, in bytes. + void Allocate(byte* texture_data, int texture_stride); + + /// Returns the index of the texture this rectangle is placed on. + /// @return The texture index. + int GetTextureIndex(); + /// Returns the rectangle's allocated texture data. + /// @return The texture data. + byte* GetTextureData(); + /// Returns the stride of the rectangle's texture data. + /// @return The texture data stride. + int GetTextureStride() const; + +private: + int id; + Vector2i dimensions; + + int texture_index; + Vector2i texture_position; + + byte* texture_data; + int texture_stride; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TextureLayoutRow.cpp b/thirdparty/RmlUi/Source/Core/TextureLayoutRow.cpp new file mode 100644 index 000000000..860c92bbc --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayoutRow.cpp @@ -0,0 +1,108 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TextureLayoutRow.h" +#include "TextureLayout.h" + +namespace Rml { + +TextureLayoutRow::TextureLayoutRow() +{ + height = 0; +} + +TextureLayoutRow::~TextureLayoutRow() +{ +} + +// Attempts to position unplaced rectangles from the layout into this row. +int TextureLayoutRow::Generate(TextureLayout& layout, int max_width, int y) +{ + int width = 1; + int first_unplaced_index = 0; + int placed_rectangles = 0; + + while (width < max_width) + { + // Find the first unplaced rectangle we can fit. + int index; + for (index = first_unplaced_index; index < layout.GetNumRectangles(); ++index) + { + TextureLayoutRectangle& rectangle = layout.GetRectangle(index); + if (!rectangle.IsPlaced()) + { + if (width + rectangle.GetDimensions().x + 1 <= max_width) + break; + } + } + + if (index == layout.GetNumRectangles()) + return placed_rectangles; + + TextureLayoutRectangle& rectangle = layout.GetRectangle(index); + + // Increment the row height if necessary. + height = Math::Max(height, rectangle.GetDimensions().y); + + // Add this glyph onto our list and mark it as placed. + rectangles.push_back(&rectangle); + rectangle.Place(layout.GetNumTextures(), Vector2i(width, y)); + ++placed_rectangles; + + // Increment our width. An extra pixel is added on so the rectangles aren't pushed up + // against each other. This will avoid filtering artifacts. + if (rectangle.GetDimensions().x > 0) + width += rectangle.GetDimensions().x + 1; + + first_unplaced_index = index + 1; + } + + return placed_rectangles; +} + +// Assigns allocated texture data to all rectangles in this row. +void TextureLayoutRow::Allocate(byte* texture_data, int stride) +{ + for (size_t i = 0; i < rectangles.size(); ++i) + rectangles[i]->Allocate(texture_data, stride); +} + +// Returns the height of the row. +int TextureLayoutRow::GetHeight() const +{ + return height; +} + +// Resets the placed status for all of the rectangles within this row. +void TextureLayoutRow::Unplace() +{ + for (size_t i = 0; i < rectangles.size(); ++i) + rectangles[i]->Unplace(); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureLayoutRow.h b/thirdparty/RmlUi/Source/Core/TextureLayoutRow.h new file mode 100644 index 000000000..ff852781a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayoutRow.h @@ -0,0 +1,77 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef TEXTURELAYOUTROW_H +#define TEXTURELAYOUTROW_H + +#include "TextureLayoutRectangle.h" + +namespace Rml { + +class TextureLayout; + +/** + A texture layout row is a single row of rectangles positioned vertically within a texture. + + @author Peter + */ + +class TextureLayoutRow +{ +public: + TextureLayoutRow(); + ~TextureLayoutRow(); + + /// Attempts to position unplaced rectangles from the layout into this row. + /// @param[in] layout The layout to position rectangles from. + /// @param[in] width The maximum width of this row. + /// @param[in] y The y-coordinate of this row. + /// @return The number of placed rectangles. + int Generate(TextureLayout& layout, int width, int y); + + /// Assigns allocated texture data to all rectangles in this row. + /// @param[in] texture_data The pointer to the beginning of the texture's data. + /// @param[in] stride The stride of the texture's surface, in bytes; + void Allocate(byte* texture_data, int stride); + + /// Returns the height of the row. + /// @return The row's height. + int GetHeight() const; + + /// Resets the placed status for all of the rectangles within this row. + void Unplace(); + +private: + using RectangleList = Vector< TextureLayoutRectangle* >; + + int height; + RectangleList rectangles; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TextureLayoutTexture.cpp b/thirdparty/RmlUi/Source/Core/TextureLayoutTexture.cpp new file mode 100644 index 000000000..07a0b1682 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayoutTexture.cpp @@ -0,0 +1,160 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TextureLayoutTexture.h" +#include "TextureDatabase.h" +#include "TextureLayout.h" + +namespace Rml { + +TextureLayoutTexture::TextureLayoutTexture() : dimensions(0, 0) +{} + +TextureLayoutTexture::~TextureLayoutTexture() +{ + // Don't free texture data; freed in the texture loader. +} + +// Returns the texture's dimensions. This is only valid after the texture has been generated. +const Vector2i& TextureLayoutTexture::GetDimensions() const +{ + return dimensions; +} + +// Attempts to position unplaced rectangles from the layout into this texture. +int TextureLayoutTexture::Generate(TextureLayout& layout, int maximum_dimensions) +{ + // Come up with an estimate for how big a texture we need. Calculate the total square pixels + // required by the remaining rectangles to place, square-root it to get the dimensions of the + // smallest texture necessary (under optimal circumstances) and round it up to the nearest + // power of two. + int square_pixels = 0; + int unplaced_rectangles = 0; + for (int i = 0; i < layout.GetNumRectangles(); ++i) + { + const TextureLayoutRectangle& rectangle = layout.GetRectangle(i); + + if (!rectangle.IsPlaced()) + { + int x = rectangle.GetDimensions().x + 1; + int y = rectangle.GetDimensions().y + 1; + + square_pixels += x*y; + ++unplaced_rectangles; + } + } + + int texture_width = Math::RealToInteger(Math::SquareRoot((float) square_pixels)); + + dimensions.y = Math::ToPowerOfTwo(texture_width); + dimensions.x = dimensions.y >> 1; + + dimensions.x = Math::Min(dimensions.x, maximum_dimensions); + dimensions.y = Math::Min(dimensions.y, maximum_dimensions); + + // Now we're layout out the rectangles in the texture. If we don't fit all the rectangles on + // and have room to grow (ie, haven't hit the maximum texture size in both dimensions) then + // we'll have another go with a bigger texture. + int num_placed_rectangles = 0; + for (;;) + { + bool success = true; + int height = 1; + + while (num_placed_rectangles != unplaced_rectangles) + { + TextureLayoutRow row; + int row_size = row.Generate(layout, dimensions.x, height); + if (row_size == 0) + { + success = false; + break; + } + + height += row.GetHeight() + 1; + if (height > dimensions.y) + { + // D'oh! We've exceeded our height boundaries. This row should be unplaced. + row.Unplace(); + success = false; + break; + } + + rows.push_back(row); + num_placed_rectangles += row_size; + } + + // If the rectangles were successfully laid out within the texture limits, we're done. + if (success) + return num_placed_rectangles; + + // Couldn't do it! Increase the texture size, clear the rectangles and try again - unless + // we've hit the maximum texture size, in which case return true if we've placed any + // rectangles (ie, the layout isn't empty). + if (dimensions.y > dimensions.x) + dimensions.x = dimensions.y; + else + { + if (dimensions.y << 1 > maximum_dimensions) + return num_placed_rectangles; + + dimensions.y <<= 1; + } + + // Unplace all of the glyphs we tried to place and have an other crack. + for (size_t i = 0; i < rows.size(); i++) + rows[i].Unplace(); + + rows.clear(); + num_placed_rectangles = 0; + } +} + +// Allocates the texture. +UniquePtr TextureLayoutTexture::AllocateTexture() +{ + // Note: this object does not free this texture data. It is freed in the font texture loader. + UniquePtr texture_data; + + if (dimensions.x > 0 && + dimensions.y > 0) + { + texture_data.reset(new byte[dimensions.x * dimensions.y * 4]); + + // Set the texture to transparent white. + for (int i = 0; i < dimensions.x * dimensions.y; i++) + ((unsigned int*)(texture_data.get()))[i] = 0x00ffffff; + + for (size_t i = 0; i < rows.size(); ++i) + rows[i].Allocate(texture_data.get(), dimensions.x * 4); + } + + return texture_data; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureLayoutTexture.h b/thirdparty/RmlUi/Source/Core/TextureLayoutTexture.h new file mode 100644 index 000000000..5ac64e155 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureLayoutTexture.h @@ -0,0 +1,76 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef TEXTURELAYOUTTEXTURE_H +#define TEXTURELAYOUTTEXTURE_H + +#include "../../Include/RmlUi/Core/Texture.h" +#include "TextureLayoutRow.h" + +namespace Rml { + +class TextureLayout; +class TextureResource; + +/** + A texture layout texture is a single rectangular area which sub-rectangles are placed on within + a complete texture layout. + + @author Peter + */ + +class TextureLayoutTexture +{ +public: + TextureLayoutTexture(); + ~TextureLayoutTexture(); + + /// Returns the texture's dimensions. This is only valid after the texture has been generated. + /// @return The texture's dimensions. + const Vector2i& GetDimensions() const; + + /// Attempts to position unplaced rectangles from the layout into this texture. The size of + /// this texture will be determined by its contents. + /// @param[in] layout The layout to position rectangles from. + /// @param[in] maximum_dimensions The maximum dimensions of this texture. If this is not big enough to place all the rectangles, then as many will be placed as possible. + /// @return The number of placed rectangles. + int Generate(TextureLayout& layout, int maximum_dimensions); + + /// Allocates the texture. + /// @return The allocated texture data. + UniquePtr AllocateTexture(); + +private: + using RowList = Vector< TextureLayoutRow >; + + Vector2i dimensions; + RowList rows; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TextureResource.cpp b/thirdparty/RmlUi/Source/Core/TextureResource.cpp new file mode 100644 index 000000000..82ca312b2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureResource.cpp @@ -0,0 +1,184 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TextureResource.h" +#include "TextureDatabase.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/RenderInterface.h" +#include "../../Include/RmlUi/Core/Profiling.h" + +namespace Rml { + +TextureResource::TextureResource() +{ +} + +TextureResource::~TextureResource() +{ + Reset(); +} + +void TextureResource::Set(const String& _source) +{ + Reset(); + source = _source; +} + +void TextureResource::Set(const String& name, const TextureCallback& callback) +{ + Reset(); + source = name; + texture_callback = MakeUnique(callback); + TextureDatabase::AddCallbackTexture(this); +} + +void TextureResource::Reset() +{ + Release(); + + if (texture_callback) + { + TextureDatabase::RemoveCallbackTexture(this); + texture_callback.reset(); + } + + source.clear(); +} + +// Returns the resource's underlying texture. +TextureHandle TextureResource::GetHandle(RenderInterface* render_interface) +{ + auto texture_iterator = texture_data.find(render_interface); + if (texture_iterator == texture_data.end()) + { + Load(render_interface); + texture_iterator = texture_data.find(render_interface); + } + + return texture_iterator->second.first; +} + +// Returns the dimensions of the resource's texture. +const Vector2i& TextureResource::GetDimensions(RenderInterface* render_interface) +{ + auto texture_iterator = texture_data.find(render_interface); + if (texture_iterator == texture_data.end()) + { + Load(render_interface); + texture_iterator = texture_data.find(render_interface); + } + + return texture_iterator->second.second; +} + +// Returns the resource's source. +const String& TextureResource::GetSource() const +{ + return source; +} + +// Releases the texture's handle. +void TextureResource::Release(RenderInterface* render_interface) +{ + if (!render_interface) + { + for (auto& interface_data_pair : texture_data) + { + TextureHandle handle = interface_data_pair.second.first; + if (handle) + interface_data_pair.first->ReleaseTexture(handle); + } + + texture_data.clear(); + } + else + { + TextureDataMap::iterator texture_iterator = texture_data.find(render_interface); + if (texture_iterator == texture_data.end()) + return; + + TextureHandle handle = texture_iterator->second.first; + if (handle) + texture_iterator->first->ReleaseTexture(handle); + + texture_data.erase(render_interface); + } +} + +bool TextureResource::Load(RenderInterface* render_interface) +{ + RMLUI_ZoneScoped; + + // Generate the texture from the callback function if we have one. + if (texture_callback) + { + Vector2i dimensions; + UniquePtr data = nullptr; + + TextureCallback& callback_fnc = *texture_callback; + + if (!callback_fnc(source, data, dimensions) || !data) + { + Log::Message(Log::LT_WARNING, "Failed to generate texture from callback function %s.", source.c_str()); + texture_data[render_interface] = TextureData(0, Vector2i(0, 0)); + + return false; + } + + TextureHandle handle; + bool success = render_interface->GenerateTexture(handle, data.get(), dimensions); + + if (success) + { + texture_data[render_interface] = TextureData(handle, dimensions); + } + else + { + Log::Message(Log::LT_WARNING, "Failed to generate internal texture %s.", source.c_str()); + texture_data[render_interface] = TextureData(0, Vector2i(0, 0)); + } + + return success; + } + + // No callback function, load the texture through the render interface. + TextureHandle handle; + Vector2i dimensions; + if (!render_interface->LoadTexture(handle, dimensions, source)) + { + Log::Message(Log::LT_WARNING, "Failed to load texture from %s.", source.c_str()); + texture_data[render_interface] = TextureData(0, Vector2i(0, 0)); + + return false; + } + + texture_data[render_interface] = TextureData(handle, dimensions); + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TextureResource.h b/thirdparty/RmlUi/Source/Core/TextureResource.h new file mode 100644 index 000000000..642e5e20a --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TextureResource.h @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TEXTURERESOURCE_H +#define RMLUI_CORE_TEXTURERESOURCE_H + +#include "../../Include/RmlUi/Core/Traits.h" +#include "../../Include/RmlUi/Core/Texture.h" + +namespace Rml { + +/** + A texture resource stores application-generated texture data (handle and dimensions) for each + unique render interface that needs to render the data. It is used through a Texture object. + + @author Peter Curry + */ + +class TextureResource : public NonCopyMoveable +{ +public: + TextureResource(); + ~TextureResource(); + + /// Clear any existing data and set the source path. + /// Texture loading is delayed until the texture is accessed by a specific render interface. + void Set(const String& source); + + /// Clear any existing data and set a callback function for loading the data. + /// Texture loading is delayed until the texture is accessed by a specific render interface. + void Set(const String& name, const TextureCallback& callback); + + /// Returns the resource's underlying texture handle. + TextureHandle GetHandle(RenderInterface* render_interface); + /// Returns the dimensions of the resource's texture. + const Vector2i& GetDimensions(RenderInterface* render_interface); + + /// Returns the resource's source. + const String& GetSource() const; + + /// Releases the texture's handle. + void Release(RenderInterface* render_interface = nullptr); + +private: + void Reset(); + + /// Attempts to load the texture from the source, or the callback function if set. + bool Load(RenderInterface* render_interface); + + String source; + + using TextureData = Pair< TextureHandle, Vector2i >; + using TextureDataMap = SmallUnorderedMap< RenderInterface*, TextureData >; + TextureDataMap texture_data; + + UniquePtr texture_callback; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Transform.cpp b/thirdparty/RmlUi/Source/Core/Transform.cpp new file mode 100644 index 000000000..e82646ce2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Transform.cpp @@ -0,0 +1,73 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Transform.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" +#include "../../Include/RmlUi/Core/Property.h" + +namespace Rml { + +// Default constructor, initializes an identity transform +Transform::Transform() +{ +} + +Transform::Transform(PrimitiveList primitives) + : primitives(primitives) +{ +} + +Property Transform::MakeProperty(PrimitiveList primitives) +{ + Property p{ TransformPtr{new Transform{primitives}}, Property::TRANSFORM }; + p.definition = StyleSheetSpecification::GetProperty(PropertyId::Transform); + return p; +} + +void Transform::ClearPrimitives() +{ + primitives.clear(); +} + +void Transform::AddPrimitive(const TransformPrimitive & p) +{ + primitives.push_back(p); +} + +int Transform::GetNumPrimitives() const noexcept +{ + return (int)primitives.size(); +} + +const TransformPrimitive & Transform::GetPrimitive(int i) const noexcept +{ + return primitives[i]; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TransformPrimitive.cpp b/thirdparty/RmlUi/Source/Core/TransformPrimitive.cpp new file mode 100644 index 000000000..d47cab05b --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TransformPrimitive.cpp @@ -0,0 +1,182 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/TransformPrimitive.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/TypeConverter.h" + +namespace Rml { +namespace Transforms { + + +/// Returns the numeric value converted to 'base_unit'. Only accepts base units of 'Number' or 'Rad': +/// 'Number' will pass-through the provided value. +/// 'Rad' will convert {Rad, Deg, %} -> Rad. +static float ResolvePrimitiveAbsoluteValue(NumericValue value, Property::Unit base_unit) noexcept +{ + RMLUI_ASSERT(base_unit == Property::RAD || base_unit == Property::NUMBER); + + if (base_unit == Property::RAD) + { + switch (value.unit) + { + case Property::RAD: + return value.number; + case Property::DEG: + return Math::DegreesToRadians(value.number); + case Property::PERCENT: + return value.number * 0.01f * 2.0f * Math::RMLUI_PI; + default: + Log::Message(Log::LT_WARNING, "Trying to pass a non-angle unit to a property expecting an angle."); + } + } + else if (base_unit == Property::NUMBER && value.unit != Property::NUMBER) + { + Log::Message(Log::LT_WARNING, "A unit was passed to a property which expected a unit-less number."); + } + + return value.number; +} + + +template +inline ResolvedPrimitive::ResolvedPrimitive(const float* values) noexcept +{ + for (size_t i = 0; i < N; ++i) + this->values[i] = values[i]; +} + +template +inline ResolvedPrimitive::ResolvedPrimitive(const NumericValue* values) noexcept +{ + for (size_t i = 0; i < N; ++i) + this->values[i] = values[i].number; +} + +template +inline ResolvedPrimitive::ResolvedPrimitive(const NumericValue* values, Array base_units) noexcept +{ + for (size_t i = 0; i < N; ++i) + this->values[i] = ResolvePrimitiveAbsoluteValue(values[i], base_units[i]); +} + +template +inline ResolvedPrimitive::ResolvedPrimitive(Array values, Array base_units) noexcept +{ + for (size_t i = 0; i < N; ++i) + this->values[i] = ResolvePrimitiveAbsoluteValue(values[i], base_units[i]); +} + +template +inline ResolvedPrimitive::ResolvedPrimitive(Array values) noexcept : values(values) { } + +template +inline UnresolvedPrimitive::UnresolvedPrimitive(const NumericValue* values) noexcept +{ + for (size_t i = 0; i < N; ++i) + this->values[i] = values[i]; +} + +template +inline UnresolvedPrimitive::UnresolvedPrimitive(Array values) noexcept : values(values) { } + + +Matrix2D::Matrix2D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } + +Matrix3D::Matrix3D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } +Matrix3D::Matrix3D(const Matrix4f& matrix) noexcept : ResolvedPrimitive(matrix.data()) { } + +TranslateX::TranslateX(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { } +TranslateX::TranslateX(float x, Property::Unit unit) noexcept : UnresolvedPrimitive({ NumericValue(x, unit) }) { } + +TranslateY::TranslateY(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { } +TranslateY::TranslateY(float y, Property::Unit unit) noexcept : UnresolvedPrimitive({ NumericValue(y, unit) }) { } + +TranslateZ::TranslateZ(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { } +TranslateZ::TranslateZ(float z, Property::Unit unit) noexcept : UnresolvedPrimitive({ NumericValue(z, unit) }) { } + +Translate2D::Translate2D(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { } +Translate2D::Translate2D(float x, float y, Property::Unit units) noexcept : UnresolvedPrimitive({ NumericValue(x, units), NumericValue(y, units) }) { } + +Translate3D::Translate3D(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { } +Translate3D::Translate3D(NumericValue x, NumericValue y, NumericValue z) noexcept : UnresolvedPrimitive({ x, y, z }) { } +Translate3D::Translate3D(float x, float y, float z, Property::Unit units) noexcept + : UnresolvedPrimitive({ NumericValue(x, units), NumericValue(y, units), NumericValue(z, units) }) { } + +ScaleX::ScaleX(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } +ScaleX::ScaleX(float value) noexcept : ResolvedPrimitive({ value }) { } + +ScaleY::ScaleY(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } +ScaleY::ScaleY(float value) noexcept : ResolvedPrimitive({ value }) { } + +ScaleZ::ScaleZ(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } +ScaleZ::ScaleZ(float value) noexcept : ResolvedPrimitive({ value }) { } + +Scale2D::Scale2D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } +Scale2D::Scale2D(float xy) noexcept : ResolvedPrimitive({ xy, xy }) { } +Scale2D::Scale2D(float x, float y) noexcept : ResolvedPrimitive({ x, y }) { } + +Scale3D::Scale3D(const NumericValue* values) noexcept : ResolvedPrimitive(values) { } +Scale3D::Scale3D(float xyz) noexcept : ResolvedPrimitive({ xyz, xyz, xyz }) { } +Scale3D::Scale3D(float x, float y, float z) noexcept : ResolvedPrimitive({ x, y, z }) { } + +RotateX::RotateX(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { } +RotateX::RotateX(float angle, Property::Unit unit) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { } + +RotateY::RotateY(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) {} +RotateY::RotateY(float angle, Property::Unit unit) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { } + +RotateZ::RotateZ(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { } +RotateZ::RotateZ(float angle, Property::Unit unit) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { } + +Rotate2D::Rotate2D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { } +Rotate2D::Rotate2D(float angle, Property::Unit unit) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { } + +Rotate3D::Rotate3D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::NUMBER, Property::NUMBER, Property::NUMBER, Property::RAD }) { } +Rotate3D::Rotate3D(float x, float y, float z, float angle, Property::Unit angle_unit) noexcept + : ResolvedPrimitive( + { NumericValue{x, Property::NUMBER}, NumericValue{y, Property::NUMBER}, NumericValue{z, Property::NUMBER}, NumericValue{angle, angle_unit} }, + { Property::NUMBER, Property::NUMBER, Property::NUMBER, Property::RAD } + ) +{ } + +SkewX::SkewX(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { } +SkewX::SkewX(float angle, Property::Unit unit) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { } + +SkewY::SkewY(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD }) { } +SkewY::SkewY(float angle, Property::Unit unit) noexcept : ResolvedPrimitive({ NumericValue{ angle, unit } }, { Property::RAD }) { } + +Skew2D::Skew2D(const NumericValue* values) noexcept : ResolvedPrimitive(values, { Property::RAD, Property::RAD }) { } +Skew2D::Skew2D(float x, float y, Property::Unit unit) noexcept + : ResolvedPrimitive({ NumericValue{ x, unit }, { NumericValue{ y, unit }} }, { Property::RAD, Property::RAD }) { } + +Perspective::Perspective(const NumericValue* values) noexcept : UnresolvedPrimitive(values) { } + + +} +} // namespace Rml \ No newline at end of file diff --git a/thirdparty/RmlUi/Source/Core/TransformState.cpp b/thirdparty/RmlUi/Source/Core/TransformState.cpp new file mode 100644 index 000000000..7f5db5722 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TransformState.cpp @@ -0,0 +1,94 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TransformState.h" + +namespace Rml { + +bool TransformState::SetTransform(const Matrix4f* in_transform) +{ + bool is_changed = (have_transform != (bool)in_transform); + if (in_transform) + { + is_changed |= (have_transform && transform != *in_transform); + transform = *in_transform; + have_transform = true; + } + else + have_transform = false; + + if (is_changed) + dirty_inverse_transform = true; + + return is_changed; +} +bool TransformState::SetLocalPerspective(const Matrix4f* in_perspective) +{ + bool is_changed = (have_perspective != (bool)in_perspective); + + if (in_perspective) + { + is_changed |= (have_perspective && local_perspective != *in_perspective); + local_perspective = *in_perspective; + have_perspective = true; + } + else + have_perspective = false; + + return is_changed; +} + +const Matrix4f* TransformState::GetTransform() const +{ + return have_transform ? &transform : nullptr; +} + +const Matrix4f* TransformState::GetLocalPerspective() const +{ + return have_perspective ? &local_perspective : nullptr; +} + +const Matrix4f* TransformState::GetInverseTransform() const +{ + if (!have_transform) + return nullptr; + + if (dirty_inverse_transform) + { + inverse_transform = transform; + have_inverse_transform = inverse_transform.Invert(); + dirty_inverse_transform = false; + } + + if (have_inverse_transform) + return &inverse_transform; + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TransformState.h b/thirdparty/RmlUi/Source/Core/TransformState.h new file mode 100644 index 000000000..a6cb90d8d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TransformState.h @@ -0,0 +1,71 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TRANSFORMSTATE_H +#define RMLUI_CORE_TRANSFORMSTATE_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class TransformState +{ +public: + + // Returns true if transform was changed. + bool SetTransform(const Matrix4f* in_transform); + + // Returns true if local perspecitve was changed. + bool SetLocalPerspective(const Matrix4f* in_perspective); + + const Matrix4f* GetTransform() const; + const Matrix4f* GetLocalPerspective() const; + + // Returns a nullptr if there is no transform set, or the transform is singular. + const Matrix4f* GetInverseTransform() const; + + +private: + bool have_transform = false; + bool have_perspective = false; + mutable bool have_inverse_transform = false; + mutable bool dirty_inverse_transform = false; + + // The accumulated transform matrix combines all transform and perspective properties of the owning element and all ancestors. + Matrix4f transform; + + // Local perspective which applies to children of the owning element. + Matrix4f local_perspective; + + // The inverse of the transform matrix for projecting points from screen space to the current element's space, such as used for picking elements. + mutable Matrix4f inverse_transform; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/TransformUtilities.cpp b/thirdparty/RmlUi/Source/Core/TransformUtilities.cpp new file mode 100644 index 000000000..229e1c1bf --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TransformUtilities.cpp @@ -0,0 +1,924 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "TransformUtilities.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" + +namespace Rml { + +using namespace Transforms; + +static Vector3f Combine(const Vector3f& a, const Vector3f& b, float a_scale, float b_scale) +{ + Vector3f result; + result.x = a_scale * a.x + b_scale * b.x; + result.y = a_scale * a.y + b_scale * b.y; + result.z = a_scale * a.z + b_scale * b.z; + return result; +} + + +// Interpolate two quaternions a, b with weight alpha [0, 1] +static Vector4f QuaternionSlerp(const Vector4f& a, const Vector4f& b, float alpha) +{ + using namespace Math; + + const float eps = 0.9995f; + + float dot = a.DotProduct(b); + dot = Clamp(dot, -1.f, 1.f); + + if (dot > eps) + return a; + + float theta = ACos(dot); + float w = Sin(alpha * theta) / SquareRoot(1.f - dot * dot); + float a_scale = Cos(alpha * theta) - dot * w; + + Vector4f result; + for (int i = 0; i < 4; i++) + { + result[i] = a[i] * a_scale + b[i] * w; + } + + return result; +} + +/// Resolve a numeric property value for an element. +static inline float ResolveLengthPercentage(NumericValue value, Element& e, float base) noexcept +{ + Property prop; + prop.value = Variant(value.number); + prop.unit = value.unit; + return e.ResolveNumericProperty(&prop, base); +} + +/// Resolve a numeric property value with the element's width as relative base value. +static inline float ResolveWidth(NumericValue value, Element& e) noexcept +{ + if (value.unit & (Property::PX | Property::NUMBER)) return value.number; + return ResolveLengthPercentage(value, e, e.GetBox().GetSize(Box::BORDER).x); +} + +/// Resolve a numeric property value with the element's height as relative base value. +static inline float ResolveHeight(NumericValue value, Element& e) noexcept +{ + if (value.unit & (Property::PX | Property::NUMBER)) return value.number; + return ResolveLengthPercentage(value, e, e.GetBox().GetSize(Box::BORDER).y); +} + +/// Resolve a numeric property value with the element's depth as relative base value. +static inline float ResolveDepth(NumericValue value, Element& e) noexcept +{ + if (value.unit & (Property::PX | Property::NUMBER)) return value.number; + Vector2f size = e.GetBox().GetSize(Box::BORDER); + return ResolveLengthPercentage(value, e, Math::Max(size.x, size.y)); +} + +static inline String ToString(NumericValue value) noexcept +{ + Property prop; + prop.value = Variant(value.number); + prop.unit = value.unit; + return prop.ToString(); +} + +struct SetIdentityVisitor +{ + template + void operator()(Transforms::ResolvedPrimitive& p) + { + for (auto& value : p.values) + value = 0.0f; + } + template + void operator()(Transforms::UnresolvedPrimitive& p) + { + for (auto& value : p.values) + value.number = 0.0f; + } + void operator()(Transforms::Matrix2D& p) + { + for (int i = 0; i < 6; i++) + p.values[i] = ((i == 0 || i == 3) ? 1.0f : 0.0f); + } + void operator()(Transforms::Matrix3D& p) + { + for (int i = 0; i < 16; i++) + p.values[i] = ((i % 5) == 0 ? 1.0f : 0.0f); + } + void operator()(Transforms::ScaleX& p) + { + p.values[0] = 1; + } + void operator()(Transforms::ScaleY& p) + { + p.values[0] = 1; + } + void operator()(Transforms::ScaleZ& p) + { + p.values[0] = 1; + } + void operator()(Transforms::Scale2D& p) + { + p.values[0] = p.values[1] = 1; + } + void operator()(Transforms::Scale3D& p) + { + p.values[0] = p.values[1] = p.values[2] = 1; + } + void operator()(Transforms::DecomposedMatrix4& p) + { + p.perspective = Vector4f(0, 0, 0, 1); + p.quaternion = Vector4f(0, 0, 0, 1); + p.translation = Vector3f(0, 0, 0); + p.scale = Vector3f(1, 1, 1); + p.skew = Vector3f(0, 0, 0); + } + + + void run(TransformPrimitive& primitive) + { + switch (primitive.type) + { + case TransformPrimitive::MATRIX2D: this->operator()(primitive.matrix_2d); break; + case TransformPrimitive::MATRIX3D: this->operator()(primitive.matrix_3d); break; + case TransformPrimitive::TRANSLATEX: this->operator()(primitive.translate_x); break; + case TransformPrimitive::TRANSLATEY: this->operator()(primitive.translate_y); break; + case TransformPrimitive::TRANSLATEZ: this->operator()(primitive.translate_z); break; + case TransformPrimitive::TRANSLATE2D: this->operator()(primitive.translate_2d); break; + case TransformPrimitive::TRANSLATE3D: this->operator()(primitive.translate_3d); break; + case TransformPrimitive::SCALEX: this->operator()(primitive.scale_x); break; + case TransformPrimitive::SCALEY: this->operator()(primitive.scale_y); break; + case TransformPrimitive::SCALEZ: this->operator()(primitive.scale_z); break; + case TransformPrimitive::SCALE2D: this->operator()(primitive.scale_2d); break; + case TransformPrimitive::SCALE3D: this->operator()(primitive.scale_3d); break; + case TransformPrimitive::ROTATEX: this->operator()(primitive.rotate_x); break; + case TransformPrimitive::ROTATEY: this->operator()(primitive.rotate_y); break; + case TransformPrimitive::ROTATEZ: this->operator()(primitive.rotate_z); break; + case TransformPrimitive::ROTATE2D: this->operator()(primitive.rotate_2d); break; + case TransformPrimitive::ROTATE3D: this->operator()(primitive.rotate_3d); break; + case TransformPrimitive::SKEWX: this->operator()(primitive.skew_x); break; + case TransformPrimitive::SKEWY: this->operator()(primitive.skew_y); break; + case TransformPrimitive::SKEW2D: this->operator()(primitive.skew_2d); break; + case TransformPrimitive::PERSPECTIVE: this->operator()(primitive.perspective); break; + case TransformPrimitive::DECOMPOSEDMATRIX4: this->operator()(primitive.decomposed_matrix_4); break; + default: + RMLUI_ASSERT(false); + break; + } + } +}; + +void TransformUtilities::SetIdentity(TransformPrimitive& p) noexcept +{ + SetIdentityVisitor{}.run(p); +} + + +struct ResolveTransformVisitor +{ + Matrix4f& m; + Element& e; + + void operator()(const Transforms::Matrix2D& p) + { + m = Matrix4f::FromRows( + Vector4f(p.values[0], p.values[2], 0, p.values[4]), + Vector4f(p.values[1], p.values[3], 0, p.values[5]), + Vector4f(0, 0, 1, 0), + Vector4f(0, 0, 0, 1) + ); + } + + void operator()(const Transforms::Matrix3D& p) + { + m = Matrix4f::FromColumns( + Vector4f(p.values[0], p.values[1], p.values[2], p.values[3]), + Vector4f(p.values[4], p.values[5], p.values[6], p.values[7]), + Vector4f(p.values[8], p.values[9], p.values[10], p.values[11]), + Vector4f(p.values[12], p.values[13], p.values[14], p.values[15]) + ); + } + + void operator()(const Transforms::TranslateX& p) + { + m = Matrix4f::TranslateX(ResolveWidth(p.values[0], e)); + } + + void operator()(const Transforms::TranslateY& p) + { + m = Matrix4f::TranslateY(ResolveHeight(p.values[0], e)); + } + + void operator()(const Transforms::TranslateZ& p) + { + m = Matrix4f::TranslateZ(ResolveDepth(p.values[0], e)); + } + + void operator()(const Transforms::Translate2D& p) + { + m = Matrix4f::Translate( + ResolveWidth(p.values[0], e), + ResolveHeight(p.values[1], e), + 0 + ); + } + + void operator()(const Transforms::Translate3D& p) + { + m = Matrix4f::Translate( + ResolveWidth(p.values[0], e), + ResolveHeight(p.values[1], e), + ResolveDepth(p.values[2], e) + ); + } + + void operator()(const Transforms::ScaleX& p) + { + m = Matrix4f::ScaleX(p.values[0]); + } + + void operator()(const Transforms::ScaleY& p) + { + m = Matrix4f::ScaleY(p.values[0]); + } + + void operator()(const Transforms::ScaleZ& p) + { + m = Matrix4f::ScaleZ(p.values[0]); + } + + void operator()(const Transforms::Scale2D& p) + { + m = Matrix4f::Scale(p.values[0], p.values[1], 1); + } + + void operator()(const Transforms::Scale3D& p) + { + m = Matrix4f::Scale(p.values[0], p.values[1], p.values[2]); + } + + void operator()(const Transforms::RotateX& p) + { + m = Matrix4f::RotateX(p.values[0]); + } + + void operator()(const Transforms::RotateY& p) + { + m = Matrix4f::RotateY(p.values[0]); + } + + void operator()(const Transforms::RotateZ& p) + { + m = Matrix4f::RotateZ(p.values[0]); + } + + void operator()(const Transforms::Rotate2D& p) + { + m = Matrix4f::RotateZ(p.values[0]); + } + + void operator()(const Transforms::Rotate3D& p) + { + m = Matrix4f::Rotate(Vector3f(p.values[0], p.values[1], p.values[2]), p.values[3]); + } + + void operator()(const Transforms::SkewX& p) + { + m = Matrix4f::SkewX(p.values[0]); + } + + void operator()(const Transforms::SkewY& p) + { + m = Matrix4f::SkewY(p.values[0]); + } + + void operator()(const Transforms::Skew2D& p) + { + m = Matrix4f::Skew(p.values[0], p.values[1]); + } + + void operator()(const Transforms::DecomposedMatrix4& p) + { + m = Matrix4f::Compose(p.translation, p.scale, p.skew, p.perspective, p.quaternion); + } + void operator()(const Transforms::Perspective& p) + { + m = Matrix4f::Perspective(ResolveDepth(p.values[0], e)); + } + + + void run(const TransformPrimitive& primitive) + { + switch (primitive.type) + { + case TransformPrimitive::MATRIX2D: this->operator()(primitive.matrix_2d); break; + case TransformPrimitive::MATRIX3D: this->operator()(primitive.matrix_3d); break; + case TransformPrimitive::TRANSLATEX: this->operator()(primitive.translate_x); break; + case TransformPrimitive::TRANSLATEY: this->operator()(primitive.translate_y); break; + case TransformPrimitive::TRANSLATEZ: this->operator()(primitive.translate_z); break; + case TransformPrimitive::TRANSLATE2D: this->operator()(primitive.translate_2d); break; + case TransformPrimitive::TRANSLATE3D: this->operator()(primitive.translate_3d); break; + case TransformPrimitive::SCALEX: this->operator()(primitive.scale_x); break; + case TransformPrimitive::SCALEY: this->operator()(primitive.scale_y); break; + case TransformPrimitive::SCALEZ: this->operator()(primitive.scale_z); break; + case TransformPrimitive::SCALE2D: this->operator()(primitive.scale_2d); break; + case TransformPrimitive::SCALE3D: this->operator()(primitive.scale_3d); break; + case TransformPrimitive::ROTATEX: this->operator()(primitive.rotate_x); break; + case TransformPrimitive::ROTATEY: this->operator()(primitive.rotate_y); break; + case TransformPrimitive::ROTATEZ: this->operator()(primitive.rotate_z); break; + case TransformPrimitive::ROTATE2D: this->operator()(primitive.rotate_2d); break; + case TransformPrimitive::ROTATE3D: this->operator()(primitive.rotate_3d); break; + case TransformPrimitive::SKEWX: this->operator()(primitive.skew_x); break; + case TransformPrimitive::SKEWY: this->operator()(primitive.skew_y); break; + case TransformPrimitive::SKEW2D: this->operator()(primitive.skew_2d); break; + case TransformPrimitive::PERSPECTIVE: this->operator()(primitive.perspective); break; + case TransformPrimitive::DECOMPOSEDMATRIX4: this->operator()(primitive.decomposed_matrix_4); break; + } + } +}; + +Matrix4f TransformUtilities::ResolveTransform(const TransformPrimitive& p, Element& e) noexcept +{ + Matrix4f m; + ResolveTransformVisitor visitor{ m, e }; + visitor.run(p); + return m; +} + + + + +struct PrepareVisitor +{ + Element& e; + + bool operator()(TranslateX& p) + { + p.values[0] = NumericValue{ ResolveWidth(p.values[0], e), Property::PX }; + return true; + } + bool operator()(TranslateY& p) + { + p.values[0] = NumericValue{ ResolveHeight(p.values[0], e), Property::PX }; + return true; + } + bool operator()(TranslateZ& p) + { + p.values[0] = NumericValue{ ResolveDepth(p.values[0], e), Property::PX }; + return true; + } + bool operator()(Translate2D& p) + { + p.values[0] = NumericValue{ ResolveWidth(p.values[0], e), Property::PX }; + p.values[1] = NumericValue{ ResolveHeight(p.values[1], e), Property::PX }; + return true; + } + bool operator()(Translate3D& p) + { + p.values[0] = NumericValue{ ResolveWidth(p.values[0], e), Property::PX }; + p.values[1] = NumericValue{ ResolveHeight(p.values[1], e), Property::PX }; + p.values[2] = NumericValue{ ResolveDepth(p.values[2], e), Property::PX }; + return true; + } + template + bool operator()(ResolvedPrimitive& /*p*/) + { + // No conversion needed for resolved transforms (with some exceptions below) + return true; + } + bool operator()(DecomposedMatrix4& /*p*/) + { + return true; + } + bool operator()(Rotate3D& p) + { + // Rotate3D can be interpolated if and only if their rotation axes point in the same direction. + // We normalize the rotation vector here for easy comparison, and return true here. Later on we make the + // pair-wise check in 'TryConvertToMatchingGenericType' to see if we need to decompose. + Vector3f vec = Vector3f(p.values[0], p.values[1], p.values[2]).Normalise(); + p.values[0] = vec.x; + p.values[1] = vec.y; + p.values[2] = vec.z; + return true; + } + bool operator()(Matrix3D& /*p*/) + { + // Matrices must be decomposed for interpolation + return false; + } + bool operator()(Matrix2D& /*p*/) + { + // Matrix2D can also be optimized for interpolation, but for now we decompose it to a full DecomposedMatrix4 + return false; + } + bool operator()(Perspective& /*p*/) + { + // Perspective must be decomposed + return false; + } + + bool run(TransformPrimitive& primitive) + { + switch (primitive.type) + { + case TransformPrimitive::MATRIX2D: return this->operator()(primitive.matrix_2d); + case TransformPrimitive::MATRIX3D: return this->operator()(primitive.matrix_3d); + case TransformPrimitive::TRANSLATEX: return this->operator()(primitive.translate_x); + case TransformPrimitive::TRANSLATEY: return this->operator()(primitive.translate_y); + case TransformPrimitive::TRANSLATEZ: return this->operator()(primitive.translate_z); + case TransformPrimitive::TRANSLATE2D: return this->operator()(primitive.translate_2d); + case TransformPrimitive::TRANSLATE3D: return this->operator()(primitive.translate_3d); + case TransformPrimitive::SCALEX: return this->operator()(primitive.scale_x); + case TransformPrimitive::SCALEY: return this->operator()(primitive.scale_y); + case TransformPrimitive::SCALEZ: return this->operator()(primitive.scale_z); + case TransformPrimitive::SCALE2D: return this->operator()(primitive.scale_2d); + case TransformPrimitive::SCALE3D: return this->operator()(primitive.scale_3d); + case TransformPrimitive::ROTATEX: return this->operator()(primitive.rotate_x); + case TransformPrimitive::ROTATEY: return this->operator()(primitive.rotate_y); + case TransformPrimitive::ROTATEZ: return this->operator()(primitive.rotate_z); + case TransformPrimitive::ROTATE2D: return this->operator()(primitive.rotate_2d); + case TransformPrimitive::ROTATE3D: return this->operator()(primitive.rotate_3d); + case TransformPrimitive::SKEWX: return this->operator()(primitive.skew_x); + case TransformPrimitive::SKEWY: return this->operator()(primitive.skew_y); + case TransformPrimitive::SKEW2D: return this->operator()(primitive.skew_2d); + case TransformPrimitive::PERSPECTIVE: return this->operator()(primitive.perspective); + case TransformPrimitive::DECOMPOSEDMATRIX4: return this->operator()(primitive.decomposed_matrix_4); + default: + break; + } + RMLUI_ASSERT(false); + return false; + } +}; + +bool TransformUtilities::PrepareForInterpolation(TransformPrimitive& p, Element& e) noexcept +{ + return PrepareVisitor{ e }.run(p); +} + + + + +enum class GenericType { None, Scale3D, Translate3D, Rotate3D }; + +struct GetGenericTypeVisitor +{ + GenericType run(const TransformPrimitive& primitive) + { + switch (primitive.type) + { + case TransformPrimitive::TRANSLATEX: return GenericType::Translate3D; + case TransformPrimitive::TRANSLATEY: return GenericType::Translate3D; + case TransformPrimitive::TRANSLATEZ: return GenericType::Translate3D; + case TransformPrimitive::TRANSLATE2D: return GenericType::Translate3D; + case TransformPrimitive::TRANSLATE3D: return GenericType::Translate3D; + case TransformPrimitive::SCALEX: return GenericType::Scale3D; + case TransformPrimitive::SCALEY: return GenericType::Scale3D; + case TransformPrimitive::SCALEZ: return GenericType::Scale3D; + case TransformPrimitive::SCALE2D: return GenericType::Scale3D; + case TransformPrimitive::SCALE3D: return GenericType::Scale3D; + case TransformPrimitive::ROTATEX: return GenericType::Rotate3D; + case TransformPrimitive::ROTATEY: return GenericType::Rotate3D; + case TransformPrimitive::ROTATEZ: return GenericType::Rotate3D; + case TransformPrimitive::ROTATE2D: return GenericType::Rotate3D; + case TransformPrimitive::ROTATE3D: return GenericType::Rotate3D; + default: + break; + } + return GenericType::None; + } +}; + + +struct ConvertToGenericTypeVisitor +{ + Translate3D operator()(const TranslateX& p) { return Translate3D{ p.values[0], {0.0f, Property::PX}, {0.0f, Property::PX} }; } + Translate3D operator()(const TranslateY& p) { return Translate3D{ {0.0f, Property::PX}, p.values[0], {0.0f, Property::PX} }; } + Translate3D operator()(const TranslateZ& p) { return Translate3D{ {0.0f, Property::PX}, {0.0f, Property::PX}, p.values[0] }; } + Translate3D operator()(const Translate2D& p) { return Translate3D{ p.values[0], p.values[1], {0.0f, Property::PX} }; } + Scale3D operator()(const ScaleX& p) { return Scale3D{ p.values[0], 1.0f, 1.0f }; } + Scale3D operator()(const ScaleY& p) { return Scale3D{ 1.0f, p.values[0], 1.0f }; } + Scale3D operator()(const ScaleZ& p) { return Scale3D{ 1.0f, 1.0f, p.values[0] }; } + Scale3D operator()(const Scale2D& p) { return Scale3D{ p.values[0], p.values[1], 1.0f }; } + Rotate3D operator()(const RotateX& p) { return Rotate3D{ 1, 0, 0, p.values[0], Property::RAD }; } + Rotate3D operator()(const RotateY& p) { return Rotate3D{ 0, 1, 0, p.values[0], Property::RAD }; } + Rotate3D operator()(const RotateZ& p) { return Rotate3D{ 0, 0, 1, p.values[0], Property::RAD }; } + Rotate3D operator()(const Rotate2D& p) { return Rotate3D{ 0, 0, 1, p.values[0], Property::RAD }; } + + template + TransformPrimitive operator()(const T& p) { RMLUI_ERROR; return p; } + + TransformPrimitive run(const TransformPrimitive& primitive) + { + TransformPrimitive result = primitive; + switch (primitive.type) + { + case TransformPrimitive::TRANSLATEX: result.type = TransformPrimitive::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_x); break; + case TransformPrimitive::TRANSLATEY: result.type = TransformPrimitive::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_y); break; + case TransformPrimitive::TRANSLATEZ: result.type = TransformPrimitive::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_z); break; + case TransformPrimitive::TRANSLATE2D: result.type = TransformPrimitive::TRANSLATE3D; result.translate_3d = this->operator()(primitive.translate_2d); break; + case TransformPrimitive::TRANSLATE3D: break; + case TransformPrimitive::SCALEX: result.type = TransformPrimitive::SCALE3D; result.scale_3d = this->operator()(primitive.scale_x); break; + case TransformPrimitive::SCALEY: result.type = TransformPrimitive::SCALE3D; result.scale_3d = this->operator()(primitive.scale_y); break; + case TransformPrimitive::SCALEZ: result.type = TransformPrimitive::SCALE3D; result.scale_3d = this->operator()(primitive.scale_z); break; + case TransformPrimitive::SCALE2D: result.type = TransformPrimitive::SCALE3D; result.scale_3d = this->operator()(primitive.scale_2d); break; + case TransformPrimitive::SCALE3D: break; + case TransformPrimitive::ROTATEX: result.type = TransformPrimitive::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_x); break; + case TransformPrimitive::ROTATEY: result.type = TransformPrimitive::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_y); break; + case TransformPrimitive::ROTATEZ: result.type = TransformPrimitive::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_z); break; + case TransformPrimitive::ROTATE2D: result.type = TransformPrimitive::ROTATE3D; result.rotate_3d = this->operator()(primitive.rotate_2d); break; + case TransformPrimitive::ROTATE3D: break; + default: + RMLUI_ASSERT(false); + break; + } + return result; + } +}; + +static bool CanInterpolateRotate3D(const Rotate3D& p0, const Rotate3D& p1) +{ + // Rotate3D can only be interpolated if and only if their rotation axes point in the same direction. + // Assumes each rotation axis has already been normalized. + auto& v0 = p0.values; + auto& v1 = p1.values; + return v0[0] == v1[0] && v0[1] == v1[1] && v0[2] == v1[2]; +} + + +bool TransformUtilities::TryConvertToMatchingGenericType(TransformPrimitive& p0, TransformPrimitive& p1) noexcept +{ + if (p0.type == p1.type) + { + if (p0.type == TransformPrimitive::ROTATE3D && !CanInterpolateRotate3D(p0.rotate_3d, p1.rotate_3d)) + return false; + + return true; + } + + GenericType c0 = GetGenericTypeVisitor{}.run(p0); + GenericType c1 = GetGenericTypeVisitor{}.run(p1); + + if (c0 == c1 && c0 != GenericType::None) + { + TransformPrimitive new_p0 = ConvertToGenericTypeVisitor{}.run(p0); + TransformPrimitive new_p1 = ConvertToGenericTypeVisitor{}.run(p1); + + RMLUI_ASSERT(new_p0.type == new_p1.type); + + if (new_p0.type == TransformPrimitive::ROTATE3D && !CanInterpolateRotate3D(new_p0.rotate_3d, new_p1.rotate_3d)) + return false; + + p0 = new_p0; + p1 = new_p1; + + return true; + } + + return false; +} + + + + + +struct InterpolateVisitor +{ + const TransformPrimitive& other_variant; + float alpha; + + template + bool Interpolate(ResolvedPrimitive& p0, const ResolvedPrimitive& p1) + { + for (size_t i = 0; i < N; i++) + p0.values[i] = p0.values[i] * (1.0f - alpha) + p1.values[i] * alpha; + return true; + } + template + bool Interpolate(UnresolvedPrimitive& p0, const UnresolvedPrimitive& p1) + { + // Assumes that the underlying units have been resolved (e.g. to pixels) + for (size_t i = 0; i < N; i++) + p0.values[i].number = p0.values[i].number * (1.0f - alpha) + p1.values[i].number * alpha; + return true; + } + bool Interpolate(Rotate3D& p0, const Rotate3D& p1) + { + RMLUI_ASSERT(CanInterpolateRotate3D(p0, p1)); + // We can only interpolate rotate3d if their rotation axes align. That should be the case if we get here, + // otherwise the generic type matching should decompose them. Thus, we only need to interpolate + // the angle value here. + p0.values[3] = p0.values[3] * (1.0f - alpha) + p1.values[3] * alpha; + return true; + } + bool Interpolate(Matrix2D& /*p0*/, const Matrix2D& /*p1*/) { RMLUI_ERROR; return false; /* Error if we get here, see PrepareForInterpolation() */ } + bool Interpolate(Matrix3D& /*p0*/, const Matrix3D& /*p1*/) { RMLUI_ERROR; return false; /* Error if we get here, see PrepareForInterpolation() */ } + bool Interpolate(Perspective& /*p0*/, const Perspective& /*p1*/) { RMLUI_ERROR; return false; /* Error if we get here, see PrepareForInterpolation() */ } + + bool Interpolate(DecomposedMatrix4& p0, const DecomposedMatrix4& p1) + { + p0.perspective = p0.perspective * (1.0f - alpha) + p1.perspective * alpha; + p0.quaternion = QuaternionSlerp(p0.quaternion, p1.quaternion, alpha); + p0.translation = p0.translation * (1.0f - alpha) + p1.translation * alpha; + p0.scale = p0.scale * (1.0f - alpha) + p1.scale * alpha; + p0.skew = p0.skew * (1.0f - alpha) + p1.skew * alpha; + return true; + } + + bool run(TransformPrimitive& variant) + { + RMLUI_ASSERT(variant.type == other_variant.type); + switch (variant.type) + { + case TransformPrimitive::MATRIX2D: return Interpolate(variant.matrix_2d, other_variant.matrix_2d); + case TransformPrimitive::MATRIX3D: return Interpolate(variant.matrix_3d, other_variant.matrix_3d); + case TransformPrimitive::TRANSLATEX: return Interpolate(variant.translate_x, other_variant.translate_x); + case TransformPrimitive::TRANSLATEY: return Interpolate(variant.translate_y, other_variant.translate_y); + case TransformPrimitive::TRANSLATEZ: return Interpolate(variant.translate_z, other_variant.translate_z); + case TransformPrimitive::TRANSLATE2D: return Interpolate(variant.translate_2d, other_variant.translate_2d); + case TransformPrimitive::TRANSLATE3D: return Interpolate(variant.translate_3d, other_variant.translate_3d); + case TransformPrimitive::SCALEX: return Interpolate(variant.scale_x, other_variant.scale_x); + case TransformPrimitive::SCALEY: return Interpolate(variant.scale_y, other_variant.scale_y); + case TransformPrimitive::SCALEZ: return Interpolate(variant.scale_z, other_variant.scale_z); + case TransformPrimitive::SCALE2D: return Interpolate(variant.scale_2d, other_variant.scale_2d); + case TransformPrimitive::SCALE3D: return Interpolate(variant.scale_3d, other_variant.scale_3d); + case TransformPrimitive::ROTATEX: return Interpolate(variant.rotate_x, other_variant.rotate_x); + case TransformPrimitive::ROTATEY: return Interpolate(variant.rotate_y, other_variant.rotate_y); + case TransformPrimitive::ROTATEZ: return Interpolate(variant.rotate_z, other_variant.rotate_z); + case TransformPrimitive::ROTATE2D: return Interpolate(variant.rotate_2d, other_variant.rotate_2d); + case TransformPrimitive::ROTATE3D: return Interpolate(variant.rotate_3d, other_variant.rotate_3d); + case TransformPrimitive::SKEWX: return Interpolate(variant.skew_x, other_variant.skew_x); + case TransformPrimitive::SKEWY: return Interpolate(variant.skew_y, other_variant.skew_y); + case TransformPrimitive::SKEW2D: return Interpolate(variant.skew_2d, other_variant.skew_2d); + case TransformPrimitive::PERSPECTIVE: return Interpolate(variant.perspective, other_variant.perspective); + case TransformPrimitive::DECOMPOSEDMATRIX4: return Interpolate(variant.decomposed_matrix_4, other_variant.decomposed_matrix_4); + } + RMLUI_ASSERT(false); + return false; + } +}; + +bool TransformUtilities::InterpolateWith(TransformPrimitive& target, const TransformPrimitive& other, float alpha) noexcept +{ + if (target.type != other.type) + return false; + + bool result = InterpolateVisitor{ other, alpha }.run(target); + return result; +} + + +template +static inline String ToString(const Transforms::ResolvedPrimitive& p, String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) noexcept { + float multiplier = 1.0f; + String tmp; + String result = "("; + for (size_t i = 0; i < N; i++) + { + if (only_unit_on_last_value && i < N - 1) + multiplier = 1.0f; + else if (rad_to_deg) + multiplier = 180.f / Math::RMLUI_PI; + + if (TypeConverter::Convert(p.values[i] * multiplier, tmp)) + result += tmp; + + if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1))) + result += unit; + + if (i < N - 1) + result += ", "; + } + result += ")"; + return result; +} + +template +static inline String ToString(const Transforms::UnresolvedPrimitive& p) noexcept { + String result = "("; + for (size_t i = 0; i < N; i++) + { + result += ToString(p.values[i]); + if (i != N - 1) + result += ", "; + } + result += ")"; + return result; +} + +static inline String ToString(const Transforms::DecomposedMatrix4& p) noexcept { + static const Transforms::DecomposedMatrix4 d{ + Vector4f(0, 0, 0, 1), + Vector4f(0, 0, 0, 1), + Vector3f(0, 0, 0), + Vector3f(1, 1, 1), + Vector3f(0, 0, 0) + }; + String tmp; + String result; + + if (p.perspective != d.perspective && TypeConverter< Vector4f, String >::Convert(p.perspective, tmp)) + result += "perspective(" + tmp + "), "; + if (p.quaternion != d.quaternion && TypeConverter< Vector4f, String >::Convert(p.quaternion, tmp)) + result += "quaternion(" + tmp + "), "; + if (p.translation != d.translation && TypeConverter< Vector3f, String >::Convert(p.translation, tmp)) + result += "translation(" + tmp + "), "; + if (p.scale != d.scale && TypeConverter< Vector3f, String >::Convert(p.scale, tmp)) + result += "scale(" + tmp + "), "; + if (p.skew != d.skew && TypeConverter< Vector3f, String >::Convert(p.skew, tmp)) + result += "skew(" + tmp + "), "; + + if (result.size() > 2) + result.resize(result.size() - 2); + + result = "decomposedMatrix3d{ " + result + " }"; + + return result; +} + +static inline String ToString(const Transforms::Matrix2D& p) noexcept { return "matrix" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::Matrix3D& p) noexcept { return "matrix3d" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::TranslateX& p) noexcept { return "translateX" + ToString(static_cast&>(p)); } +static inline String ToString(const Transforms::TranslateY& p) noexcept { return "translateY" + ToString(static_cast&>(p)); } +static inline String ToString(const Transforms::TranslateZ& p) noexcept { return "translateZ" + ToString(static_cast&>(p)); } +static inline String ToString(const Transforms::Translate2D& p) noexcept { return "translate" + ToString(static_cast&>(p)); } +static inline String ToString(const Transforms::Translate3D& p) noexcept { return "translate3d" + ToString(static_cast&>(p)); } +static inline String ToString(const Transforms::ScaleX& p) noexcept { return "scaleX" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::ScaleY& p) noexcept { return "scaleY" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::ScaleZ& p) noexcept { return "scaleZ" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::Scale2D& p) noexcept { return "scale" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::Scale3D& p) noexcept { return "scale3d" + ToString(static_cast&>(p), ""); } +static inline String ToString(const Transforms::RotateX& p) noexcept { return "rotateX" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::RotateY& p) noexcept { return "rotateY" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::RotateZ& p) noexcept { return "rotateZ" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::Rotate2D& p) noexcept { return "rotate" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::Rotate3D& p) noexcept { return "rotate3d" + ToString(static_cast&>(p), "deg", true, true); } +static inline String ToString(const Transforms::SkewX& p) noexcept { return "skewX" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::SkewY& p) noexcept { return "skewY" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::Skew2D& p) noexcept { return "skew" + ToString(static_cast&>(p), "deg", true); } +static inline String ToString(const Transforms::Perspective& p) noexcept { return "perspective" + ToString(static_cast&>(p)); } + +struct ToStringVisitor +{ + String run(const TransformPrimitive& variant) + { + switch (variant.type) + { + case TransformPrimitive::MATRIX2D: return ToString(variant.matrix_2d); + case TransformPrimitive::MATRIX3D: return ToString(variant.matrix_3d); + case TransformPrimitive::TRANSLATEX: return ToString(variant.translate_x); + case TransformPrimitive::TRANSLATEY: return ToString(variant.translate_y); + case TransformPrimitive::TRANSLATEZ: return ToString(variant.translate_z); + case TransformPrimitive::TRANSLATE2D: return ToString(variant.translate_2d); + case TransformPrimitive::TRANSLATE3D: return ToString(variant.translate_3d); + case TransformPrimitive::SCALEX: return ToString(variant.scale_x); + case TransformPrimitive::SCALEY: return ToString(variant.scale_y); + case TransformPrimitive::SCALEZ: return ToString(variant.scale_z); + case TransformPrimitive::SCALE2D: return ToString(variant.scale_2d); + case TransformPrimitive::SCALE3D: return ToString(variant.scale_3d); + case TransformPrimitive::ROTATEX: return ToString(variant.rotate_x); + case TransformPrimitive::ROTATEY: return ToString(variant.rotate_y); + case TransformPrimitive::ROTATEZ: return ToString(variant.rotate_z); + case TransformPrimitive::ROTATE2D: return ToString(variant.rotate_2d); + case TransformPrimitive::ROTATE3D: return ToString(variant.rotate_3d); + case TransformPrimitive::SKEWX: return ToString(variant.skew_x); + case TransformPrimitive::SKEWY: return ToString(variant.skew_y); + case TransformPrimitive::SKEW2D: return ToString(variant.skew_2d); + case TransformPrimitive::PERSPECTIVE: return ToString(variant.perspective); + case TransformPrimitive::DECOMPOSEDMATRIX4: return ToString(variant.decomposed_matrix_4); + default: + break; + } + RMLUI_ASSERT(false); + return String(); + } +}; + +String TransformUtilities::ToString(const TransformPrimitive& p) noexcept +{ + String result = ToStringVisitor{}.run(p); + return result; +} + + +bool TransformUtilities::Decompose(Transforms::DecomposedMatrix4& d, const Matrix4f& m) noexcept +{ + // Follows the procedure given in https://drafts.csswg.org/css-transforms-2/#interpolation-of-3d-matrices + + const float eps = 0.0005f; + + if (Math::AbsoluteValue(m[3][3]) < eps) + return false; + + + // Perspective matrix + Matrix4f p = m; + + for (int i = 0; i < 3; i++) + p[i][3] = 0; + p[3][3] = 1; + + if (Math::AbsoluteValue(p.Determinant()) < eps) + return false; + + if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0) + { + auto rhs = m.GetColumn(3); + Matrix4f p_inv = p; + if (!p_inv.Invert()) + return false; + auto& p_inv_trans = p.Transpose(); + d.perspective = p_inv_trans * rhs; + } + else + { + d.perspective[0] = d.perspective[1] = d.perspective[2] = 0; + d.perspective[3] = 1; + } + + for (int i = 0; i < 3; i++) + d.translation[i] = m[3][i]; + + Vector3f row[3]; + for (int i = 0; i < 3; i++) + { + row[i][0] = m[i][0]; + row[i][1] = m[i][1]; + row[i][2] = m[i][2]; + } + + d.scale[0] = row[0].Magnitude(); + row[0] = row[0].Normalise(); + + d.skew[0] = row[0].DotProduct(row[1]); + row[1] = Combine(row[1], row[0], 1, -d.skew[0]); + + d.scale[1] = row[1].Magnitude(); + row[1] = row[1].Normalise(); + d.skew[0] /= d.scale[1]; + + d.skew[1] = row[0].DotProduct(row[2]); + row[2] = Combine(row[2], row[0], 1, -d.skew[1]); + d.skew[2] = row[1].DotProduct(row[2]); + row[2] = Combine(row[2], row[1], 1, -d.skew[2]); + + d.scale[2] = row[2].Magnitude(); + row[2] = row[2].Normalise(); + d.skew[2] /= d.scale[2]; + d.skew[1] /= d.scale[2]; + + // Check if we need to flip coordinate system + auto pdum3 = row[1].CrossProduct(row[2]); + if (row[0].DotProduct(pdum3) < 0.0f) + { + for (int i = 0; i < 3; i++) + { + d.scale[i] *= -1.f; + row[i] *= -1.f; + } + } + + d.quaternion[0] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] - row[1][1] - row[2][2], 0.0f)); + d.quaternion[1] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] + row[1][1] - row[2][2], 0.0f)); + d.quaternion[2] = 0.5f * Math::SquareRoot(Math::Max(1.f - row[0][0] - row[1][1] + row[2][2], 0.0f)); + d.quaternion[3] = 0.5f * Math::SquareRoot(Math::Max(1.f + row[0][0] + row[1][1] + row[2][2], 0.0f)); + + if (row[2][1] > row[1][2]) + d.quaternion[0] *= -1.f; + if (row[0][2] > row[2][0]) + d.quaternion[1] *= -1.f; + if (row[1][0] > row[0][1]) + d.quaternion[2] *= -1.f; + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TransformUtilities.h b/thirdparty/RmlUi/Source/Core/TransformUtilities.h new file mode 100644 index 000000000..1812e86f9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TransformUtilities.h @@ -0,0 +1,71 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_TRANSFORMUTILITIES_H +#define RMLUI_CORE_TRANSFORMUTILITIES_H + +#include "../../Include/RmlUi/Core/Header.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +struct TransformPrimitive; +namespace Transforms { struct DecomposedMatrix4; } + + +namespace TransformUtilities +{ + // Set the primitive to its identity value. + void SetIdentity(TransformPrimitive& primitive) noexcept; + + // Resolve the primitive into a transformation matrix, given the current element properties and layout. + Matrix4f ResolveTransform(const TransformPrimitive& primitive, Element& e) noexcept; + + // Prepares the primitive for interpolation. This must be done before calling InterpolateWith(). + // Promote units to basic types which can be interpolated, that is, convert 'length -> pixel' for unresolved primitives. + // Returns false if the owning transform must to be converted to a DecomposedMatrix4 primitive. + bool PrepareForInterpolation(TransformPrimitive& primitive, Element& e) noexcept; + + // If primitives do not match, try to convert them to a common generic type, e.g. TranslateX -> Translate3D. + // Returns true if they are already the same type or were converted to a common generic type. + bool TryConvertToMatchingGenericType(TransformPrimitive& p0, TransformPrimitive& p1) noexcept; + + // Interpolate the target primitive with another primitive, weighted by alpha [0, 1]. + // Primitives must be of the same type, and PrepareForInterpolation() must previously have been called on both. + bool InterpolateWith(TransformPrimitive& target, const TransformPrimitive& other, float alpha) noexcept; + + // Decompose a Matrix4 into its decomposed components. + // Returns true on success, or false if the matrix is singular. + bool Decompose(Transforms::DecomposedMatrix4& decomposed_matrix, const Matrix4f& matrix) noexcept; + + String ToString(const TransformPrimitive& primitive) noexcept; +} + + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Tween.cpp b/thirdparty/RmlUi/Source/Core/Tween.cpp new file mode 100644 index 000000000..355ff9788 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Tween.cpp @@ -0,0 +1,239 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Tween.h" +#include "../../Include/RmlUi/Core/Math.h" +#include + +namespace Rml { + +namespace TweenFunctions { + +// Tweening functions below. +// Partly based on http://libclaw.sourceforge.net/tweeners.html + +static inline float square(float t) { + return t * t; +} + +static float back(float t) +{ + return t * t * (2.70158f * t - 1.70158f); +} + +static float bounce(float t) +{ + if (t > 1.f - 1.f / 2.75f) + return 1.f - 7.5625f * square(1.f - t); + else if (t > 1.f - 2.f / 2.75f) + return 1.0f - (7.5625f * square(1.f - t - 1.5f / 2.75f) + 0.75f); + else if (t > 1.f - 2.5f / 2.75f) + return 1.0f - (7.5625f * square(1.f - t - 2.25f / 2.75f) + 0.9375f); + return 1.0f - (7.5625f * square(1.f - t - 2.625f / 2.75f) + 0.984375f); +} + +static float circular(float t) +{ + return 1.f - Math::SquareRoot(1.f - t * t); +} + +static float cubic(float t) +{ + return t * t * t; +} + +static float elastic(float t) +{ + if (t == 0) return t; + if (t == 1) return t; + return -Math::Exp(7.24f * (t - 1.f)) * Math::Sin((t - 1.1f) * 2.f * Math::RMLUI_PI / 0.4f); +} + +static float exponential(float t) +{ + if (t == 0) return t; + if (t == 1) return t; + return Math::Exp(7.24f * (t - 1.f)); +} + +static float linear(float t) +{ + return t; +} + +static float quadratic(float t) +{ + return t * t; +} + +static float quartic(float t) +{ + return t * t * t * t; +} + +static float quintic(float t) +{ + return t * t * t * t * t; +} + +static float sine(float t) +{ + return 1.f - Math::Cos(t * Math::RMLUI_PI * 0.5f); +} + +} // namespace TweenFunctions + + +Tween::Tween(Type type, Direction direction) { + if (direction & In) type_in = type; + if (direction & Out) type_out = type; +} +Tween::Tween(Type type_in, Type type_out) : type_in(type_in), type_out(type_out) {} +Tween::Tween(CallbackFnc callback, Direction direction) : callback(callback) { + if (direction & In) type_in = Callback; + if (direction & Out) type_out = Callback; +} +float Tween::operator()(float t) const +{ + if (type_in != None && type_out == None) + { + return in(t); + } + if (type_in == None && type_out != None) + { + return out(t); + } + if (type_in != None && type_out != None) + { + return in_out(t); + } + return t; +} + +void Tween::reverse() +{ + std::swap(type_in, type_out); +} + +bool Tween::operator==(const Tween& other) const +{ + return type_in == other.type_in && type_out == other.type_out && callback == other.callback; +} + +bool Tween::operator!=(const Tween& other) const +{ + return !(*this == other); +} + +String Tween::to_string() const +{ + static const Array type_str = { { "none", "back", "bounce", "circular", "cubic", "elastic", "exponential", "linear", "quadratic", "quartic", "quintic", "sine", "callback" } }; + + if (size_t(type_in) < type_str.size() && size_t(type_out) < type_str.size()) + { + if (type_in == None && type_out == None) + { + return "none"; + } + else if (type_in == type_out) + { + return type_str[size_t(type_in)] + String("-in-out"); + } + else if (type_in == None) + { + return type_str[size_t(type_out)] + String("-out"); + } + else if (type_out == None) + { + return type_str[size_t(type_in)] + String("-in"); + } + else if (type_in != type_out) + { + return type_str[size_t(type_in)] + String("-in-") + type_str[size_t(type_out)] + String("-out"); + } + } + return "unknown"; +} + +float Tween::tween(Type type, float t) const +{ + using namespace TweenFunctions; + + switch (type) + { + case Back: + return back(t); + case Bounce: + return bounce(t); + case Circular: + return circular(t); + case Cubic: + return cubic(t); + case Elastic: + return elastic(t); + case Exponential: + return exponential(t); + case Linear: + return linear(t); + case Quadratic: + return quadratic(t); + case Quartic: + return quartic(t); + case Quintic: + return quintic(t); + case Sine: + return sine(t); + case Callback: + if (callback) + return (*callback)(t); + break; + default: + break; + } + return t; +} + +float Tween::in(float t) const +{ + return tween(type_in, t); +} + +float Tween::out(float t) const +{ + return 1.0f - tween(type_out, 1.0f - t); +} + +float Tween::in_out(float t) const +{ + if (t < 0.5f) + return tween(type_in, 2.0f * t) * 0.5f; + else + return 0.5f + out(2.0f * t - 1.0f) * 0.5f; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/TypeConverter.cpp b/thirdparty/RmlUi/Source/Core/TypeConverter.cpp new file mode 100644 index 000000000..d527df41f --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/TypeConverter.cpp @@ -0,0 +1,153 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/TypeConverter.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/Animation.h" +#include "../../Include/RmlUi/Core/Transform.h" +#include "../../Include/RmlUi/Core/TransformPrimitive.h" +#include "TransformUtilities.h" + +namespace Rml { + +bool TypeConverter::Convert(const TransformPtr& src, TransformPtr& dest) +{ + dest = src; + return true; +} + +bool TypeConverter::Convert(const TransformPtr& src, String& dest) +{ + if (src) + { + dest.clear(); + const Transform::PrimitiveList& primitives = src->GetPrimitives(); + for (size_t i = 0; i < primitives.size(); i++) + { + dest += TransformUtilities::ToString(primitives[i]); + if (i != primitives.size() - 1) + dest += ' '; + } + } + else + { + dest = "none"; + } + return true; +} + +bool TypeConverter::Convert(const TransitionList& src, TransitionList& dest) +{ + dest = src; + return true; +} + +bool TypeConverter::Convert(const TransitionList& src, String& dest) +{ + if (src.none) + { + dest = "none"; + return true; + } + String tmp; + for (size_t i = 0; i < src.transitions.size(); i++) + { + const Transition& t = src.transitions[i]; + dest += StyleSheetSpecification::GetPropertyName(t.id) + " "; + dest += t.tween.to_string() + " "; + if (TypeConverter< float, String >::Convert(t.duration, tmp)) dest += tmp + "s "; + if (t.delay > 0.0f && TypeConverter< float, String >::Convert(t.delay, tmp)) dest += tmp + "s "; + if (t.reverse_adjustment_factor > 0.0f && TypeConverter< float, String >::Convert(t.delay, tmp)) dest += tmp; + if (dest.size() > 0) dest.resize(dest.size() - 1); + if (i != src.transitions.size() - 1) dest += ", "; + } + return true; +} + +bool TypeConverter::Convert(const AnimationList& src, AnimationList& dest) +{ + dest = src; + return true; +} + +bool TypeConverter::Convert(const AnimationList& src, String& dest) +{ + String tmp; + for (size_t i = 0; i < src.size(); i++) + { + const Animation& a = src[i]; + if (TypeConverter< float, String >::Convert(a.duration, tmp)) dest += tmp + "s "; + dest += a.tween.to_string() + " "; + if (a.delay > 0.0f && TypeConverter< float, String >::Convert(a.delay, tmp)) dest += tmp + "s "; + if (a.alternate) dest += "alternate "; + if (a.paused) dest += "paused "; + if (a.num_iterations == -1) dest += "infinite "; + else if (TypeConverter< int, String >::Convert(a.num_iterations, tmp)) dest += tmp + " "; + dest += a.name; + if (i != src.size() - 1) dest += ", "; + } + return true; +} + +bool TypeConverter::Convert(const DecoratorsPtr& src, DecoratorsPtr& dest) +{ + dest = src; + return true; +} + + +bool TypeConverter::Convert(const DecoratorsPtr& src, String& dest) +{ + if (!src || src->list.empty()) + dest = "none"; + else + dest += src->value; + return true; +} + + +bool TypeConverter::Convert(const FontEffectsPtr& src, FontEffectsPtr& dest) +{ + dest = src; + return true; +} + + +bool TypeConverter::Convert(const FontEffectsPtr& src, String& dest) +{ + if (!src || src->list.empty()) + dest = "none"; + else + dest += src->value; + return true; +} + + + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/URL.cpp b/thirdparty/RmlUi/Source/Core/URL.cpp new file mode 100644 index 000000000..e0e3bcda3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/URL.cpp @@ -0,0 +1,625 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/URL.h" +#include + +namespace Rml { + +const char* DEFAULT_PROTOCOL = "file"; + +// Constructs an Empty URL. +URL::URL() +{ + port = 0; + url_dirty = false; +} + +// Constructs a new URL from the given string. +URL::URL(const String& _url) +{ + port = 0; + RMLUI_VERIFY(SetURL(_url)); +} + +// Constructs a new URL from the given string. +URL::URL(const char* _url) +{ + port = 0; + RMLUI_VERIFY(SetURL(_url)); +} + +// Destroys the URL. +URL::~URL() +{ +} + +// Assigns a new URL to the object. +bool URL::SetURL(const String& _url) +{ + url_dirty = false; + url = _url; + + // Make sure an Empty URL is completely Empty. + if (url.empty()) + { + protocol.clear(); + login.clear(); + password.clear(); + host.clear(); + port = 0; + path.clear(); + file_name.clear(); + extension.clear(); + + return true; + } + + // Find the protocol. This consists of the string appearing before the + // '://' token (ie, file://, http://). + const char* host_begin = strchr(_url.c_str(), ':'); + if (nullptr != host_begin) + { + protocol = String(_url.c_str(), host_begin); + if (0 != strncmp(host_begin, "://", 3)) + { + char malformed_terminator[4] = {0, 0, 0, 0}; + strncpy(malformed_terminator, host_begin, 3); + Log::Message(Log::LT_ERROR, "Malformed protocol identifier found in URL %s; expected %s://, found %s%s.\n", _url.c_str(), protocol.c_str(), protocol.c_str(), malformed_terminator); + + return false; + } + host_begin += 3; + } + else + { + protocol = DEFAULT_PROTOCOL; + host_begin = _url.c_str(); + } + + + // We only want to look for a host if a protocol was specified. + const char* path_begin; + if (host_begin != _url.c_str()) + { + // Find the host. This is the string appearing after the protocol or after + // the username:password combination, and terminated either with a colon, + // if a port is specified, or a forward slash if there is no port. + + // Check for a login pair + const char* at_symbol = strchr( host_begin, '@' ); + if ( at_symbol ) + { + String login_password; + login_password = String( host_begin, at_symbol ); + host_begin = at_symbol + 1; + + const char* password_ptr = strchr( login_password.c_str(), ':' ); + if ( password_ptr ) + { + login = String( login_password.c_str(), password_ptr ); + password = String( password_ptr + 1 ); + } + else + { + login = login_password; + } + } + + // Get the host portion + path_begin = strchr(host_begin, '/'); + // Search for the colon in the host name, which will indicate a port. + const char* port_begin = strchr(host_begin, ':'); + if (nullptr != port_begin && (nullptr == path_begin || port_begin < path_begin)) + { + if (1 != sscanf(port_begin, ":%d", &port)) + { + Log::Message(Log::LT_ERROR, "Malformed port number found in URL %s.\n", _url.c_str()); + return false; + } + + host = String(host_begin, port_begin); + + // Don't continue if there is no path. + if (nullptr == path_begin) + { + return true; + } + + // Increment the path string past the trailing slash. + ++path_begin; + } + else + { + port = -1; + + if (nullptr == path_begin) + { + host = host_begin; + return true; + } + else + { + // Assign the host name, then increment the path string past the + // trailing slash. + host = String(host_begin, path_begin); + ++path_begin; + } + } + } + else + { + path_begin = _url.c_str(); + } + + // Check for parameters + String path_segment; + const char* parameters = strchr(path_begin, '?'); + if ( parameters ) + { + // Pull the path segment out, so further processing doesn't read the parameters + path_segment = String(path_begin, parameters); + path_begin = path_segment.c_str(); + + // Loop through all parameters, loading them + StringList parameter_list; + StringUtilities::ExpandString( parameter_list, parameters + 1, '&' ); + for ( size_t i = 0; i < parameter_list.size(); i++ ) + { + // Split into key and value + StringList key_value; + StringUtilities::ExpandString( key_value, parameter_list[i], '=' ); + + key_value[0] = UrlDecode(key_value[0]); + if ( key_value.size() == 2 ) + this->parameters[key_value[0]] = UrlDecode(key_value[1]); + else + this->parameters[key_value[0]] = ""; + } + } + + + // Find the path. This is the string appearing after the host, terminated + // by the last forward slash. + const char* file_name_begin = strrchr(path_begin, '/'); + if (nullptr == file_name_begin) + { + // No path! + file_name_begin = path_begin; + path = ""; + } + else + { + // Copy the path including the trailing slash. + path = String(path_begin, ++file_name_begin); + + // Normalise the path, stripping any ../'s from it + size_t parent_dir_pos = String::npos; + while ((parent_dir_pos = path.find("/..")) != String::npos && parent_dir_pos != 0) + { + // Find the start of the parent directory. + size_t parent_dir_start_pos = path.rfind('/', parent_dir_pos - 1); + if (parent_dir_start_pos == String::npos) + parent_dir_start_pos = 0; + + // Strip out the parent dir and the /.. + path.erase(parent_dir_start_pos, parent_dir_pos - parent_dir_start_pos + 3); + + // We've altered the URL, mark it dirty + url_dirty = true; + } + } + + + // Find the file name. This is the string after the trailing slash of the + // path, and just before the extension. + const char* extension_begin = strrchr(file_name_begin, '.'); + if (nullptr == extension_begin) + { + file_name = file_name_begin; + extension = ""; + } + else + { + file_name = String(file_name_begin, extension_begin); + extension = extension_begin + 1; + } + + return true; +} + +// Returns the entire URL. +const String& URL::GetURL() const +{ + if (url_dirty) + ConstructURL(); + + return url; +} + +// Sets the URL's protocol. +bool URL::SetProtocol(const String& _protocol) +{ + protocol = _protocol; + url_dirty = true; + + return true; +} + +// Returns the protocol this URL is utilising. +const String& URL::GetProtocol() const +{ + return protocol; +} + +/// Sets the URL's login +bool URL::SetLogin( const String& _login ) +{ + login = _login; + url_dirty = true; + return true; +} + +/// Returns the URL's login +const String& URL::GetLogin() const +{ + return login; +} + +/// Sets the URL's password +bool URL::SetPassword(const String& _password) +{ + password = _password; + url_dirty = true; + return true; +} + +/// Returns the URL's password +const String& URL::GetPassword() const +{ + return password; +} + +// Sets the URL's host. +bool URL::SetHost(const String& _host) +{ + host = _host; + url_dirty = true; + + return true; +} + +// Returns the URL's host. +const String& URL::GetHost() const +{ + return host; +} + +// Sets the URL's port number. +bool URL::SetPort(int _port) +{ + port = _port; + url_dirty = true; + + return true; +} + +// Returns the URL's port number. +int URL::GetPort() const +{ + return port; +} + +// Sets the URL's path. +bool URL::SetPath(const String& _path) +{ + path = _path; + url_dirty = true; + + return true; +} + +// Prefixes the URL's existing path with the given prefix. +bool URL::PrefixPath(const String& prefix) +{ + // If there's no trailing slash on the end of the prefix, add one. + if (!prefix.empty() && + prefix[prefix.size() - 1] != '/') + path = prefix + "/" + path; + else + path = prefix + path; + + url_dirty = true; + + return true; +} + +// Returns the URL's path. +const String& URL::GetPath() const +{ + return path; +} + +// Sets the URL's file name. +bool URL::SetFileName(const String& _file_name) +{ + file_name = _file_name; + url_dirty = true; + + return true; +} + +// Returns the URL's file name. +const String& URL::GetFileName() const +{ + return file_name; +} + +// Sets the URL's file extension. +bool URL::SetExtension(const String& _extension) +{ + extension = _extension; + url_dirty = true; + + return true; +} + +// Returns the URL's file extension. +const String& URL::GetExtension() const +{ + return extension; +} + +// Gets the current parameters +const URL::Parameters& URL::GetParameters() const +{ + return parameters; +} + +// Set an individual parameter +void URL::SetParameter(const String& key, const String& value) +{ + parameters[key] = value; + url_dirty = true; +} + +// Set all parameters +void URL::SetParameters(const Parameters& _parameters) +{ + parameters = _parameters; + url_dirty = true; +} + +// Clear the parameters +void URL::ClearParameters() +{ + parameters.clear(); +} + +// Returns the URL's path, file name and extension. +String URL::GetPathedFileName() const +{ + String pathed_file_name = path; + + // Append the file name. + pathed_file_name += file_name; + + // Append the extension. + if (!extension.empty()) + { + pathed_file_name += "."; + pathed_file_name += extension; + } + + return pathed_file_name; +} + +String URL::GetQueryString() const +{ + String query_string; + + int count = 0; + for ( Parameters::const_iterator itr = parameters.begin(); itr != parameters.end(); ++itr ) + { + query_string += ( count == 0 ) ? "" : "&"; + + query_string += UrlEncode((*itr).first); + query_string += "="; + query_string += UrlEncode((*itr).second); + + count++; + } + + return query_string; +} + +// Less-than operator for use as a key in STL containers. +bool URL::operator<(const URL& rhs) const +{ + if (url_dirty) + ConstructURL(); + if (rhs.url_dirty) + rhs.ConstructURL(); + + return url < rhs.url; +} + +void URL::ConstructURL() const +{ + url = ""; + + // Append the protocol. + if (!protocol.empty() && !host.empty()) + { + url = protocol; + url += "://"; + } + + // Append login and password + if (!login.empty()) + { + url += login ; + if (!password.empty()) + { + url += ":" ; + url += password ; + } + url += "@" ; + } + RMLUI_ASSERTMSG( password.empty() || ( !password.empty() && !login.empty() ), "Can't have a password without a login!" ); + + // Append the host. + url += host; + + // Only check ports if there is some host/protocol part + if ( !url.empty() ) + { + if (port > 0) + { + RMLUI_ASSERTMSG( !host.empty(), "Can't have a port without a host!" ); + char port_string[16]; + sprintf(port_string, ":%d/", port); + url += port_string; + } + else + { + url += "/"; + } + } + + // Append the path. + if (!path.empty()) + { + url += path; + } + + // Append the file name. + url += file_name; + + // Append the extension. + if (!extension.empty()) + { + url += "."; + url += extension; + } + + // Append parameters + if (!parameters.empty()) + { + url += "?"; + url += GetQueryString(); + } + + url_dirty = false; +} + +String URL::UrlEncode(const String &value) +{ + String encoded; + char hex[4] = {0,0,0,0}; + + encoded.clear(); + + const char *value_c = value.c_str(); + for (String::size_type i = 0; value_c[i]; i++) + { + char c = value_c[i]; + if (IsUnreservedChar(c)) + encoded += c; + else + { + sprintf(hex, "%%%02X", c); + encoded += hex; + } + } + + return encoded; +} + +String URL::UrlDecode(const String &value) +{ + String decoded; + + decoded.clear(); + + const char *value_c = value.c_str(); + String::size_type value_len = value.size(); + for (String::size_type i = 0; i < value_len; i++) + { + char c = value_c[i]; + if (c == '+') + { + decoded += ' '; + } + else if (c == '%') + { + char *endp; + String t = value.substr(i+1, 2); + int ch = strtol(t.c_str(), &endp, 16); + if (*endp == '\0') + decoded += char(ch); + else + decoded += t; + i += 2; + } + else + { + decoded += c; + } + } + + return decoded; +} + +bool URL::IsUnreservedChar(const char in) +{ + switch (in) + { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': + case '-': case '.': case '_': case '~': + return true; + default: + break; + } + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Utilities.h b/thirdparty/RmlUi/Source/Core/Utilities.h new file mode 100644 index 000000000..392ae5e75 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Utilities.h @@ -0,0 +1,45 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_UTILITIES_H +#define RMLUI_CORE_UTILITIES_H + +namespace Rml { + +namespace Utilities { + +template +inline void HashCombine(std::size_t& seed, const T& v) +{ + Hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +} +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/Variant.cpp b/thirdparty/RmlUi/Source/Core/Variant.cpp new file mode 100644 index 000000000..5778f3568 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Variant.cpp @@ -0,0 +1,507 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Variant.h" +#include + +namespace Rml { + +Variant::Variant() : type(NONE) +{ + // Make sure our object size assumptions fit inside the static buffer + static_assert(sizeof(Colourb) <= LOCAL_DATA_SIZE, "Local data too small for Colourb"); + static_assert(sizeof(Colourf) <= LOCAL_DATA_SIZE, "Local data too small for Colourf"); + static_assert(sizeof(Vector4f) <= LOCAL_DATA_SIZE, "Local data too small for Vector4f"); + static_assert(sizeof(String) <= LOCAL_DATA_SIZE, "Local data too small for String"); + static_assert(sizeof(TransformPtr) <= LOCAL_DATA_SIZE, "Local data too small for TransformPtr"); + static_assert(sizeof(TransitionList) <= LOCAL_DATA_SIZE, "Local data too small for TransitionList"); + static_assert(sizeof(AnimationList) <= LOCAL_DATA_SIZE, "Local data too small for AnimationList"); + static_assert(sizeof(DecoratorsPtr) <= LOCAL_DATA_SIZE, "Local data too small for DecoratorsPtr"); + static_assert(sizeof(FontEffectsPtr) <= LOCAL_DATA_SIZE, "Local data too small for FontEffectsPtr"); +} + +Variant::Variant(const Variant& copy) : type(NONE) +{ + Set(copy); +} + +Variant::Variant(Variant&& other) noexcept : type(NONE) +{ + Set(std::move(other)); +} + +Variant::~Variant() +{ + Clear(); +} + +void Variant::Clear() +{ + // Free any allocated types. + switch (type) + { + case STRING: + { + // Clean up the string. + String* string = (String*)data; + string->~String(); + } + break; + case TRANSFORMPTR: + { + // Clean up the transform. + TransformPtr* transform = (TransformPtr*)data; + transform->~TransformPtr(); + } + break; + case TRANSITIONLIST: + { + // Clean up the transition list. + TransitionList* transition_list = (TransitionList*)data; + transition_list->~TransitionList(); + } + break; + case ANIMATIONLIST: + { + // Clean up the transition list. + AnimationList* animation_list = (AnimationList*)data; + animation_list->~AnimationList(); + } + break; + case DECORATORSPTR: + { + DecoratorsPtr* decorators = (DecoratorsPtr*)data; + decorators->~DecoratorsPtr(); + } + break; + case FONTEFFECTSPTR: + { + FontEffectsPtr* font_effects = (FontEffectsPtr*)data; + font_effects->~shared_ptr(); + } + break; + default: + break; + } + type = NONE; +} + + + +////////////////////////////////////////////////// +// Set methods +////////////////////////////////////////////////// + +#define SET_VARIANT(type) *((type*)data) = value; + +void Variant::Set(const Variant& copy) +{ + switch (copy.type) + { + case STRING: + Set(*(String*)copy.data); + break; + + case TRANSFORMPTR: + Set(*(TransformPtr*)copy.data); + break; + + case TRANSITIONLIST: + Set(*(TransitionList*)copy.data); + break; + + case ANIMATIONLIST: + Set(*(AnimationList*)copy.data); + break; + + case DECORATORSPTR: + Set(*(DecoratorsPtr*)copy.data); + break; + + case FONTEFFECTSPTR: + Set(*(FontEffectsPtr*)copy.data); + break; + + default: + memcpy(data, copy.data, LOCAL_DATA_SIZE); + type = copy.type; + break; + } + RMLUI_ASSERT(type == copy.type); +} + +void Variant::Set(Variant&& other) +{ + switch (other.type) + { + case STRING: + Set(std::move(*(String*)other.data)); + break; + + case TRANSFORMPTR: + Set(std::move(*(TransformPtr*)other.data)); + break; + + case TRANSITIONLIST: + Set(std::move(*(TransitionList*)other.data)); + break; + + case ANIMATIONLIST: + Set(std::move(*(AnimationList*)other.data)); + break; + + case DECORATORSPTR: + Set(std::move(*(DecoratorsPtr*)other.data)); + break; + + case FONTEFFECTSPTR: + Set(std::move(*(FontEffectsPtr*)other.data)); + break; + + default: + memcpy(data, other.data, LOCAL_DATA_SIZE); + type = other.type; + break; + } + RMLUI_ASSERT(type == other.type); +} + +void Variant::Set(const bool value) +{ + type = BOOL; + SET_VARIANT(bool); +} + +void Variant::Set(const byte value) +{ + type = BYTE; + SET_VARIANT(byte); +} + +void Variant::Set(const char value) +{ + type = CHAR; + SET_VARIANT(char); +} + +void Variant::Set(const float value) +{ + type = FLOAT; + SET_VARIANT(float); +} + +void Variant::Set(const double value) +{ + type = DOUBLE; + SET_VARIANT(double); +} + +void Variant::Set(const int value) +{ + type = INT; + SET_VARIANT(int); +} + +void Variant::Set(const int64_t value) +{ + type = INT64; + SET_VARIANT(int64_t); +} + +void Variant::Set(const char* value) +{ + Set(String(value)); +} + +void Variant::Set(void* voidptr) +{ + type = VOIDPTR; + memcpy(data, &voidptr, sizeof(void*)); +} + +void Variant::Set(const Vector2f& value) +{ + type = VECTOR2; + SET_VARIANT(Vector2f); +} + +void Variant::Set(const Vector3f& value) +{ + type = VECTOR3; + SET_VARIANT(Vector3f); +} + +void Variant::Set(const Vector4f& value) +{ + type = VECTOR4; + SET_VARIANT(Vector4f); +} + +void Variant::Set(const Colourf& value) +{ + type = COLOURF; + SET_VARIANT(Colourf); +} + +void Variant::Set(const Colourb& value) +{ + type = COLOURB; + SET_VARIANT(Colourb); +} + +void Variant::Set(ScriptInterface* value) +{ + type = SCRIPTINTERFACE; + memcpy(data, &value, sizeof(ScriptInterface*)); +} + + +void Variant::Set(const String& value) +{ + if (type == STRING) + { + (*(String*)data) = value; + } + else + { + type = STRING; + new(data) String(value); + } +} +void Variant::Set(String&& value) +{ + if (type == STRING) + { + (*(String*)data) = std::move(value); + } + else + { + type = STRING; + new(data) String(std::move(value)); + } +} + + +void Variant::Set(const TransformPtr& value) +{ + if (type == TRANSFORMPTR) + { + SET_VARIANT(TransformPtr); + } + else + { + type = TRANSFORMPTR; + new(data) TransformPtr(value); + } +} +void Variant::Set(TransformPtr&& value) +{ + if (type == TRANSFORMPTR) + { + (*(TransformPtr*)data) = std::move(value); + } + else + { + type = TRANSFORMPTR; + new(data) TransformPtr(std::move(value)); + } +} + +void Variant::Set(const TransitionList& value) +{ + if (type == TRANSITIONLIST) + { + *(TransitionList*)data = value; + } + else + { + type = TRANSITIONLIST; + new(data) TransitionList(value); + } +} +void Variant::Set(TransitionList&& value) +{ + if (type == TRANSITIONLIST) + { + (*(TransitionList*)data) = std::move(value); + } + else + { + type = TRANSITIONLIST; + new(data) TransitionList(std::move(value)); + } +} + +void Variant::Set(const AnimationList& value) +{ + if (type == ANIMATIONLIST) + { + *(AnimationList*)data = value; + } + else + { + type = ANIMATIONLIST; + new(data) AnimationList(value); + } +} +void Variant::Set(AnimationList&& value) +{ + if (type == ANIMATIONLIST) + { + (*(AnimationList*)data) = std::move(value); + } + else + { + type = ANIMATIONLIST; + new(data) AnimationList(std::move(value)); + } +} + +void Variant::Set(const DecoratorsPtr& value) +{ + if (type == DECORATORSPTR) + { + *(DecoratorsPtr*)data = value; + } + else + { + type = DECORATORSPTR; + new(data) DecoratorsPtr(value); + } +} +void Variant::Set(DecoratorsPtr&& value) +{ + if (type == DECORATORSPTR) + { + (*(DecoratorsPtr*)data) = std::move(value); + } + else + { + type = DECORATORSPTR; + new(data) DecoratorsPtr(std::move(value)); + } +} +void Variant::Set(const FontEffectsPtr& value) +{ + if (type == FONTEFFECTSPTR) + { + *(FontEffectsPtr*)data = value; + } + else + { + type = FONTEFFECTSPTR; + new(data) FontEffectsPtr(value); + } +} +void Variant::Set(FontEffectsPtr&& value) +{ + if (type == FONTEFFECTSPTR) + { + (*(FontEffectsPtr*)data) = std::move(value); + } + else + { + type = FONTEFFECTSPTR; + new(data) FontEffectsPtr(std::move(value)); + } +} + +Variant& Variant::operator=(const Variant& copy) +{ + if (copy.type != type) + Clear(); + Set(copy); + return *this; +} + +Variant& Variant::operator=(Variant&& other) noexcept +{ + if (other.type != type) + Clear(); + Set(std::move(other)); + return *this; +} + +#define DEFAULT_VARIANT_COMPARE(TYPE) static_cast(*(TYPE*)data) == static_cast(*(TYPE*)other.data) + +bool Variant::operator==(const Variant & other) const +{ + if (type != other.type) + return false; + + switch (type) + { + case BOOL: + return DEFAULT_VARIANT_COMPARE(bool); + case BYTE: + return DEFAULT_VARIANT_COMPARE(byte); + case CHAR: + return DEFAULT_VARIANT_COMPARE(char); + case FLOAT: + return DEFAULT_VARIANT_COMPARE(float); + case DOUBLE: + return DEFAULT_VARIANT_COMPARE(double); + case INT: + return DEFAULT_VARIANT_COMPARE(int); + case INT64: + return DEFAULT_VARIANT_COMPARE(int64_t); + case STRING: + return DEFAULT_VARIANT_COMPARE(String); + case VECTOR2: + return DEFAULT_VARIANT_COMPARE(Vector2f); + case VECTOR3: + return DEFAULT_VARIANT_COMPARE(Vector3f); + case VECTOR4: + return DEFAULT_VARIANT_COMPARE(Vector4f); + case COLOURF: + return DEFAULT_VARIANT_COMPARE(Colourf); + case COLOURB: + return DEFAULT_VARIANT_COMPARE(Colourb); + case SCRIPTINTERFACE: + return DEFAULT_VARIANT_COMPARE(ScriptInterface*); + case VOIDPTR: + return DEFAULT_VARIANT_COMPARE(void*); + case TRANSFORMPTR: + return DEFAULT_VARIANT_COMPARE(TransformPtr); + case TRANSITIONLIST: + return DEFAULT_VARIANT_COMPARE(TransitionList); + case ANIMATIONLIST: + return DEFAULT_VARIANT_COMPARE(AnimationList); + case DECORATORSPTR: + return DEFAULT_VARIANT_COMPARE(DecoratorsPtr); + case FONTEFFECTSPTR: + return DEFAULT_VARIANT_COMPARE(FontEffectsPtr); + case NONE: + return true; + break; + } + RMLUI_ERRORMSG("Variant comparison not implemented for this type."); + return false; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Vector3.cpp b/thirdparty/RmlUi/Source/Core/Vector3.cpp new file mode 100644 index 000000000..57cfe1491 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Vector3.cpp @@ -0,0 +1,45 @@ +/* + * This source file is part of rmlui, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +Vector3i operator*(int lhs, const Vector3i& rhs) +{ + return Vector3i(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); +} + +Vector3f operator*(float lhs, const Vector3f& rhs) +{ + return Vector3f(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); +} + + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/Vector4.cpp b/thirdparty/RmlUi/Source/Core/Vector4.cpp new file mode 100644 index 000000000..c34605a59 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/Vector4.cpp @@ -0,0 +1,53 @@ +/* + * This source file is part of rmlui, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2014 Markus Schöngart + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +Vector4i operator*(int lhs, const Vector4i& rhs) +{ + return Vector4i(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w); +} + +Vector4f operator*(float lhs, const Vector4f& rhs) +{ + return Vector4f(lhs * rhs.x, lhs * rhs.y, lhs * rhs.z, lhs * rhs.w); +} + +template <> +Vector4< float > Vector4< float >::Normalise() const +{ + float magnitude = Magnitude(); + if (Math::IsZero(magnitude)) + return *this; + + return *this / magnitude; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/WidgetScroll.cpp b/thirdparty/RmlUi/Source/Core/WidgetScroll.cpp new file mode 100644 index 000000000..d760f6733 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/WidgetScroll.cpp @@ -0,0 +1,558 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "WidgetScroll.h" +#include "Clock.h" +#include "LayoutEngine.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Property.h" + +namespace Rml { + +static const float DEFAULT_REPEAT_DELAY = 0.5f; +static const float DEFAULT_REPEAT_PERIOD = 0.1f; + +WidgetScroll::WidgetScroll(Element* _parent) +{ + parent = _parent; + + orientation = UNKNOWN; + + track = nullptr; + bar = nullptr; + arrows[0] = nullptr; + arrows[1] = nullptr; + + bar_position = 0; + bar_drag_anchor = 0; + + arrow_timers[0] = -1; + arrow_timers[1] = -1; + last_update_time = 0; + + track_length = 0; + bar_length = 0; + line_height = 12; +} + +WidgetScroll::~WidgetScroll() +{ + if (bar != nullptr) + { + bar->RemoveEventListener(EventId::Drag, this); + bar->RemoveEventListener(EventId::Dragstart, this); + } + + if (track != nullptr) + track->RemoveEventListener(EventId::Click, this); + + for (int i = 0; i < 2; i++) + { + if (arrows[i] != nullptr) + { + arrows[i]->RemoveEventListener(EventId::Mousedown, this); + arrows[i]->RemoveEventListener(EventId::Mouseup, this); + arrows[i]->RemoveEventListener(EventId::Mouseout, this); + } + } +} + +// Initialises the slider to a given orientation. +bool WidgetScroll::Initialise(Orientation _orientation) +{ + // Check that we haven't already been successfully initialised. + if (orientation != UNKNOWN) + { + RMLUI_ERROR; + return false; + } + + // Check that a valid orientation has been passed in. + if (_orientation != HORIZONTAL && + _orientation != VERTICAL) + { + RMLUI_ERROR; + return false; + } + + orientation = _orientation; + + // Create all of our child elements as standard elements, and abort if we can't create them. + ElementPtr track_element = Factory::InstanceElement(parent, "*", "slidertrack", XMLAttributes()); + ElementPtr bar_element = Factory::InstanceElement(parent, "*", "sliderbar", XMLAttributes()); + ElementPtr arrow0_element = Factory::InstanceElement(parent, "*", "sliderarrowdec", XMLAttributes()); + ElementPtr arrow1_element = Factory::InstanceElement(parent, "*", "sliderarrowinc", XMLAttributes()); + + if (!track_element || !bar_element || !arrow0_element || !arrow1_element) + { + return false; + } + + // Add them as non-DOM elements. + track = parent->AppendChild(std::move(track_element), false); + bar = parent->AppendChild(std::move(bar_element), false); + arrows[0] = parent->AppendChild(std::move(arrow0_element), false); + arrows[1] = parent->AppendChild(std::move(arrow1_element), false); + + bar->SetProperty(PropertyId::Drag, Property(Style::Drag::Drag)); + + // Attach the listeners as appropriate. + bar->AddEventListener(EventId::Drag, this); + bar->AddEventListener(EventId::Dragstart, this); + + track->AddEventListener(EventId::Click, this); + + for (int i = 0; i < 2; i++) + { + arrows[i]->AddEventListener(EventId::Mousedown, this); + arrows[i]->AddEventListener(EventId::Mouseup, this); + arrows[i]->AddEventListener(EventId::Mouseout, this); + } + + return true; +} + +// Updates the key repeats for the increment / decrement arrows. +void WidgetScroll::Update() +{ + for (int i = 0; i < 2; i++) + { + bool updated_time = false; + float delta_time = 0; + + if (arrow_timers[i] > 0) + { + if (!updated_time) + { + double current_time = Clock::GetElapsedTime(); + delta_time = float(current_time - last_update_time); + last_update_time = current_time; + } + + arrow_timers[i] -= delta_time; + while (arrow_timers[i] <= 0) + { + arrow_timers[i] += DEFAULT_REPEAT_PERIOD; + SetBarPosition(i == 0 ? OnLineDecrement() : OnLineIncrement()); + } + } + } +} + +// Sets the position of the bar. +void WidgetScroll::SetBarPosition(float _bar_position) +{ + bar_position = Math::Clamp(_bar_position, 0.0f, 1.0f); + PositionBar(); + + // 'parent' is the scrollbar element, its parent again is the actual element we want to scroll + Element* element_scroll = parent->GetParentNode(); + if (!element_scroll) + { + RMLUI_ERROR; + return; + } + + if (orientation == VERTICAL) + element_scroll->SetScrollTop(bar_position * (element_scroll->GetScrollHeight() - element_scroll->GetClientHeight())); + else if (orientation == HORIZONTAL) + element_scroll->SetScrollLeft(bar_position * (element_scroll->GetScrollWidth() - element_scroll->GetClientWidth())); +} + +// Returns the current position of the bar. +float WidgetScroll::GetBarPosition() const +{ + return bar_position; +} + +// Returns the slider's orientation. +WidgetScroll::Orientation WidgetScroll::GetOrientation() const +{ + return orientation; +} + +// Sets the dimensions to the size of the slider. +void WidgetScroll::GetDimensions(Vector2f& dimensions) const +{ + switch (orientation) + { + RMLUI_UNUSED_SWITCH_ENUM(UNKNOWN); + case VERTICAL: dimensions.x = 16; dimensions.y = 256; break; + case HORIZONTAL: dimensions.x = 256; dimensions.y = 16; break; + } +} + +// Lays out and resizes the internal elements. +void WidgetScroll::FormatElements(const Vector2f& containing_block, bool resize_element, float slider_length, float bar_length) +{ + int length_axis = orientation == VERTICAL ? 1 : 0; + + // Build the box for the containing slider element. As the containing block is not guaranteed to have a defined + // height, we must use the width for both axes. + Box parent_box; + LayoutEngine::BuildBox(parent_box, Vector2f(containing_block.x, containing_block.x), parent); + slider_length -= orientation == VERTICAL ? (parent_box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + parent_box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM)) : + (parent_box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + parent_box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT)); + + // Set the length of the slider. + Vector2f content = parent_box.GetSize(); + content[length_axis] = slider_length; + parent_box.SetContent(content); + // And set it on the slider element! + if (resize_element) + parent->SetBox(parent_box); + + // Generate the initial dimensions for the track. It'll need to be cut down to fit the arrows. + Box track_box; + LayoutEngine::BuildBox(track_box, parent_box.GetSize(), track); + content = track_box.GetSize(); + content[length_axis] = slider_length -= orientation == VERTICAL ? (track_box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + track_box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM)) : + (track_box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + track_box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT)); + // If no height has been explicitly specified for the track, it'll be initialised to -1 as per normal block + // elements. We'll fix that up here. + if (orientation == HORIZONTAL && + content.y < 0) + content.y = parent_box.GetSize().y; + + // Now we size the arrows. + for (int i = 0; i < 2; i++) + { + Box arrow_box; + LayoutEngine::BuildBox(arrow_box, parent_box.GetSize(), arrows[i]); + + // Clamp the size to (0, 0). + Vector2f arrow_size = arrow_box.GetSize(); + if (arrow_size.x < 0 || + arrow_size.y < 0) + arrow_box.SetContent(Vector2f(0, 0)); + + arrows[i]->SetBox(arrow_box); + + // Shrink the track length by the arrow size. + content[length_axis] -= arrow_box.GetSize(Box::MARGIN)[length_axis]; + } + + // Now the track has been sized, we can fix everything into position. + track_box.SetContent(content); + track->SetBox(track_box); + + if (orientation == VERTICAL) + { + Vector2f offset(arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::LEFT), arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::TOP)); + arrows[0]->SetOffset(offset, parent); + + offset.x = track->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y += arrows[0]->GetBox().GetSize(Box::BORDER).y + arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM) + track->GetBox().GetEdge(Box::MARGIN, Box::TOP); + track->SetOffset(offset, parent); + + offset.x = arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y += track->GetBox().GetSize(Box::BORDER).y + track->GetBox().GetEdge(Box::MARGIN, Box::BOTTOM) + arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::TOP); + arrows[1]->SetOffset(offset, parent); + } + else + { + Vector2f offset(arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::LEFT), arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::TOP)); + arrows[0]->SetOffset(offset, parent); + + offset.x += arrows[0]->GetBox().GetSize(Box::BORDER).x + arrows[0]->GetBox().GetEdge(Box::MARGIN, Box::RIGHT) + track->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y = track->GetBox().GetEdge(Box::MARGIN, Box::TOP); + track->SetOffset(offset, parent); + + offset.x += track->GetBox().GetSize(Box::BORDER).x + track->GetBox().GetEdge(Box::MARGIN, Box::RIGHT) + arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::LEFT); + offset.y = arrows[1]->GetBox().GetEdge(Box::MARGIN, Box::TOP); + arrows[1]->SetOffset(offset, parent); + } + + FormatBar(bar_length); +} + +// Lays out and positions the bar element. +void WidgetScroll::FormatBar(float bar_length) +{ + Box bar_box; + LayoutEngine::BuildBox(bar_box, parent->GetBox().GetSize(), bar); + + const auto& computed = bar->GetComputedValues(); + + const Style::Width width = computed.width; + const Style::Height height = computed.height; + + Vector2f bar_box_content = bar_box.GetSize(); + if (orientation == HORIZONTAL) + { + if (height.type == height.Auto) + bar_box_content.y = parent->GetBox().GetSize().y; + } + + if (bar_length >= 0) + { + Vector2f track_size = track->GetBox().GetSize(); + + if (orientation == VERTICAL) + { + float track_length = track_size.y - (bar_box.GetCumulativeEdge(Box::CONTENT, Box::TOP) + bar_box.GetCumulativeEdge(Box::CONTENT, Box::BOTTOM)); + + if (height.type == height.Auto) + { + bar_box_content.y = track_length * bar_length; + + // Check for 'min-height' restrictions. + float min_track_length = ResolveValue(computed.min_height, track_length); + bar_box_content.y = Math::Max(min_track_length, bar_box_content.y); + + // Check for 'max-height' restrictions. + float max_track_length = ResolveValue(computed.max_height, track_length); + if (max_track_length > 0) + bar_box_content.y = Math::Min(max_track_length, bar_box_content.y); + } + + // Make sure we haven't gone further than we're allowed to (min-height may have made us too big). + bar_box_content.y = Math::Min(bar_box_content.y, track_length); + } + else + { + float track_length = track_size.x - (bar_box.GetCumulativeEdge(Box::CONTENT, Box::LEFT) + bar_box.GetCumulativeEdge(Box::CONTENT, Box::RIGHT)); + + if (width.type == width.Auto) + { + bar_box_content.x = track_length * bar_length; + + // Check for 'min-width' restrictions. + float min_track_length = ResolveValue(computed.min_width, track_length); + bar_box_content.x = Math::Max(min_track_length, bar_box_content.x); + + // Check for 'max-width' restrictions. + float max_track_length = ResolveValue(computed.max_width, track_length); + if (max_track_length > 0) + bar_box_content.x = Math::Min(max_track_length, bar_box_content.x); + } + + // Make sure we haven't gone further than we're allowed to (min-width may have made us too big). + bar_box_content.x = Math::Min(bar_box_content.x, track_length); + } + } + + // Set the new dimensions on the bar to re-decorate it. + bar_box.SetContent(bar_box_content); + bar->SetBox(bar_box); + + // Now that it's been resized, re-position it. + PositionBar(); +} + +// Handles events coming through from the slider's components. +void WidgetScroll::ProcessEvent(Event& event) +{ + if (event.GetTargetElement() == bar) + { + if (event == EventId::Drag) + { + if (orientation == HORIZONTAL) + { + float traversable_track_length = track->GetBox().GetSize(Box::CONTENT).x - bar->GetBox().GetSize(Box::CONTENT).x; + if (traversable_track_length > 0) + { + float traversable_track_origin = track->GetAbsoluteOffset().x + bar_drag_anchor; + float new_bar_position = (event.GetParameter< float >("mouse_x", 0) - traversable_track_origin) / traversable_track_length; + new_bar_position = Math::Clamp(new_bar_position, 0.0f, 1.0f); + + SetBarPosition(new_bar_position); + } + } + else + { + float traversable_track_length = track->GetBox().GetSize(Box::CONTENT).y - bar->GetBox().GetSize(Box::CONTENT).y; + if (traversable_track_length > 0) + { + float traversable_track_origin = track->GetAbsoluteOffset().y + bar_drag_anchor; + float new_bar_position = (event.GetParameter< float >("mouse_y", 0) - traversable_track_origin) / traversable_track_length; + new_bar_position = Math::Clamp(new_bar_position, 0.0f, 1.0f); + + SetBarPosition(new_bar_position); + } + } + } + else if (event == EventId::Dragstart) + { + if (orientation == HORIZONTAL) + bar_drag_anchor = event.GetParameter< int >("mouse_x", 0) - Math::RealToInteger(bar->GetAbsoluteOffset().x); + else + bar_drag_anchor = event.GetParameter< int >("mouse_y", 0) - Math::RealToInteger(bar->GetAbsoluteOffset().y); + } + } + else if (event.GetTargetElement() == track) + { + if (event == EventId::Click) + { + if (orientation == HORIZONTAL) + { + float mouse_position = event.GetParameter< float >("mouse_x", 0); + float click_position = (mouse_position - track->GetAbsoluteOffset().x) / track->GetBox().GetSize().x; + + SetBarPosition(click_position <= bar_position ? OnPageDecrement() : OnPageIncrement()); + } + else + { + float mouse_position = event.GetParameter< float >("mouse_y", 0); + float click_position = (mouse_position - track->GetAbsoluteOffset().y) / track->GetBox().GetSize().y; + + SetBarPosition(click_position <= bar_position ? OnPageDecrement() : OnPageIncrement()); + } + } + } + + if (event == EventId::Mousedown) + { + if (event.GetTargetElement() == arrows[0]) + { + arrow_timers[0] = DEFAULT_REPEAT_DELAY; + last_update_time = Clock::GetElapsedTime(); + SetBarPosition(OnLineDecrement()); + } + else if (event.GetTargetElement() == arrows[1]) + { + arrow_timers[1] = DEFAULT_REPEAT_DELAY; + last_update_time = Clock::GetElapsedTime(); + SetBarPosition(OnLineIncrement()); + } + } + else if (event == EventId::Mouseup || + event == EventId::Mouseout) + { + if (event.GetTargetElement() == arrows[0]) + arrow_timers[0] = -1; + else if (event.GetTargetElement() == arrows[1]) + arrow_timers[1] = -1; + } +} + +void WidgetScroll::PositionBar() +{ + const Vector2f& track_dimensions = track->GetBox().GetSize(); + const Vector2f& bar_dimensions = bar->GetBox().GetSize(Box::BORDER); + + if (orientation == VERTICAL) + { + float traversable_track_length = track_dimensions.y - bar_dimensions.y; + bar->SetOffset(Vector2f(bar->GetBox().GetEdge(Box::MARGIN, Box::LEFT), track->GetRelativeOffset().y + traversable_track_length * bar_position), parent); + } + else + { + float traversable_track_length = track_dimensions.x - bar_dimensions.x; + bar->SetOffset(Vector2f(track->GetRelativeOffset().x + traversable_track_length * bar_position, bar->GetBox().GetEdge(Box::MARGIN, Box::TOP)), parent); + } +} + + + +// Sets the length of the entire track in some arbitrary unit. +void WidgetScroll::SetTrackLength(float _track_length, bool RMLUI_UNUSED_PARAMETER(force_resize)) +{ + RMLUI_UNUSED(force_resize); + + if (track_length != _track_length) + { + track_length = _track_length; + // GenerateBar(); + } +} + +// Sets the length the bar represents in some arbitrary unit, relative to the track length. +void WidgetScroll::SetBarLength(float _bar_length, bool RMLUI_UNUSED_PARAMETER(force_resize)) +{ + RMLUI_UNUSED(force_resize); + + if (bar_length != _bar_length) + { + bar_length = _bar_length; + // GenerateBar(); + } +} + +// Sets the line height of the parent element; this is used for scrolling speeds. +void WidgetScroll::SetLineHeight(float _line_height) +{ + line_height = _line_height; +} + +// Lays out and resizes the internal elements. +void WidgetScroll::FormatElements(const Vector2f& containing_block, float slider_length) +{ + float relative_bar_length; + + if (track_length <= 0) + relative_bar_length = 1; + else if (bar_length <= 0) + relative_bar_length = 0; + else + relative_bar_length = bar_length / track_length; + + WidgetScroll::FormatElements(containing_block, true, slider_length, relative_bar_length); +} + +// Called when the slider is incremented by one 'line', either by the down / right key or a mouse-click on the +// increment arrow. +float WidgetScroll::OnLineIncrement() +{ + return Scroll(line_height); +} + +// Called when the slider is decremented by one 'line', either by the up / left key or a mouse-click on the decrement +// arrow. +float WidgetScroll::OnLineDecrement() +{ + return Scroll(-line_height); +} + +// Called when the slider is incremented by one 'page', either by the page-up key or a mouse-click on the track +// below / right of the bar. +float WidgetScroll::OnPageIncrement() +{ + return Scroll(bar_length); +} + +// Called when the slider is incremented by one 'page', either by the page-down key or a mouse-click on the track +// above / left of the bar. +float WidgetScroll::OnPageDecrement() +{ + return Scroll(-bar_length); +} + +// Returns the bar position after scrolling for a number of pixels. +float WidgetScroll::Scroll(float distance) +{ + float traversable_track_length = (track_length - bar_length); + if (traversable_track_length <= 0) + return bar_position; + + return (bar_position * traversable_track_length + distance) / traversable_track_length; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/WidgetScroll.h b/thirdparty/RmlUi/Source/Core/WidgetScroll.h new file mode 100644 index 000000000..6e1b9e0ab --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/WidgetScroll.h @@ -0,0 +1,162 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_WIDGETSCROLL_H +#define RMLUI_CORE_WIDGETSCROLL_H + +#include "../../Include/RmlUi/Core/EventListener.h" + +namespace Rml { + +class Element; + +/** + A widget for incorporating scrolling functionality into an element. + + @author Peter Curry + */ + +class WidgetScroll final : public EventListener +{ +public: + enum Orientation + { + UNKNOWN, + VERTICAL, + HORIZONTAL + }; + + WidgetScroll(Element* parent); + virtual ~WidgetScroll(); + + /// Initialises the slider to a given orientation. + bool Initialise(Orientation orientation); + + /// Updates the key repeats for the increment / decrement arrows. + void Update(); + + /// Sets the position of the bar. + /// @param[in] bar_position The new position of the bar (0 representing the start of the track, 1 representing the end). + void SetBarPosition(float bar_position); + /// Returns the current position of the bar. + /// @return The current position of the bar (0 representing the start of the track, 1 representing the end). + float GetBarPosition() const; + + /// Returns the slider's orientation. + /// @return The orientation of the slider. + Orientation GetOrientation() const; + + /// Sets the dimensions to the size of the slider. + /// @param[in] dimensions The dimensions to size. + void GetDimensions(Vector2f& dimensions) const; + + /// Sets the length of the entire track in scrollable units (usually lines or characters). This affects the + /// length of the bar element and the speed of scrolling using the mouse-wheel or arrows. + /// @param[in] track_length The length of the track. + /// @param[in] force_resize True to resize the bar immediately, false to wait until the next format. + void SetTrackLength(float track_length, bool force_resize = true); + /// Sets the length the bar represents in scrollable units (usually lines or characters), relative to the track + /// length. For example, for a scroll bar, this would represent how big each visible 'page' is compared to the + /// whole document (which would be set as the track length). + /// @param[in] bar_length The length of the slider's bar. + /// @param[in] force_resize True to resize the bar immediately, false to wait until the next format. + void SetBarLength(float bar_length, bool force_resize = true); + + /// Sets the line height of the parent element; this is used for scrolling speeds. + /// @param[in] line_height The line height of the parent element. + void SetLineHeight(float line_height); + + /// Lays out and resizes the internal elements. + /// @param[in] containing_block The padded box containing the slider. This is used to resolve relative properties. + /// @param[in] length The total length, in pixels, of the slider widget. + void FormatElements(const Vector2f& containing_block, float slider_length); + +private: + /// Handles events coming through from the slider's components. + void ProcessEvent(Event& event) override; + + /// Lays out and resizes the slider's internal elements. + /// @param[in] containing_block The padded box containing the slider. This is used to resolve relative properties. + /// @param[in] resize_element True to resize the parent slider element, false to only resize its components. + /// @param[in] slider_length The total length, in pixels, of the slider widget. + /// @param[in] bar_length The total length of the bar, as a proportion of the track length. If this is -1, the intrinsic length will be used. + void FormatElements(const Vector2f& containing_block, bool resize_element, float slider_length, float bar_length = -1); + /// Lays out and positions the bar element. + /// @param[in] bar_length The total length of the bar, as a proportion of the track length. If this is -1, the intrinsic length will be used. + void FormatBar(float bar_length = -1); + + // Set the offset on 'bar' from its position. + void PositionBar(); + + /// Called when the slider is incremented by one 'line', either by the down / right key or a mouse-click on the + /// increment arrow. + /// @return The new position of the bar. + float OnLineIncrement(); + /// Called when the slider is decremented by one 'line', either by the up / left key or a mouse-click on the + /// decrement arrow. + /// @return The new position of the bar. + float OnLineDecrement(); + /// Called when the slider is incremented by one 'page', either by the page-up key or a mouse-click on the + /// track below / right of the bar. + /// @return The new position of the bar. + float OnPageIncrement(); + /// Called when the slider is incremented by one 'page', either by the page-down key or a mouse-click on the + /// track above / left of the bar. + /// @return The new position of the bar. + float OnPageDecrement(); + + // Returns the bar position after scrolling for a number of pixels. + float Scroll(float distance); + + Element* parent; + + Orientation orientation; + + // The background track element, across which the bar slides. + Element* track; + // The bar element. This is the element that is dragged across the trough. + Element* bar; + // The two (optional) buttons for incrementing and decrementing the slider. + Element* arrows[2]; + + // A number from 0 to 1, indicating how far along the track the bar is. + float bar_position; + // If the bar is being dragged, this is the pixel offset from the start of the bar to where it was picked up. + int bar_drag_anchor; + + // Set to the auto-repeat timer if either of the arrow buttons have been pressed, -1 if they haven't. + float arrow_timers[2]; + double last_update_time; + + float track_length; + float bar_length; + float line_height; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandler.cpp b/thirdparty/RmlUi/Source/Core/XMLNodeHandler.cpp new file mode 100644 index 000000000..3b91d86ab --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandler.cpp @@ -0,0 +1,37 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +XMLNodeHandler::~XMLNodeHandler() +{ +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerBody.cpp b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerBody.cpp new file mode 100644 index 000000000..c480b5edc --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerBody.cpp @@ -0,0 +1,83 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerBody.h" +#include "XMLParseTools.h" +#include "../../Include/RmlUi/Core/XMLParser.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/Factory.h" + +namespace Rml { + +XMLNodeHandlerBody::XMLNodeHandlerBody() +{ +} + +XMLNodeHandlerBody::~XMLNodeHandlerBody() +{ +} + +Element* XMLNodeHandlerBody::ElementStart(XMLParser* parser, const String& RMLUI_UNUSED_PARAMETER(name), const XMLAttributes& attributes) +{ + RMLUI_UNUSED(name); + + Element* element = parser->GetParseFrame()->element; + + // Check for and apply any template + String template_name = Get(attributes, "template", ""); + if (!template_name.empty()) + { + element = XMLParseTools::ParseTemplate(element, template_name); + } + + // Apply any attributes to the document + ElementDocument* document = parser->GetParseFrame()->element->GetOwnerDocument(); + if (document) + document->SetAttributes(attributes); + + // Tell the parser to use the element handler for all children + parser->PushDefaultHandler(); + + return element; +} + +bool XMLNodeHandlerBody::ElementEnd(XMLParser* RMLUI_UNUSED_PARAMETER(parser), const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(parser); + RMLUI_UNUSED(name); + + return true; +} + +bool XMLNodeHandlerBody::ElementData(XMLParser* parser, const String& data, XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(type); + return Factory::InstanceElementText(parser->GetParseFrame()->element, data); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerBody.h b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerBody.h new file mode 100644 index 000000000..dc3f3c83e --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerBody.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLNODEHANDLERBODY_H +#define RMLUI_CORE_XMLNODEHANDLERBODY_H + +#include "../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + Element Node handler that processes the HEAD tag + + @author Lloyd Weehuizen + */ + +class XMLNodeHandlerBody : public XMLNodeHandler +{ +public: + XMLNodeHandlerBody(); + ~XMLNodeHandlerBody(); + + /// Called when a new element start is opened + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerDefault.cpp b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerDefault.cpp new file mode 100644 index 000000000..41f50c201 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerDefault.cpp @@ -0,0 +1,98 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerDefault.h" +#include "XMLParseTools.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/XMLParser.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" + + +namespace Rml { + +XMLNodeHandlerDefault::XMLNodeHandlerDefault() +{ +} + +XMLNodeHandlerDefault::~XMLNodeHandlerDefault() +{ +} + +Element* XMLNodeHandlerDefault::ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) +{ + RMLUI_ZoneScopedC(0x556B2F); + + // Determine the parent + Element* parent = parser->GetParseFrame()->element; + + // Attempt to instance the element with the instancer + ElementPtr element = Factory::InstanceElement(parent, name, name, attributes); + if (!element) + { + Log::Message(Log::LT_ERROR, "Failed to create element for tag %s, instancer returned nullptr.", name.c_str()); + return nullptr; + } + + // Move and append the element to the parent + Element* result = parent->AppendChild(std::move(element)); + + return result; +} + +bool XMLNodeHandlerDefault::ElementEnd(XMLParser* RMLUI_UNUSED_PARAMETER(parser), const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(parser); + RMLUI_UNUSED(name); + + return true; +} + +bool XMLNodeHandlerDefault::ElementData(XMLParser* parser, const String& data, XMLDataType type) +{ + RMLUI_ZoneScopedC(0x006400); + + // Determine the parent + Element* parent = parser->GetParseFrame()->element; + RMLUI_ASSERT(parent); + + if (type == XMLDataType::InnerXML) + { + // Structural data views use the raw inner xml contents of the node, submit them now. + if (ElementUtilities::ApplyStructuralDataViews(parent, data)) + return true; + } + + // Parse the text into the element + return Factory::InstanceElementText(parent, data); +} + + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerDefault.h b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerDefault.h new file mode 100644 index 000000000..200d80c3d --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerDefault.h @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLNODEHANDLERDEFAULT_H +#define RMLUI_CORE_XMLNODEHANDLERDEFAULT_H + +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + Element Node handler that creates elements + + @author Lloyd Weehuizen + */ + +class XMLNodeHandlerDefault : public XMLNodeHandler +{ +public: + XMLNodeHandlerDefault(); + ~XMLNodeHandlerDefault(); + + /// Called when a new element start is opened + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerHead.cpp b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerHead.cpp new file mode 100644 index 000000000..c501f7ae4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerHead.cpp @@ -0,0 +1,149 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerHead.h" +#include "DocumentHeader.h" +#include "TemplateCache.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/Element.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" +#include "../../Include/RmlUi/Core/XMLParser.h" +#include "../../Include/RmlUi/Core/URL.h" + +namespace Rml { + +XMLNodeHandlerHead::XMLNodeHandlerHead() +{ +} + +XMLNodeHandlerHead::~XMLNodeHandlerHead() +{ +} + +Element* XMLNodeHandlerHead::ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) +{ + if (name == "head") + { + // Process the head attribute + parser->GetDocumentHeader()->source = parser->GetSourceURL().GetURL(); + } + + // Is it a link tag? + else if (name == "link") + { + // Lookup the type and href + String type = StringUtilities::ToLower(Get(attributes, "type", "")); + String href = Get(attributes, "href", ""); + + if (!type.empty() && !href.empty()) + { + // If its RCSS (... or CSS!), add to the RCSS fields. + if (type == "text/rcss" || + type == "text/css") + { + parser->GetDocumentHeader()->rcss_external.push_back(href); + } + + // If its an template, add to the template fields + else if (type == "text/template") + { + parser->GetDocumentHeader()->template_resources.push_back(href); + } + + else + { + Log::ParseError(parser->GetSourceURL().GetURL(), parser->GetLineNumber(), "Invalid link type '%s'", type.c_str()); + } + } + else + { + Log::ParseError(parser->GetSourceURL().GetURL(), parser->GetLineNumber(), "Link tag requires type and href attributes"); + } + } + + // Process script tags + else if (name == "script") + { + // Check if its an external string + String src = Get(attributes, "src", ""); + if (src.size() > 0) + { + parser->GetDocumentHeader()->scripts_external.push_back(src); + } + } + + // No elements constructed + return nullptr; +} + +bool XMLNodeHandlerHead::ElementEnd(XMLParser* parser, const String& name) +{ + // When the head tag closes, inject the header into the active document + if (name == "head") + { + Element* element = parser->GetParseFrame()->element; + if (!element) + return true; + + ElementDocument* document = element->GetOwnerDocument(); + if (document) + document->ProcessHeader(parser->GetDocumentHeader()); + } + return true; +} + +bool XMLNodeHandlerHead::ElementData(XMLParser* parser, const String& data, XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(type); + const String& tag = parser->GetParseFrame()->tag; + + // Store the title + if (tag == "title") + { + SystemInterface* system_interface = GetSystemInterface(); + if (system_interface != nullptr) + system_interface->TranslateString(parser->GetDocumentHeader()->title, data); + } + + // Store an inline script + if (tag == "script" && data.size() > 0) + parser->GetDocumentHeader()->scripts_inline.push_back(data); + + // Store an inline style + if (tag == "style" && data.size() > 0) + { + parser->GetDocumentHeader()->rcss_inline.push_back(data); + parser->GetDocumentHeader()->rcss_inline_line_numbers.push_back(parser->GetLineNumberOpenTag()); + } + + return true; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerHead.h b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerHead.h new file mode 100644 index 000000000..efd368fef --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerHead.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLNODEHANDLERHEAD_H +#define RMLUI_CORE_XMLNODEHANDLERHEAD_H + +#include "../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + Element Node handler that processes the HEAD tag + + @author Lloyd Weehuizen + */ + +class XMLNodeHandlerHead : public XMLNodeHandler +{ +public: + XMLNodeHandlerHead(); + ~XMLNodeHandlerHead(); + + /// Called when a new element start is opened + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerTemplate.cpp b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerTemplate.cpp new file mode 100644 index 000000000..706dcff89 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerTemplate.cpp @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLNodeHandlerTemplate.h" +#include "Template.h" +#include "TemplateCache.h" +#include "XMLParseTools.h" +#include "../../Include/RmlUi/Core/Dictionary.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/XMLParser.h" + +namespace Rml { + +XMLNodeHandlerTemplate::XMLNodeHandlerTemplate() +{ +} + +XMLNodeHandlerTemplate::~XMLNodeHandlerTemplate() +{ +} + +Element* XMLNodeHandlerTemplate::ElementStart(XMLParser* parser, const String& RMLUI_UNUSED_ASSERT_PARAMETER(name), const XMLAttributes& attributes) +{ + RMLUI_UNUSED_ASSERT(name); + RMLUI_ASSERT(name == "template"); + + String template_name = Get(attributes, "src", ""); + + // Tell the parser to use the element handler for all child nodes + parser->PushDefaultHandler(); + + return XMLParseTools::ParseTemplate(parser->GetParseFrame()->element, template_name); +} + +bool XMLNodeHandlerTemplate::ElementEnd(XMLParser* RMLUI_UNUSED_PARAMETER(parser), const String& RMLUI_UNUSED_PARAMETER(name)) +{ + RMLUI_UNUSED(parser); + RMLUI_UNUSED(name); + + return true; +} + +bool XMLNodeHandlerTemplate::ElementData(XMLParser* parser, const String& data, XMLDataType RMLUI_UNUSED_PARAMETER(type)) +{ + RMLUI_UNUSED(type); + return Factory::InstanceElementText(parser->GetParseFrame()->element, data); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/XMLNodeHandlerTemplate.h b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerTemplate.h new file mode 100644 index 000000000..d41f04970 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLNodeHandlerTemplate.h @@ -0,0 +1,57 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLNODEHANDLERTEMPLATE_H +#define RMLUI_CORE_XMLNODEHANDLERTEMPLATE_H + +#include "../../Include/RmlUi/Core/XMLNodeHandler.h" + +namespace Rml { + +/** + Element Node handler that processes the custom template tags + + @author Lloyd Weehuizen + */ + +class XMLNodeHandlerTemplate : public XMLNodeHandler +{ +public: + XMLNodeHandlerTemplate(); + ~XMLNodeHandlerTemplate(); + + /// Called when a new element start is opened + Element* ElementStart(XMLParser* parser, const String& name, const XMLAttributes& attributes) override; + /// Called when an element is closed + bool ElementEnd(XMLParser* parser, const String& name) override; + /// Called for element data + bool ElementData(XMLParser* parser, const String& data, XMLDataType type) override; +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/XMLParseTools.cpp b/thirdparty/RmlUi/Source/Core/XMLParseTools.cpp new file mode 100644 index 000000000..d47189854 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLParseTools.cpp @@ -0,0 +1,190 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "XMLParseTools.h" +#include "../../Include/RmlUi/Core/StreamMemory.h" +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/StringUtilities.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "TemplateCache.h" +#include "Template.h" +#include +#include + +namespace Rml { + +// Searchs a string for the specified tag +// NOTE: tag *MUST* be in lowercase +const char* XMLParseTools::FindTag(const char* tag, const char* string, bool closing_tag) +{ + const size_t length = strlen(tag); + const char* ptr = string; + bool found_closing = false; + + while (*ptr) + { + // Check if the first character matches + if (tolower((*ptr)) == tag[0]) + { + // If it does, check the whole word + if (StringUtilities::StringCompareCaseInsensitive(StringView(ptr, ptr + length), StringView(tag, tag + length))) + { + // Check for opening <, loop back in the string skipping white space and forward slashes if + // we're looking for the closing tag + const char* tag_start = ptr - 1; + while (tag_start > string && (StringUtilities::IsWhitespace(*tag_start) || *tag_start == '/')) + { + if (*tag_start == '/') + found_closing = true; + tag_start--; + } + + // If the character we're looking at is a <, and found closing matches closing tag, + // its the tag we're looking for + if (*tag_start == '<' && found_closing == closing_tag) + return tag_start; + + // Otherwise, keep looking + } + } + ptr++; + } + + return nullptr; +} + +bool XMLParseTools::ReadAttribute(const char* &string, String& name, String& value) +{ + const char* ptr = string; + + name = ""; + value = ""; + + // Skip whitespace + while (StringUtilities::IsWhitespace(*ptr)) + ptr++; + + // Look for the end of the attribute name + bool found_whitespace = false; + while (*ptr != '=' && *ptr != '>' && (!found_whitespace || StringUtilities::IsWhitespace(*ptr))) + { + if (StringUtilities::IsWhitespace(*ptr)) + found_whitespace = true; + else + name += *ptr; + ptr++; + } + if (*ptr == '>') + return false; + + // If we stopped on an equals, parse the value + if (*ptr == '=') + { + + // Skip over white space, ='s and quotes + bool quoted = false; + while (StringUtilities::IsWhitespace(*ptr) || *ptr == '\'' || *ptr == '"' || *ptr == '=') + { + if (*ptr == '\'' || *ptr == '"') + quoted = true; + ptr++; + } + if (*ptr == '>') + return false; + + // Store the value + while (*ptr != '\'' && *ptr != '"' && *ptr != '>' && (*ptr != ' ' || quoted)) + { + value += *ptr++; + } + if (*ptr == '>') + return false; + + // Advance passed the quote + if (quoted) + ptr++; + } + else + { + ptr--; + } + + // Update the string pointer + string = ptr; + + return true; +} + +Element* XMLParseTools::ParseTemplate(Element* element, const String& template_name) +{ + // Load the template, and parse it + Template* parse_template = TemplateCache::GetTemplate(template_name); + if (!parse_template) + { + Log::ParseError(element->GetOwnerDocument()->GetSourceURL(), -1, "Failed to find template '%s'.", template_name.c_str()); + return element; + } + + return parse_template->ParseTemplate(element); +} + +const char* XMLParseTools::ParseDataBrackets(bool& inside_brackets, char c, char previous) +{ + if (inside_brackets) + { + if (c == '}' && previous == '}') + inside_brackets = false; + + else if (c == '{' && previous == '{') + return "Nested double curly brackets are illegal."; + + else if (previous == '}' && c != '}') + return "Single closing curly bracket encountered, use double curly brackets to close an expression."; + + else if (previous == '/' && c == '>') + return "Closing double curly brackets not found, XML end node encountered first."; + + else if (previous == '<' && c == '/') + return "Closing double curly brackets not found, XML end node encountered first."; + } + else + { + if (c == '{' && previous == '{') + { + inside_brackets = true; + } + else if (c == '}' && previous == '}') + { + return "Closing double curly brackets encountered outside an expression."; + } + } + + return nullptr; +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/XMLParseTools.h b/thirdparty/RmlUi/Source/Core/XMLParseTools.h new file mode 100644 index 000000000..1887658ec --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLParseTools.h @@ -0,0 +1,72 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_XMLPARSETOOLS_H +#define RMLUI_CORE_XMLPARSETOOLS_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class Element; + +/** + Tools for aiding in parsing XML documents. + + @author Lloyd Weehuizen + */ + +class XMLParseTools +{ +public: + /// Searchs a string for the specified tag + /// @param tag Tag to find, *must* be in lower case + /// @param string String to search + /// @param closing_tag Is it the closing tag we're looking for? + static const char* FindTag(const char* tag, const char* string, bool closing_tag = false); + /// Reads the next attribute from the string, advancing the pointer + /// @param[in,out] string String to read the attribute from, pointer will be advanced passed the read + /// @param[out] name Name of the attribute read + /// @param[out] value Value of the attribute read + static bool ReadAttribute(const char* &string, String& name, String& value); + + /// Applies the named template to the specified element + /// @param element Element to apply the template to + /// @param template_name Name of the template to apply, in TEMPLATE:ELEMENT_ID form + /// @returns Element to continue the parse from + static Element* ParseTemplate(Element* element, const String& template_name); + + /// Determine the presence of data expression brackets inside XML data. + /// Call this for each iteration through the data string. + /// 'inside_brackets' should be initialized to false. + /// Returns nullptr on success, or an error string on failure. + static const char* ParseDataBrackets(bool& inside_brackets, char c, char previous); +}; + +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Core/XMLParser.cpp b/thirdparty/RmlUi/Source/Core/XMLParser.cpp new file mode 100644 index 000000000..4c96f87ac --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/XMLParser.cpp @@ -0,0 +1,187 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DocumentHeader.h" +#include "../../Include/RmlUi/Core/Log.h" +#include "../../Include/RmlUi/Core/Profiling.h" +#include "../../Include/RmlUi/Core/Stream.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "../../Include/RmlUi/Core/XMLNodeHandler.h" +#include "../../Include/RmlUi/Core/URL.h" +#include "../../Include/RmlUi/Core/XMLParser.h" +#include "../../Include/RmlUi/Core/Factory.h" + +namespace Rml { + +using NodeHandlers = UnorderedMap< String, SharedPtr >; +static NodeHandlers node_handlers; +static SharedPtr default_node_handler; + +XMLParser::XMLParser(Element* root) +{ + RegisterCDATATag("script"); + + for (const String& name : Factory::GetStructuralDataViewAttributeNames()) + RegisterInnerXMLAttribute(name); + + // Add the first frame. + ParseFrame frame; + frame.element = root; + stack.push(frame); + + active_handler = nullptr; + + header = MakeUnique(); +} + +XMLParser::~XMLParser() +{} + +// Registers a custom node handler to be used to a given tag. +XMLNodeHandler* XMLParser::RegisterNodeHandler(const String& _tag, SharedPtr handler) +{ + String tag = StringUtilities::ToLower(_tag); + + // Check for a default node registration. + if (tag.empty()) + { + default_node_handler = std::move(handler); + return default_node_handler.get(); + } + + XMLNodeHandler* result = handler.get(); + node_handlers[tag] = std::move(handler); + return result; +} + +// Releases all registered node handlers. This is called internally. +void XMLParser::ReleaseHandlers() +{ + default_node_handler.reset(); + node_handlers.clear(); +} + +DocumentHeader* XMLParser::GetDocumentHeader() +{ + return header.get(); +} + +// Pushes the default element handler onto the parse stack. +void XMLParser::PushDefaultHandler() +{ + active_handler = default_node_handler.get(); +} + +bool XMLParser::PushHandler(const String& tag) +{ + NodeHandlers::iterator i = node_handlers.find(StringUtilities::ToLower(tag)); + if (i == node_handlers.end()) + return false; + + active_handler = i->second.get(); + return true; +} + +/// Access the current parse frame +const XMLParser::ParseFrame* XMLParser::GetParseFrame() const +{ + return &stack.top(); +} + +const URL& XMLParser::GetSourceURL() const +{ + RMLUI_ASSERT(GetSourceURLPtr()); + return *GetSourceURLPtr(); +} + +/// Called when the parser finds the beginning of an element tag. +void XMLParser::HandleElementStart(const String& _name, const XMLAttributes& attributes) +{ + RMLUI_ZoneScoped; + const String name = StringUtilities::ToLower(_name); + + // Check for a specific handler that will override the child handler. + NodeHandlers::iterator itr = node_handlers.find(name); + if (itr != node_handlers.end()) + active_handler = itr->second.get(); + + // Store the current active handler, so we can use it through this function (as active handler may change) + XMLNodeHandler* node_handler = active_handler; + + Element* element = nullptr; + + // Get the handler to handle the open tag + if (node_handler) + { + element = node_handler->ElementStart(this, name, attributes); + } + + // Push onto the stack + ParseFrame frame; + frame.node_handler = node_handler; + frame.child_handler = active_handler; + frame.element = (element ? element : stack.top().element); + frame.tag = name; + stack.push(frame); +} + +/// Called when the parser finds the end of an element tag. +void XMLParser::HandleElementEnd(const String& _name) +{ + RMLUI_ZoneScoped; + String name = StringUtilities::ToLower(_name); + + // Copy the top of the stack + ParseFrame frame = stack.top(); + // Pop the frame + stack.pop(); + // Restore active handler to the previous frame's child handler + active_handler = stack.top().child_handler; + + // Check frame names + if (name != frame.tag) + { + Log::Message(Log::LT_ERROR, "Closing tag '%s' mismatched on %s:%d was expecting '%s'.", name.c_str(), GetSourceURL().GetURL().c_str(), GetLineNumber(), frame.tag.c_str()); + } + + // Call element end handler + if (frame.node_handler) + { + frame.node_handler->ElementEnd(this, name); + } +} + +/// Called when the parser encounters data. +void XMLParser::HandleData(const String& data, XMLDataType type) +{ + RMLUI_ZoneScoped; + if (stack.top().node_handler) + stack.top().node_handler->ElementData(this, data, type); +} + +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Core/precompiled.h b/thirdparty/RmlUi/Source/Core/precompiled.h new file mode 100644 index 000000000..4a9c96ab4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Core/precompiled.h @@ -0,0 +1,34 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_CORE_PRECOMPILED_H +#define RMLUI_CORE_PRECOMPILED_H + +#include "../../Include/RmlUi/Core.h" + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/BeaconSource.h b/thirdparty/RmlUi/Source/Debugger/BeaconSource.h new file mode 100644 index 000000000..bd7dabfe1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/BeaconSource.h @@ -0,0 +1,55 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +static const char* beacon_rcss = R"RCSS( +body +{ + position: absolute; + top: 5px; + right: 33dp; + z-index: 1000000; + width: 20px; + font-family: rmlui-debugger-font; + font-size: 12dp; + color: black; + visibility: hidden; +} +button +{ + display: block; + width: 18dp; + height: 18dp; + text-align: center; + border-width: 1px; + font-weight: bold; +} +)RCSS"; + +static const char* beacon_rml = R"RML( + +)RML"; diff --git a/thirdparty/RmlUi/Source/Debugger/CommonSource.h b/thirdparty/RmlUi/Source/Debugger/CommonSource.h new file mode 100644 index 000000000..e96fd5bdd --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/CommonSource.h @@ -0,0 +1,195 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +static const char* common_rcss = R"RCSS( +body +{ + font-family: rmlui-debugger-font; + z-index: 1000000; + font-size: 13dp; + line-height: 1.4; + color: black; + padding-top: 30dp; +} +div, h1, h2, h3, h4, p +{ + display: block; +} +em +{ + font-style: italic; +} +h1 +{ + position: absolute; + top: 0px; + height: 22dp; + padding: 4dp 5dp; + color: white; + background-color: #888; + font-size: 15dp; +} +h2 +{ + background-color: #ddd; + border-width: 1px 0px; + border-color: #888; +} +h3 +{ + margin-top: 0.6em; + color: red; +} +h4 +{ + color: #cc0000; +} +handle#position_handle +{ + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} +h1 .button +{ + z-index: 1; +} +div#close_button +{ + margin-left: 10dp; + z-index: 1; + float: right; + width: 18dp; + color: black; + background-color: #ddd; + border-width: 1px; + border-color: #666; + text-align: center; +} +div#close_button:hover +{ + background-color: #eee; +} +div#close_button:active +{ + background-color: #fff; +} +div#content +{ + position: relative; + width: auto; + height: 100%; + overflow: auto; + background: white; + border-width: 2dp; + border-color: #888; + border-top-width: 0px; +} +.error +{ + background: #d24040; + color: white; + border-color: #b74e4e; +} +.warning +{ + background: #e8d34e; + color: black; + border-color: #ca9466; +} +.info +{ + background: #2a9cdb; + color: white; + border-color: #3b70bb; +} +.debug +{ + background: #3fab2a; + color: white; + border-color: #226c13; +} +scrollbarvertical +{ + width: 16dp; + scrollbar-margin: 16px; +} +scrollbarhorizontal +{ + height: 16dp; + scrollbar-margin: 16px; +} +scrollbarvertical slidertrack, +scrollbarhorizontal slidertrack +{ + background: #aaa; + border-color: #888; +} +scrollbarvertical slidertrack +{ + border-left-width: 1px; +} +scrollbarhorizontal slidertrack +{ + height: 15dp; + border-top-width: 1px; +} +scrollbarvertical sliderbar, +scrollbarhorizontal sliderbar +{ + background: #ddd; + border-color: #888; +} +scrollbarvertical sliderbar +{ + border-width: 1px 0px; + margin-left: 1dp; +} +scrollbarhorizontal sliderbar +{ + height: 15dp; + border-width: 0px 1px; + margin-top: 1dp; +} +scrollbarcorner +{ + background: #888; +} +handle#size_handle +{ + position: absolute; + width: 16dp; + height: 16dp; + bottom: -2dp; + right: 2dp; + background-color: #888; +} +)RCSS"; diff --git a/thirdparty/RmlUi/Source/Debugger/Debugger.cpp b/thirdparty/RmlUi/Source/Debugger/Debugger.cpp new file mode 100644 index 000000000..ed5d4274f --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/Debugger.cpp @@ -0,0 +1,91 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../../Include/RmlUi/Debugger/Debugger.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "DebuggerPlugin.h" + +namespace Rml { +namespace Debugger { + +// Initialises the debug plugin. The debugger will be loaded into the given context. +bool Initialise(Context* context) +{ + if (DebuggerPlugin::GetInstance() != nullptr) + { + Log::Message(Log::LT_WARNING, "Unable to initialise debugger plugin, already initialised!"); + return false; + } + + DebuggerPlugin* plugin = new DebuggerPlugin(); + if (!plugin->Initialise(context)) + { + Log::Message(Log::LT_WARNING, "Unable to initialise debugger plugin."); + + delete plugin; + return false; + } + + SetContext(context); + RegisterPlugin(plugin); + + return true; +} + +// Sets the context to be debugged. +bool SetContext(Context* context) +{ + DebuggerPlugin* plugin = DebuggerPlugin::GetInstance(); + if (plugin == nullptr) + return false; + + plugin->SetContext(context); + + return true; +} + +// Sets the visibility of the debugger. +void SetVisible(bool visibility) +{ + DebuggerPlugin* plugin = DebuggerPlugin::GetInstance(); + if (plugin != nullptr) + plugin->SetVisible(visibility); +} + +// Returns the visibility of the debugger. +bool IsVisible() +{ + DebuggerPlugin* plugin = DebuggerPlugin::GetInstance(); + if (plugin == nullptr) + return false; + + return plugin->IsVisible(); +} + +} +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Debugger/DebuggerPlugin.cpp b/thirdparty/RmlUi/Source/Debugger/DebuggerPlugin.cpp new file mode 100644 index 000000000..55cef07bc --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/DebuggerPlugin.cpp @@ -0,0 +1,410 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DebuggerPlugin.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementInstancer.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Types.h" +#include "ElementContextHook.h" +#include "ElementInfo.h" +#include "ElementLog.h" +#include "FontSource.h" +#include "Geometry.h" +#include "MenuSource.h" +#include "DebuggerSystemInterface.h" +#include + +namespace Rml { +namespace Debugger { + +DebuggerPlugin* DebuggerPlugin::instance = nullptr; + +DebuggerPlugin::DebuggerPlugin() +{ + RMLUI_ASSERT(instance == nullptr); + instance = this; + host_context = nullptr; + debug_context = nullptr; + log_interface = nullptr; + + menu_element = nullptr; + info_element = nullptr; + log_element = nullptr; + hook_element = nullptr; + + render_outlines = false; + + application_interface = nullptr; +} + +DebuggerPlugin::~DebuggerPlugin() +{ + instance = nullptr; +} + +// Initialises the debugging tools into the given context. +bool DebuggerPlugin::Initialise(Context* context) +{ + host_context = context; + Geometry::SetContext(context); + + if (!LoadFont()) + { + Log::Message(Log::LT_ERROR, "Failed to initialise debugger, unable to load font."); + return false; + } + + if (!LoadMenuElement() || + !LoadInfoElement() || + !LoadLogElement()) + { + Log::Message(Log::LT_ERROR, "Failed to initialise debugger, error while load debugger elements."); + return false; + } + + hook_element_instancer = MakeUnique< ElementInstancerGeneric >(); + Factory::RegisterElementInstancer("debug-hook", hook_element_instancer.get()); + + return true; +} + +// Sets the context to be debugged. +bool DebuggerPlugin::SetContext(Context* context) +{ + // Remove the debug hook from the old context. + if (debug_context && hook_element) + { + debug_context->UnloadDocument(hook_element); + hook_element = nullptr; + } + + // Add the debug hook into the new context. + if (context) + { + ElementDocument* element = context->CreateDocument("debug-hook"); + if (!element) + return false; + + RMLUI_ASSERT(!hook_element); + hook_element = rmlui_dynamic_cast< ElementContextHook* >(element); + if (!hook_element) + { + context->UnloadDocument(element); + return false; + } + + hook_element->Initialise(this); + } + + // Attach the info element to the new context. + if (info_element) + { + if (debug_context) + { + debug_context->RemoveEventListener("click", info_element, true); + debug_context->RemoveEventListener("mouseover", info_element, true); + } + + if (context) + { + context->AddEventListener("click", info_element, true); + context->AddEventListener("mouseover", info_element, true); + } + + info_element->Reset(); + } + + debug_context = context; + return true; +} + +// Sets the visibility of the debugger. +void DebuggerPlugin::SetVisible(bool visibility) +{ + if (visibility) + menu_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + else + menu_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); +} + +// Returns the visibility of the debugger. +bool DebuggerPlugin::IsVisible() +{ + return menu_element->IsVisible(); +} + +// Renders any debug elements in the debug context. +void DebuggerPlugin::Render() +{ + // Render the outlines of the debug context's elements. + if (render_outlines && debug_context) + { + for (int i = 0; i < debug_context->GetNumDocuments(); ++i) + { + ElementDocument* document = debug_context->GetDocument(i); + if (document->GetId().find("rmlui-debug-") == 0) + continue; + + Stack< Element* > element_stack; + element_stack.push(document); + + while (!element_stack.empty()) + { + Element* element = element_stack.top(); + element_stack.pop(); + if (element->IsVisible()) + { + ElementUtilities::ApplyTransform(*element); + for (int j = 0; j < element->GetNumBoxes(); ++j) + { + const Box& box = element->GetBox(j); + Geometry::RenderOutline( + element->GetAbsoluteOffset(Box::BORDER) + box.GetPosition(Box::BORDER), + box.GetSize(Box::BORDER), + Colourb(255, 0, 0, 128), + 1 + ); + } + + for (int j = 0; j < element->GetNumChildren(); ++j) + element_stack.push(element->GetChild(j)); + } + } + } + } + + // Render the info element's boxes. + if (info_element && info_element->IsVisible()) + { + info_element->RenderHoverElement(); + info_element->RenderSourceElement(); + } +} + +// Called when RmlUi shuts down. +void DebuggerPlugin::OnShutdown() +{ + // Release the elements before we leak track, this ensures the debugger hook has been cleared + // and that we don't try send the messages to the debug log window + ReleaseElements(); + + hook_element_instancer.reset(); + + delete this; +} + +// Called whenever a RmlUi context is destroyed. +void DebuggerPlugin::OnContextDestroy(Context* context) +{ + if (context == debug_context) + { + // The context we're debugging is being destroyed, so we need to remove our debug hook elements. + SetContext(nullptr); + } + + if (context == host_context) + { + // Our host is being destroyed, so we need to shut down the debugger. + + ReleaseElements(); + + Geometry::SetContext(nullptr); + host_context = nullptr; + } +} + +// Called whenever an element is destroyed. +void DebuggerPlugin::OnElementDestroy(Element* element) +{ + if (info_element) + info_element->OnElementDestroy(element); +} + +// Event handler for events from the debugger elements. +void DebuggerPlugin::ProcessEvent(Event& event) +{ + if (event == EventId::Click) + { + if (event.GetTargetElement()->GetId() == "event-log-button") + { + if (log_element->IsVisible()) + log_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + else + log_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + } + else if (event.GetTargetElement()->GetId() == "debug-info-button") + { + if (info_element->IsVisible()) + info_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + else + info_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + } + else if (event.GetTargetElement()->GetId() == "outlines-button") + { + render_outlines = !render_outlines; + } + } +} + +DebuggerPlugin* DebuggerPlugin::GetInstance() +{ + return instance; +} + +bool DebuggerPlugin::LoadFont() +{ + const String font_family_name = "rmlui-debugger-font"; + + return (LoadFontFace(courier_prime_code, sizeof(courier_prime_code)/sizeof(courier_prime_code[0]), font_family_name, Style::FontStyle::Normal, Style::FontWeight::Normal) && + LoadFontFace(courier_prime_code_italic, sizeof(courier_prime_code_italic)/sizeof(courier_prime_code_italic[0]), font_family_name, Style::FontStyle::Italic, Style::FontWeight::Normal)); +} + +bool DebuggerPlugin::LoadMenuElement() +{ + menu_element = host_context->CreateDocument(); + if (!menu_element) + return false; + + menu_element->SetId("rmlui-debug-menu"); + menu_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + menu_element->SetInnerRML(menu_rml); + + SharedPtr style_sheet = Factory::InstanceStyleSheetString(menu_rcss); + if (!style_sheet) + { + host_context->UnloadDocument(menu_element); + menu_element = nullptr; + return false; + } + + menu_element->SetStyleSheet(std::move(style_sheet)); + + // Set the version info in the menu. + menu_element->GetElementById("version-number")->SetInnerRML("v" + Rml::GetVersion()); + + // Attach to the buttons. + Element* event_log_button = menu_element->GetElementById("event-log-button"); + event_log_button->AddEventListener(EventId::Click, this); + + Element* element_info_button = menu_element->GetElementById("debug-info-button"); + element_info_button->AddEventListener(EventId::Click, this); + + Element* outlines_button = menu_element->GetElementById("outlines-button"); + outlines_button->AddEventListener(EventId::Click, this); + + return true; +} + +bool DebuggerPlugin::LoadInfoElement() +{ + info_element_instancer = MakeUnique< ElementInstancerGeneric >(); + Factory::RegisterElementInstancer("debug-info", info_element_instancer.get()); + info_element = rmlui_dynamic_cast< ElementInfo* >(host_context->CreateDocument("debug-info")); + if (!info_element) + return false; + + info_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + + if (!info_element->Initialise()) + { + host_context->UnloadDocument(info_element); + info_element = nullptr; + + return false; + } + + return true; +} + +bool DebuggerPlugin::LoadLogElement() +{ + log_element_instancer = MakeUnique< ElementInstancerGeneric >(); + Factory::RegisterElementInstancer("debug-log", log_element_instancer.get()); + log_element = rmlui_dynamic_cast< ElementLog* >(host_context->CreateDocument("debug-log")); + if (!log_element) + return false; + + log_element->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + + if (!log_element->Initialise()) + { + host_context->UnloadDocument(log_element); + log_element = nullptr; + + return false; + } + + // Make the system interface; this will trap the log messages for us. + application_interface = Rml::GetSystemInterface(); + log_interface = MakeUnique(application_interface, log_element); + Rml::SetSystemInterface(log_interface.get()); + + return true; +} + +void DebuggerPlugin::ReleaseElements() +{ + if (host_context) + { + if (menu_element) + { + host_context->UnloadDocument(menu_element); + menu_element = nullptr; + } + + if (info_element) + { + host_context->UnloadDocument(info_element); + info_element = nullptr; + } + + if (log_element) + { + host_context->UnloadDocument(log_element); + log_element = nullptr; + Rml::SetSystemInterface(application_interface); + application_interface = nullptr; + log_interface.reset(); + } + } + + if (debug_context) + { + if (hook_element) + { + debug_context->UnloadDocument(hook_element); + hook_element = nullptr; + } + } +} + +} +} diff --git a/thirdparty/RmlUi/Source/Debugger/DebuggerPlugin.h b/thirdparty/RmlUi/Source/Debugger/DebuggerPlugin.h new file mode 100644 index 000000000..ffccca9cc --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/DebuggerPlugin.h @@ -0,0 +1,132 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_DEBUGGERPLUGIN_H +#define RMLUI_DEBUGGER_DEBUGGERPLUGIN_H + +#include "../../Include/RmlUi/Core/EventListener.h" +#include "../../Include/RmlUi/Core/Plugin.h" + +namespace Rml { + +class ElementDocument; +class SystemInterface; + +namespace Debugger { + +class ElementLog; +class ElementInfo; +class ElementContextHook; +class DebuggerSystemInterface; + +/** + RmlUi plugin interface for the debugger. + + @author Robert Curry + */ + +class DebuggerPlugin : public Rml::Plugin, public Rml::EventListener +{ +public: + DebuggerPlugin(); + ~DebuggerPlugin(); + + /// Initialises the debugging tools into the given context. + /// @param[in] context The context to load the tools into. + /// @return True on success, false if an error occured. + bool Initialise(Context* context); + + /// Sets the context to be debugged. + /// @param[in] context The context to be debugged. + /// @return True if the debugger is initialised and the context was switched, false otherwise.. + bool SetContext(Context* context); + + /// Sets the visibility of the debugger. + /// @param[in] visibility True to show the debugger, false to hide it. + void SetVisible(bool visibility); + /// Returns the visibility of the debugger. + /// @return True if the debugger is visible, false if not. + bool IsVisible(); + + /// Renders any debug elements in the debug context. + void Render(); + + /// Called when RmlUi shuts down. + void OnShutdown() override; + + /// Called whenever a RmlUi context is destroyed. + /// @param[in] context The destroyed context. + void OnContextDestroy(Context* context) override; + + /// Called whenever an element is destroyed. + /// @param[in] element The destroyed element. + void OnElementDestroy(Element* element) override; + + /// Event handler for events from the debugger elements. + /// @param[in] event The event to process. + void ProcessEvent(Event& event) override; + + /// Access the singleton instance of the debugger + /// @return nullptr or an instance of the plugin + static DebuggerPlugin* GetInstance(); + +private: + bool LoadFont(); + bool LoadMenuElement(); + bool LoadInfoElement(); + bool LoadLogElement(); + + // Release all loaded elements + void ReleaseElements(); + + // The context hosting the debug documents. + Context* host_context; + // The context we're debugging. + Context* debug_context; + + // The debug elements. + ElementDocument* menu_element; + ElementInfo* info_element; + ElementLog* log_element; + ElementContextHook* hook_element; + + Rml::SystemInterface* application_interface; + UniquePtr log_interface; + + UniquePtr hook_element_instancer, info_element_instancer, log_element_instancer; + + bool render_outlines; + + // Singleton instance + static DebuggerPlugin* instance; +}; + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/DebuggerSystemInterface.cpp b/thirdparty/RmlUi/Source/Debugger/DebuggerSystemInterface.cpp new file mode 100644 index 000000000..203c536cd --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/DebuggerSystemInterface.cpp @@ -0,0 +1,95 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DebuggerSystemInterface.h" +#include "ElementLog.h" + +namespace Rml { +namespace Debugger { + +DebuggerSystemInterface::DebuggerSystemInterface(Rml::SystemInterface* _application_interface, ElementLog* _log) +{ + application_interface = _application_interface; + log = _log; +} + +DebuggerSystemInterface::~DebuggerSystemInterface() +{ + application_interface = nullptr; +} + +// Get the number of seconds elapsed since the start of the application. +double DebuggerSystemInterface::GetElapsedTime() +{ + return application_interface->GetElapsedTime(); +} + +// Translate the input string into the translated string. +int DebuggerSystemInterface::TranslateString(String& translated, const String& input) +{ + return application_interface->TranslateString(translated, input); +} + +// Log the specified message. +bool DebuggerSystemInterface::LogMessage(Log::Type type, const String& message) +{ + log->AddLogMessage(type, message); + + return application_interface->LogMessage(type, message); +} + +// Set mouse cursor. +void DebuggerSystemInterface::SetMouseCursor(const String& cursor_name) +{ + application_interface->SetMouseCursor(cursor_name); +} + +void DebuggerSystemInterface::SetClipboardText(const String& text) +{ + application_interface->SetClipboardText(text); +} + +void DebuggerSystemInterface::GetClipboardText(String& text) +{ + application_interface->GetClipboardText(text); +} + +// Activate keyboard (for touchscreen devices) +void DebuggerSystemInterface::ActivateKeyboard() +{ + application_interface->ActivateKeyboard(); +} + +// Deactivate keyboard (for touchscreen devices) +void DebuggerSystemInterface::DeactivateKeyboard() +{ + application_interface->DeactivateKeyboard(); +} + +} +} diff --git a/thirdparty/RmlUi/Source/Debugger/DebuggerSystemInterface.h b/thirdparty/RmlUi/Source/Debugger/DebuggerSystemInterface.h new file mode 100644 index 000000000..970392348 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/DebuggerSystemInterface.h @@ -0,0 +1,95 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_DEBUGGERSYSTEMINTERFACE_H +#define RMLUI_DEBUGGER_DEBUGGERSYSTEMINTERFACE_H + +#include "../../Include/RmlUi/Core/SystemInterface.h" + +namespace Rml { +namespace Debugger { + +class ElementLog; + +/** + The log interface the debugger installs into RmlUi. This is a pass-through interface, so it holds onto the + application's system interface and passes all the calls through. + + @author Peter Curry + */ + +class DebuggerSystemInterface : public Rml::SystemInterface +{ +public: + /// Instances a new debugging log interface. + /// @param[in] log The logging element to send messages to. + DebuggerSystemInterface(Rml::SystemInterface* application_interface, ElementLog* log); + virtual ~DebuggerSystemInterface(); + + /// Get the number of seconds elapsed since the start of the application. + /// @return Elapsed time, in seconds. + double GetElapsedTime() override; + + /// Translate the input string into the translated string. + /// @param[out] translated Translated string ready for display. + /// @param[in] input String as received from XML. + /// @return Number of translations that occured. + int TranslateString(String& translated, const String& input) override; + + /// Log the specified message. + /// @param[in] type Type of log message, ERROR, WARNING, etc. + /// @param[in] message Message to log. + /// @return True to continue execution, false to break into the debugger. + bool LogMessage(Log::Type type, const String& message) override; + + /// Set mouse cursor. + /// @param[in] cursor_name Cursor name to activate. + void SetMouseCursor(const String& cursor_name) override; + + /// Set clipboard text. + /// @param[in] text Text to apply to clipboard. + void SetClipboardText(const String& text) override; + + /// Get clipboard text. + /// @param[out] text Retrieved text from clipboard. + void GetClipboardText(String& text) override; + + /// Activate keyboard (for touchscreen devices) + void ActivateKeyboard() override; + + /// Deactivate keyboard (for touchscreen devices) + void DeactivateKeyboard() override; +private: + Rml::SystemInterface* application_interface; + ElementLog* log; +}; + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/ElementContextHook.cpp b/thirdparty/RmlUi/Source/Debugger/ElementContextHook.cpp new file mode 100644 index 000000000..a42f2eb5b --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/ElementContextHook.cpp @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementContextHook.h" +#include "DebuggerPlugin.h" + +namespace Rml { +namespace Debugger { + +ElementContextHook::ElementContextHook(const String& tag) : ElementDocument(tag) +{ + debugger = nullptr; +} + +ElementContextHook::~ElementContextHook() +{ +} + +void ElementContextHook::Initialise(DebuggerPlugin* _debugger) +{ + SetId("rmlui-debug-hook"); + debugger = _debugger; +} + +void ElementContextHook::OnRender() +{ + // Make sure we're in the front of the render queue for this context (at least next frame). + PullToFront(); + + // Render the debugging elements. + debugger->Render(); +} + +} +} diff --git a/thirdparty/RmlUi/Source/Debugger/ElementContextHook.h b/thirdparty/RmlUi/Source/Debugger/ElementContextHook.h new file mode 100644 index 000000000..1074ae126 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/ElementContextHook.h @@ -0,0 +1,64 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_ELEMENTCONTEXTHOOK_H +#define RMLUI_DEBUGGER_ELEMENTCONTEXTHOOK_H + +#include "../../Include/RmlUi/Core/ElementDocument.h" + +namespace Rml { +namespace Debugger { + +class DebuggerPlugin; + +/** + An element that the debugger uses to render into a foreign context. + + @author Peter Curry + */ + +class ElementContextHook : public ElementDocument +{ +public: + RMLUI_RTTI_DefineWithParent(ElementContextHook, ElementDocument) + + ElementContextHook(const String& tag); + virtual ~ElementContextHook(); + + void Initialise(DebuggerPlugin* debugger); + + void OnRender() override; + +private: + DebuggerPlugin* debugger; +}; + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/ElementInfo.cpp b/thirdparty/RmlUi/Source/Debugger/ElementInfo.cpp new file mode 100644 index 000000000..6a677c294 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/ElementInfo.cpp @@ -0,0 +1,687 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementInfo.h" +#include "../../Include/RmlUi/Core/Core.h" +#include "../../Include/RmlUi/Core/ElementUtilities.h" +#include "../../Include/RmlUi/Core/ElementText.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include "../../Include/RmlUi/Core/Property.h" +#include "../../Include/RmlUi/Core/PropertiesIteratorView.h" +#include "../../Include/RmlUi/Core/StyleSheet.h" +#include "../../Include/RmlUi/Core/StyleSheetSpecification.h" +#include "../../Include/RmlUi/Core/SystemInterface.h" +#include "Geometry.h" +#include "CommonSource.h" +#include "InfoSource.h" +#include + +namespace Rml { +namespace Debugger { + +ElementInfo::ElementInfo(const String& tag) : ElementDocument(tag) +{ + hover_element = nullptr; + source_element = nullptr; + enable_element_select = true; + show_source_element = true; + update_source_element = true; + force_update_once = false; + title_dirty = true; + previous_update_time = 0.0; +} + +ElementInfo::~ElementInfo() +{ +} + +// Initialises the info element. +bool ElementInfo::Initialise() +{ + SetInnerRML(info_rml); + SetId("rmlui-debug-info"); + + AddEventListener(EventId::Click, this); + AddEventListener(EventId::Mouseover, this); + AddEventListener(EventId::Mouseout, this); + + SharedPtr style_sheet = Factory::InstanceStyleSheetString(String(common_rcss) + String(info_rcss)); + if (!style_sheet) + return false; + + SetStyleSheet(std::move(style_sheet)); + + return true; +} + +// Clears the element references. +void ElementInfo::Reset() +{ + hover_element = nullptr; + show_source_element = true; + update_source_element = true; + SetSourceElement(nullptr); +} + +void ElementInfo::OnUpdate() +{ + if (source_element && (update_source_element || force_update_once) && IsVisible()) + { + const double t = GetSystemInterface()->GetElapsedTime(); + const float dt = (float)(t - previous_update_time); + + constexpr float update_interval = 0.3f; + + if (dt > update_interval || (force_update_once)) + { + if (force_update_once && source_element) + { + // Since an update is being forced, it is possibly because we are reacting to an event and made some changes. + // Update the source element's document to reflect any recent changes. + if (auto document = source_element->GetOwnerDocument()) + document->UpdateDocument(); + } + force_update_once = false; + + UpdateSourceElement(); + } + } + + if (title_dirty) + { + UpdateTitle(); + title_dirty = false; + } +} + +// Called when an element is destroyed. +void ElementInfo::OnElementDestroy(Element* element) +{ + if (hover_element == element) + hover_element = nullptr; + + if (source_element == element) + source_element = nullptr; +} + +void ElementInfo::RenderHoverElement() +{ + if (hover_element) + { + ElementUtilities::ApplyTransform(*hover_element); + for (int i = 0; i < hover_element->GetNumBoxes(); i++) + { + // Render the content area. + const Box element_box = hover_element->GetBox(i); + Vector2f size = element_box.GetSize(Box::BORDER); + size = Vector2f(std::max(size.x, 2.0f), std::max(size.y, 2.0f)); + Geometry::RenderOutline( + hover_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::BORDER), + size, + Colourb(255, 0, 0, 255), + 1 + ); + } + } +} + +void ElementInfo::RenderSourceElement() +{ + if (source_element && show_source_element) + { + ElementUtilities::ApplyTransform(*source_element); + + for (int i = 0; i < source_element->GetNumBoxes(); i++) + { + const Box element_box = source_element->GetBox(i); + + // Content area: + Geometry::RenderBox(source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::CONTENT), element_box.GetSize(), Colourb(158, 214, 237, 128)); + + // Padding area: + Geometry::RenderBox(source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::PADDING), element_box.GetSize(Box::PADDING), source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::CONTENT), element_box.GetSize(), Colourb(135, 122, 214, 128)); + + // Border area: + Geometry::RenderBox(source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::BORDER), element_box.GetSize(Box::BORDER), source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::PADDING), element_box.GetSize(Box::PADDING), Colourb(133, 133, 133, 128)); + + // Border area: + Geometry::RenderBox(source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::MARGIN), element_box.GetSize(Box::MARGIN), source_element->GetAbsoluteOffset(Box::BORDER) + element_box.GetPosition(Box::BORDER), element_box.GetSize(Box::BORDER), Colourb(240, 255, 131, 128)); + } + } +} + +void ElementInfo::ProcessEvent(Event& event) +{ + // Only process events if we're visible + if (IsVisible()) + { + if (event == EventId::Click) + { + Element* target_element = event.GetTargetElement(); + + // Deal with clicks on our own elements differently. + if (target_element->GetOwnerDocument() == this) + { + const String& id = event.GetTargetElement()->GetId(); + + if (id == "close_button") + { + if (IsVisible()) + SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + } + else if (id == "update_source") + { + update_source_element = !update_source_element; + target_element->SetClass("active", update_source_element); + } + else if (id == "show_source") + { + show_source_element = !target_element->IsClassSet("active");; + target_element->SetClass("active", show_source_element); + } + else if (id == "enable_element_select") + { + enable_element_select = !target_element->IsClassSet("active");; + target_element->SetClass("active", enable_element_select); + } + else if (target_element->GetTagName() == "pseudo" && source_element) + { + const String name = target_element->GetAttribute("name", ""); + + if (!name.empty()) + { + bool pseudo_active = target_element->IsClassSet("active"); + if (name == "focus") + { + if (!pseudo_active) + source_element->Focus(); + else if (auto document = source_element->GetOwnerDocument()) + document->Focus(); + } + else + { + source_element->SetPseudoClass(name, !pseudo_active); + } + + force_update_once = true; + } + } + // Check if the id is in the form "a %d" or "c %d" - these are the ancestor or child labels. + else + { + int element_index; + if (sscanf(target_element->GetId().c_str(), "a %d", &element_index) == 1) + { + Element* new_source_element = source_element; + for (int i = 0; i < element_index; i++) + { + if (new_source_element != nullptr) + new_source_element = new_source_element->GetParentNode(); + } + SetSourceElement(new_source_element); + } + else if (sscanf(target_element->GetId().c_str(), "c %d", &element_index) == 1) + { + if (source_element != nullptr) + SetSourceElement(source_element->GetChild(element_index)); + } + } + event.StopPropagation(); + } + // Otherwise we just want to focus on the clicked element (unless it's on a debug element) + else if (enable_element_select && target_element->GetOwnerDocument() != nullptr && !IsDebuggerElement(target_element)) + { + Element* new_source_element = target_element; + if (new_source_element != source_element) + { + SetSourceElement(new_source_element); + event.StopPropagation(); + } + } + } + else if (event == EventId::Mouseover) + { + Element* target_element = event.GetTargetElement(); + ElementDocument* owner_document = target_element->GetOwnerDocument(); + if (owner_document == this) + { + // Check if the id is in the form "a %d" or "c %d" - these are the ancestor or child labels. + const String& id = target_element->GetId(); + int element_index; + if (sscanf(id.c_str(), "a %d", &element_index) == 1) + { + hover_element = source_element; + for (int i = 0; i < element_index; i++) + { + if (hover_element != nullptr) + hover_element = hover_element->GetParentNode(); + } + } + else if (sscanf(id.c_str(), "c %d", &element_index) == 1) + { + if (source_element != nullptr) + hover_element = source_element->GetChild(element_index); + } + else + { + hover_element = nullptr; + } + + if (id == "show_source" && !show_source_element) + { + // Preview the source element view while hovering + show_source_element = true; + } + + if (id == "show_source" || id == "update_source" || id == "enable_element_select") + { + title_dirty = true; + } + } + // Otherwise we just want to focus on the clicked element (unless it's on a debug element) + else if (enable_element_select && owner_document != nullptr && owner_document->GetId().find("rmlui-debug-") != 0) + { + hover_element = target_element; + } + } + else if (event == EventId::Mouseout) + { + Element* target_element = event.GetTargetElement(); + ElementDocument* owner_document = target_element->GetOwnerDocument(); + if (owner_document == this) + { + const String& id = target_element->GetId(); + if (id == "show_source") + { + // Disable the preview of the source element view + if (show_source_element && !target_element->IsClassSet("active")) + show_source_element = false; + } + + if (id == "show_source" || id == "update_source" || id == "enable_element_select") + { + title_dirty = true; + } + } + } + } +} + +void ElementInfo::SetSourceElement(Element* new_source_element) +{ + source_element = new_source_element; + force_update_once = true; +} + +void ElementInfo::UpdateSourceElement() +{ + previous_update_time = GetSystemInterface()->GetElapsedTime(); + title_dirty = true; + + // Set the pseudo classes + if (Element* pseudo = GetElementById("pseudo")) + { + PseudoClassList list; + if (source_element) + list = source_element->GetActivePseudoClasses(); + + // There are some fixed pseudo classes that we always show and iterate through to determine if they are set. + // We also want to show other pseudo classes when they are set, they are added under the #extra element last. + for (int i = 0; i < pseudo->GetNumChildren(); i++) + { + Element* child = pseudo->GetChild(i); + const String name = child->GetAttribute("name", ""); + + if (!name.empty()) + { + bool active = (list.erase(name) == 1); + child->SetClass("active", active); + } + else if(child->GetId() == "extra") + { + // First, we iterate through the extra elements and remove those that are no longer active. + for (int j = 0; j < child->GetNumChildren(); j++) + { + Element* grandchild = child->GetChild(j); + const String grandchild_name = grandchild->GetAttribute("name", ""); + bool active = (list.erase(grandchild_name) == 1); + if(!active) + child->RemoveChild(grandchild); + } + // Finally, create new pseudo buttons for the rest of the active pseudo classes. + for (auto& extra_pseudo : list) + { + Element* grandchild = child->AppendChild(CreateElement("pseudo")); + grandchild->SetClass("active", true); + grandchild->SetAttribute("name", extra_pseudo); + grandchild->SetInnerRML(":" + extra_pseudo); + } + } + } + } + + // Set the attributes + if (Element* attributes_content = GetElementById("attributes-content")) + { + String attributes; + + if (source_element != nullptr) + { + { + String name; + String value; + + // The element's attribute list is not always synchronized with its internal values, fetch + // them manually here (see e.g. Element::OnAttributeChange for relevant attributes) + { + name = "id"; + value = source_element->GetId(); + if (!value.empty()) + attributes += CreateString(name.size() + value.size() + 32, "%s: %s
", name.c_str(), value.c_str()); + } + { + name = "class"; + value = source_element->GetClassNames(); + if (!value.empty()) + attributes += CreateString(name.size() + value.size() + 32, "%s: %s
", name.c_str(), value.c_str()); + } + } + + for(const auto& pair : source_element->GetAttributes()) + { + auto& name = pair.first; + auto& variant = pair.second; + String value = StringUtilities::EncodeRml(variant.Get()); + if(name != "class" && name != "style" && name != "id") + attributes += CreateString(name.size() + value.size() + 32, "%s: %s
", name.c_str(), value.c_str()); + } + + // Text is not an attribute but useful nonetheless + if (auto text_element = rmlui_dynamic_cast(source_element)) + { + const String& text_content = text_element->GetText(); + attributes += CreateString(text_content.size() + 32, "Text: %s
", text_content.c_str()); + } + } + + if (attributes.empty()) + { + while (attributes_content->HasChildNodes()) + attributes_content->RemoveChild(attributes_content->GetChild(0)); + attributes_rml.clear(); + } + else if (attributes != attributes_rml) + { + attributes_content->SetInnerRML(attributes); + attributes_rml = std::move(attributes); + } + } + + // Set the properties + if (Element* properties_content = GetElementById("properties-content")) + { + String properties; + if (source_element != nullptr) + BuildElementPropertiesRML(properties, source_element, source_element); + + if (properties.empty()) + { + while (properties_content->HasChildNodes()) + properties_content->RemoveChild(properties_content->GetChild(0)); + properties_rml.clear(); + } + else if (properties != properties_rml) + { + properties_content->SetInnerRML(properties); + properties_rml = std::move(properties); + } + } + + // Set the events + if (Element* events_content = GetElementById("events-content")) + { + String events; + + if (source_element != nullptr) + { + events = source_element->GetEventDispatcherSummary(); + } + + if (events.empty()) + { + while (events_content->HasChildNodes()) + events_content->RemoveChild(events_content->GetChild(0)); + events_rml.clear(); + } + else if (events != events_rml) + { + events_content->SetInnerRML(events); + events_rml = std::move(events); + } + } + + // Set the position + if (Element* position_content = GetElementById("position-content")) + { + // left, top, width, height. + if (source_element != nullptr) + { + const Vector2f element_offset = source_element->GetRelativeOffset(Box::BORDER); + const Vector2f element_size = source_element->GetBox().GetSize(Box::BORDER); + + const String positions = + "left: " + ToString(element_offset.x) + "px
" + + "top: " + ToString(element_offset.y) + "px
" + + "width: " + ToString(element_size.x) + "px
" + + "height: " + ToString(element_size.y) + "px
"; + + position_content->SetInnerRML( positions ); + } + else + { + while (position_content->HasChildNodes()) + position_content->RemoveChild(position_content->GetFirstChild()); + } + } + + // Set the ancestors + if (Element* ancestors_content = GetElementById("ancestors-content")) + { + String ancestors; + Element* element_ancestor = nullptr; + if (source_element != nullptr) + element_ancestor = source_element->GetParentNode(); + + int ancestor_depth = 1; + while (element_ancestor) + { + String ancestor_name = element_ancestor->GetAddress(false, false); + ancestors += CreateString(ancestor_name.size() + 32, "

%s

", ancestor_depth, ancestor_name.c_str()); + element_ancestor = element_ancestor->GetParentNode(); + ancestor_depth++; + } + + if (ancestors.empty()) + { + while (ancestors_content->HasChildNodes()) + ancestors_content->RemoveChild(ancestors_content->GetFirstChild()); + ancestors_rml.clear(); + } + else if (ancestors != ancestors_rml) + { + ancestors_content->SetInnerRML(ancestors); + ancestors_rml = std::move(ancestors); + } + } + + // Set the children + if (Element* children_content = GetElementById("children-content")) + { + String children; + if (source_element != nullptr) + { + const int num_dom_children = (source_element->GetNumChildren(false)); + + for (int i = 0; i < source_element->GetNumChildren(true); i++) + { + Element* child = source_element->GetChild(i); + + // If this is a debugger document, do not show it. + if (IsDebuggerElement(child)) + continue; + + String child_name = child->GetTagName(); + const String child_id = child->GetId(); + if (!child_id.empty()) + { + child_name += "#"; + child_name += child_id; + } + const char* non_dom_string = (i >= num_dom_children ? " class=\"non_dom\"" : ""); + + children += CreateString(child_name.size() + 40, "

%s

", i, non_dom_string, child_name.c_str()); + } + } + + if (children.empty()) + { + while (children_content->HasChildNodes()) + children_content->RemoveChild(children_content->GetChild(0)); + children_rml.clear(); + } + else if(children != children_rml) + { + children_content->SetInnerRML(children); + children_rml = std::move(children); + } + } +} + +void ElementInfo::BuildElementPropertiesRML(String& property_rml, Element* element, Element* primary_element) +{ + NamedPropertyList property_list; + + for(auto it = element->IterateLocalProperties(); !it.AtEnd(); ++it) + { + PropertyId property_id = it.GetId(); + const String& property_name = it.GetName(); + const Property* prop = &it.GetProperty(); + + // Check that this property isn't overridden or just not inherited. + if (primary_element->GetProperty(property_id) != prop) + continue; + + property_list.push_back(NamedProperty{ property_name, prop }); + } + + std::sort(property_list.begin(), property_list.end(), + [](const NamedProperty& a, const NamedProperty& b) { + if (a.second->source && !b.second->source) return false; + if (!a.second->source && b.second->source) return true; + return a.second->specificity > b.second->specificity; + } + ); + + if (!property_list.empty()) + { + // Print the 'inherited from ...' header if we're not the primary element. + if (element != primary_element) + { + property_rml += "

inherited from " + element->GetAddress(false, false) + "

"; + } + + const PropertySource* previous_source = nullptr; + bool first_iteration = true; + + for (auto& named_property : property_list) + { + auto& source = named_property.second->source; + if(source.get() != previous_source || first_iteration) + { + previous_source = source.get(); + first_iteration = false; + + // Print the rule name header. + if(source) + { + String str_line_number; + TypeConverter::Convert(source->line_number, str_line_number); + property_rml += "

" + source->rule_name + "

"; + property_rml += "

" + source->path + " : " + str_line_number + "

"; + } + else + { + property_rml += "

inline

"; + } + } + + BuildPropertyRML(property_rml, named_property.first, named_property.second); + } + } + + if (element->GetParentNode() != nullptr) + BuildElementPropertiesRML(property_rml, element->GetParentNode(), primary_element); +} + +void ElementInfo::BuildPropertyRML(String& property_rml, const String& name, const Property* property) +{ + const String property_value = property->ToString(); + + property_rml += "" + name + ": " + property_value + "
"; +} + +void ElementInfo::UpdateTitle() +{ + auto title_content = GetElementById("title-content"); + auto enable_select = GetElementById("enable_element_select"); + auto show_source = GetElementById("show_source"); + auto update_source = GetElementById("update_source"); + + if (title_content && enable_select && show_source && update_source) + { + if (enable_select->IsPseudoClassSet("hover")) + title_content->SetInnerRML("(select elements)"); + else if (show_source->IsPseudoClassSet("hover")) + title_content->SetInnerRML("(draw element dimensions)"); + else if (update_source->IsPseudoClassSet("hover")) + title_content->SetInnerRML("(update info continuously)"); + else if (source_element) + title_content->SetInnerRML(source_element->GetTagName()); + else + title_content->SetInnerRML("Element Information"); + } +} + + +bool ElementInfo::IsDebuggerElement(Element* element) +{ + return element->GetOwnerDocument()->GetId().find("rmlui-debug-") == 0; +} + +} +} diff --git a/thirdparty/RmlUi/Source/Debugger/ElementInfo.h b/thirdparty/RmlUi/Source/Debugger/ElementInfo.h new file mode 100644 index 000000000..ebc4594b4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/ElementInfo.h @@ -0,0 +1,103 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_ELEMENTINFO_H +#define RMLUI_DEBUGGER_ELEMENTINFO_H + +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/EventListener.h" + +namespace Rml { +namespace Debugger { + +typedef Pair< String, const Property* > NamedProperty; +typedef Vector< NamedProperty > NamedPropertyList; + +/** + @author Robert Curry + */ + +class ElementInfo : public ElementDocument, public EventListener +{ +public: + RMLUI_RTTI_DefineWithParent(ElementInfo, ElementDocument) + + ElementInfo(const String& tag); + ~ElementInfo(); + + /// Initialises the info element. + /// @return True if the element initialised successfully, false otherwise. + bool Initialise(); + /// Clears the element references. + void Reset(); + + /// Called when an element is destroyed. + void OnElementDestroy(Element* element); + + void RenderHoverElement(); + void RenderSourceElement(); + +protected: + void ProcessEvent(Event& event) override; + /// Updates the element info if changed + void OnUpdate() override; + +private: + void SetSourceElement(Element* new_source_element); + void UpdateSourceElement(); + + void BuildElementPropertiesRML(String& property_rml, Element* element, Element* primary_element); + void BuildPropertyRML(String& property_rml, const String& name, const Property* property); + + void UpdateTitle(); + + bool IsDebuggerElement(Element* element); + + double previous_update_time; + + String attributes_rml, properties_rml, events_rml, ancestors_rml, children_rml; + + // Enables or disables the selection of elements in user context. + bool enable_element_select; + // Draws the dimensions of the source element. + bool show_source_element; + // Updates the source element information at regular intervals. + bool update_source_element; + // Forces an update to the source element during the next update loop. + bool force_update_once; + + bool title_dirty; + + Element* hover_element; + Element* source_element; +}; + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/ElementLog.cpp b/thirdparty/RmlUi/Source/Debugger/ElementLog.cpp new file mode 100644 index 000000000..0689d51f6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/ElementLog.cpp @@ -0,0 +1,306 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementLog.h" +#include "CommonSource.h" +#include "BeaconSource.h" +#include "LogSource.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/Factory.h" +#include + +namespace Rml { +namespace Debugger { + +const int MAX_LOG_MESSAGES = 50; + +ElementLog::ElementLog(const String& tag) : ElementDocument(tag) +{ + dirty_logs = false; + beacon = nullptr; + current_beacon_level = Log::LT_MAX; + auto_scroll = true; + message_content = nullptr; + current_index = 0; + + // Set up the log type buttons. + log_types[Log::LT_ALWAYS].visible = true; + log_types[Log::LT_ALWAYS].class_name = "error"; + log_types[Log::LT_ALWAYS].alert_contents = "A"; + + log_types[Log::LT_ERROR].visible = true; + log_types[Log::LT_ERROR].class_name = "error"; + log_types[Log::LT_ERROR].alert_contents = "!"; + log_types[Log::LT_ERROR].button_name = "error_button"; + + log_types[Log::LT_ASSERT].visible = true; + log_types[Log::LT_ASSERT].class_name = "error"; + log_types[Log::LT_ASSERT].alert_contents = "!"; + + log_types[Log::LT_WARNING].visible = true; + log_types[Log::LT_WARNING].class_name = "warning"; + log_types[Log::LT_WARNING].alert_contents = "!"; + log_types[Log::LT_WARNING].button_name = "warning_button"; + + log_types[Log::LT_INFO].visible = false; + log_types[Log::LT_INFO].class_name = "info"; + log_types[Log::LT_INFO].alert_contents = "i"; + log_types[Log::LT_INFO].button_name = "info_button"; + + log_types[Log::LT_DEBUG].visible = true; + log_types[Log::LT_DEBUG].class_name = "debug"; + log_types[Log::LT_DEBUG].alert_contents = "?"; + log_types[Log::LT_DEBUG].button_name = "debug_button"; +} + +ElementLog::~ElementLog() +{ +} + +// Initialises the log element. +bool ElementLog::Initialise() +{ + SetInnerRML(log_rml); + SetId("rmlui-debug-log"); + + message_content = GetElementById("content"); + if (message_content) + { + message_content->AddEventListener(EventId::Resize, this); + } + + SharedPtr style_sheet = Factory::InstanceStyleSheetString(String(common_rcss) + String(log_rcss)); + if (!style_sheet) + return false; + + SetStyleSheet(std::move(style_sheet)); + + AddEventListener(EventId::Click, this); + + // Create the log beacon. + beacon = GetContext()->CreateDocument(); + if (!beacon) + return false; + + beacon->SetId("rmlui-debug-log-beacon"); + beacon->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + beacon->SetInnerRML(beacon_rml); + + Element* button = beacon->GetFirstChild(); + if (button) + beacon->GetFirstChild()->AddEventListener(EventId::Click, this); + + style_sheet = Factory::InstanceStyleSheetString(String(common_rcss) + String(beacon_rcss)); + if (!style_sheet) + { + GetContext()->UnloadDocument(beacon); + beacon = nullptr; + return false; + } + + beacon->SetStyleSheet(style_sheet); + + return true; +} + +// Adds a log message to the debug log. +void ElementLog::AddLogMessage(Log::Type type, const String& message) +{ + LogMessageList& log_message_list = log_types[type].log_messages; + if (log_message_list.size() >= MAX_LOG_MESSAGES) + { + log_message_list.erase(log_message_list.begin()); + } + + // Add the message to the list of messages for the specified log type. + LogMessage log_message; + log_message.index = current_index++; + log_message.message = StringUtilities::EncodeRml(message); + log_message_list.push_back(log_message); + + // If this log type is invisible, and there is a button for this log type, then change its text from + // "Off" to "Off*" to signal that there are unread logs. + if (!log_types[type].visible) + { + if (!log_types[type].button_name.empty()) + { + Element* button = GetElementById(log_types[type].button_name); + if (button) + { + button->SetInnerRML("Off*"); + } + } + } + // Trigger the beacon if we're hidden. Override any lower-level log type if it is already visible. + else + { + if (beacon != nullptr) + { + if (type < current_beacon_level) + { + beacon->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + + current_beacon_level = type; + Element* beacon_button = beacon->GetFirstChild(); + if (beacon_button) + { + beacon_button->SetClassNames(log_types[type].class_name); + beacon_button->SetInnerRML(log_types[type].alert_contents); + } + } + } + } + + // Force a refresh of the RML. + dirty_logs = true; +} + +void ElementLog::OnUpdate() +{ + ElementDocument::OnUpdate(); + + if (dirty_logs) + { + // Set the log content: + String messages; + if (message_content) + { + unsigned int log_pointers[Log::LT_MAX]; + for (int i = 0; i < Log::LT_MAX; i++) + log_pointers[i] = 0; + int next_type = FindNextEarliestLogType(log_pointers); + int num_messages = 0; + while (next_type != -1 && num_messages < MAX_LOG_MESSAGES) + { + messages += CreateString(128, "
%s

", log_types[next_type].class_name.c_str(), log_types[next_type].alert_contents.c_str()); + messages += log_types[next_type].log_messages[log_pointers[next_type]].message; + messages += "

"; + + log_pointers[next_type]++; + next_type = FindNextEarliestLogType(log_pointers); + num_messages++; + } + + if (message_content->HasChildNodes()) + { + float last_element_top = message_content->GetLastChild()->GetAbsoluteTop(); + auto_scroll = message_content->GetAbsoluteTop() + message_content->GetAbsoluteTop() > last_element_top; + } + else + auto_scroll = true; + + message_content->SetInnerRML(messages); + + dirty_logs = false; + } + } +} + +void ElementLog::ProcessEvent(Event& event) +{ + // Only process events if we're visible + if (beacon != nullptr) + { + if (event == EventId::Click) + { + if (event.GetTargetElement() == beacon->GetFirstChild()) + { + if (!IsVisible()) + SetProperty(PropertyId::Visibility, Property(Style::Visibility::Visible)); + + beacon->SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + current_beacon_level = Log::LT_MAX; + } + else if (event.GetTargetElement()->GetId() == "close_button") + { + SetProperty(PropertyId::Visibility, Property(Style::Visibility::Hidden)); + } + else if (event.GetTargetElement()->GetId() == "clear_button") + { + for (int i = 0; i < Log::LT_MAX; i++) + { + log_types[i].log_messages.clear(); + if (!log_types[i].visible) + { + if (Element * button = GetElementById(log_types[i].button_name)) + button->SetInnerRML("Off"); + } + } + dirty_logs = true; + } + else + { + for (int i = 0; i < Log::LT_MAX; i++) + { + if (!log_types[i].button_name.empty() && event.GetTargetElement()->GetId() == log_types[i].button_name) + { + log_types[i].visible = !log_types[i].visible; + if (log_types[i].visible) + event.GetTargetElement()->SetInnerRML("On"); + else + event.GetTargetElement()->SetInnerRML("Off"); + dirty_logs = true; + } + } + } + } + } + + if (event == EventId::Resize && auto_scroll) + { + if (message_content != nullptr && + message_content->HasChildNodes()) + message_content->GetLastChild()->ScrollIntoView(); + } +} + +int ElementLog::FindNextEarliestLogType(unsigned int log_pointers[Log::LT_MAX]) +{ + int log_channel = -1; + unsigned int index = UINT_MAX; + + for (int i = 0; i < Log::LT_MAX; i++) + { + if (log_types[i].visible) + { + if (log_pointers[i] < log_types[i].log_messages.size()) + { + if (log_types[i].log_messages[log_pointers[i]].index < index) + { + index = log_types[i].log_messages[log_pointers[i]].index; + log_channel = i; + } + } + } + } + + return log_channel; +} + +} +} diff --git a/thirdparty/RmlUi/Source/Debugger/ElementLog.h b/thirdparty/RmlUi/Source/Debugger/ElementLog.h new file mode 100644 index 000000000..8abc33efd --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/ElementLog.h @@ -0,0 +1,95 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_ELEMENTLOG_H +#define RMLUI_DEBUGGER_ELEMENTLOG_H + +#include "../../Include/RmlUi/Core/ElementDocument.h" +#include "../../Include/RmlUi/Core/EventListener.h" +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { +namespace Debugger { + +class DebuggerSystemInterface; + +/** + @author Robert Curry + */ + +class ElementLog : public Rml::ElementDocument, public Rml::EventListener +{ +public: + RMLUI_RTTI_DefineWithParent(ElementLog, Rml::ElementDocument) + + ElementLog(const String& tag); + ~ElementLog(); + + /// Initialises the log element. + /// @return True if the element initialised successfully, false otherwise. + bool Initialise(); + + /// Adds a log message to the debug log. + void AddLogMessage(Log::Type type, const String& message); + +protected: + void OnUpdate() override; + void ProcessEvent(Event& event) override; + +private: + struct LogMessage + { + unsigned int index; + String message; + }; + using LogMessageList = Vector< LogMessage >; + + struct LogType + { + bool visible; + String class_name; + String alert_contents; + String button_name; + LogMessageList log_messages; + }; + LogType log_types[Log::LT_MAX]; + + int FindNextEarliestLogType(unsigned int log_pointers[Log::LT_MAX]); + + unsigned int current_index; + bool dirty_logs; + bool auto_scroll; + Element* message_content; + ElementDocument* beacon; + int current_beacon_level; +}; + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/FontSource.h b/thirdparty/RmlUi/Source/Debugger/FontSource.h new file mode 100644 index 000000000..454389177 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/FontSource.h @@ -0,0 +1,5195 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_FONTSOURCE_H +#define RMLUI_DEBUGGER_FONTSOURCE_H + +/* + The fonts 'Courier Prime Code' and 'Courier Prime Code Italic', included + in this file, are licensed under the following terms. + + ----------------------------------------------------------- + + Copyright (c) 2013, Quote-Unquote Apps (http://quoteunquoteapps.com), + with Reserved Font Name Courier Prime. + + This Font Software is licensed under the SIL Open Font License, Version 1.1. + This license is copied below, and is also available with a FAQ at: + http://scripts.sil.org/OFL + + + ----------------------------------------------------------- + SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 + ----------------------------------------------------------- + + PREAMBLE + The goals of the Open Font License (OFL) are to stimulate worldwide + development of collaborative font projects, to support the font creation + efforts of academic and linguistic communities, and to provide a free and + open framework in which fonts may be shared and improved in partnership + with others. + + The OFL allows the licensed fonts to be used, studied, modified and + redistributed freely as long as they are not sold by themselves. The + fonts, including any derivative works, can be bundled, embedded, + redistributed and/or sold with any software provided that any reserved + names are not used by derivative works. The fonts and derivatives, + however, cannot be released under any other type of license. The + requirement for fonts to remain under this license does not apply + to any document created using the fonts or their derivatives. + + DEFINITIONS + "Font Software" refers to the set of files released by the Copyright + Holder(s) under this license and clearly marked as such. This may + include source files, build scripts and documentation. + + "Reserved Font Name" refers to any names specified as such after the + copyright statement(s). + + "Original Version" refers to the collection of Font Software components as + distributed by the Copyright Holder(s). + + "Modified Version" refers to any derivative made by adding to, deleting, + or substituting -- in part or in whole -- any of the components of the + Original Version, by changing formats or by porting the Font Software to a + new environment. + + "Author" refers to any designer, engineer, programmer, technical + writer or other person who contributed to the Font Software. + + PERMISSION & CONDITIONS + Permission is hereby granted, free of charge, to any person obtaining + a copy of the Font Software, to use, study, copy, merge, embed, modify, + redistribute, and sell modified and unmodified copies of the Font + Software, subject to the following conditions: + + 1) Neither the Font Software nor any of its individual components, + in Original or Modified Versions, may be sold by itself. + + 2) Original or Modified Versions of the Font Software may be bundled, + redistributed and/or sold with any software, provided that each copy + contains the above copyright notice and this license. These can be + included either as stand-alone text files, human-readable headers or + in the appropriate machine-readable metadata fields within text or + binary files as long as those fields can be easily viewed by the user. + + 3) No Modified Version of the Font Software may use the Reserved Font + Name(s) unless explicit written permission is granted by the corresponding + Copyright Holder. This restriction only applies to the primary font name as + presented to the users. + + 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font + Software shall not be used to promote, endorse or advertise any + Modified Version, except to acknowledge the contribution(s) of the + Copyright Holder(s) and the Author(s) or with their explicit written + permission. + + 5) The Font Software, modified or unmodified, in part or in whole, + must be distributed entirely under this license, and must not be + distributed under any other license. The requirement for fonts to + remain under this license does not apply to any document created + using the Font Software. + + TERMINATION + This license becomes null and void if any of the above conditions are + not met. + + DISCLAIMER + THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT + OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE + COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL + DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM + OTHER DEALINGS IN THE FONT SOFTWARE. + +*/ + + + +static const unsigned char courier_prime_code[] = { + 0x0,0x1,0x0,0x0,0x0,0x10,0x1,0x0,0x0,0x4,0x0,0x0,0x44,0x53,0x49,0x47,0x0,0x0,0x0,0x1,0x0,0x1,0x20,0x48,0x0,0x0,0x0,0x8,0x47,0x53, + 0x55,0x42,0x1a,0x6f,0xb,0xcc,0x0,0x0,0x1,0xc,0x0,0x0,0x4,0x6e,0x4f,0x53,0x2f,0x32,0x71,0x18,0x89,0x8e,0x0,0x0,0x5,0x7c,0x0,0x0,0x0,0x60, + 0x63,0x6d,0x61,0x70,0xd7,0xce,0xb9,0xf9,0x0,0x0,0x5,0xdc,0x0,0x0,0x6,0x46,0x63,0x76,0x74,0x20,0x22,0xd6,0xfe,0xb8,0x0,0x1,0x13,0x98,0x0,0x0, + 0x0,0x3c,0x66,0x70,0x67,0x6d,0x3f,0xae,0x1b,0x9f,0x0,0x1,0x13,0xd4,0x0,0x0,0xb,0xe2,0x67,0x61,0x73,0x70,0x0,0x0,0x0,0x10,0x0,0x1,0x13,0x90, + 0x0,0x0,0x0,0x8,0x67,0x6c,0x79,0x66,0xcf,0x99,0x79,0xec,0x0,0x0,0xc,0x24,0x0,0x0,0xbc,0xce,0x68,0x65,0x61,0x64,0xd,0x2f,0xe1,0xd2,0x0,0x0, + 0xc8,0xf4,0x0,0x0,0x0,0x36,0x68,0x68,0x65,0x61,0xf,0x24,0xb,0x9c,0x0,0x0,0xc9,0x2c,0x0,0x0,0x0,0x24,0x68,0x6d,0x74,0x78,0x59,0x11,0x10,0xfa, + 0x0,0x0,0xc9,0x50,0x0,0x0,0x6,0x38,0x6c,0x6f,0x63,0x61,0x6d,0x14,0x9f,0x1,0x0,0x0,0xcf,0x88,0x0,0x0,0x3,0x38,0x6d,0x61,0x78,0x70,0x2,0xe9, + 0xc,0xe7,0x0,0x0,0xd2,0xc0,0x0,0x0,0x0,0x20,0x6e,0x61,0x6d,0x65,0xb8,0x46,0xea,0xc9,0x0,0x0,0xd2,0xe0,0x0,0x0,0x37,0x6b,0x70,0x6f,0x73,0x74, + 0xae,0xc8,0xe9,0xb5,0x0,0x1,0xa,0x4c,0x0,0x0,0x9,0x44,0x70,0x72,0x65,0x70,0x19,0x50,0x2,0x10,0x0,0x1,0x1f,0xb8,0x0,0x0,0x0,0x8d,0x0,0x1, + 0x0,0x0,0x0,0xa,0x0,0xa2,0x2,0x30,0x0,0x3,0x44,0x46,0x4c,0x54,0x0,0x14,0x67,0x72,0x65,0x6b,0x0,0x28,0x6c,0x61,0x74,0x6e,0x0,0x3c,0x0,0x4, + 0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x5,0x0,0x0,0x0,0x6,0x0,0xc,0x0,0x15,0x0,0x1b,0x0,0x4,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x5,0x0,0x1, + 0x0,0x7,0x0,0xd,0x0,0x16,0x0,0x1c,0x0,0x16,0x0,0x3,0x43,0x41,0x54,0x20,0x0,0x26,0x4d,0x4f,0x4c,0x20,0x0,0x38,0x52,0x4f,0x4d,0x20,0x0,0x4a, + 0x0,0x0,0xff,0xff,0x0,0x5,0x0,0x2,0x0,0x8,0x0,0xe,0x0,0x17,0x0,0x1d,0x0,0x0,0xff,0xff,0x0,0x6,0x0,0x3,0x0,0x9,0x0,0xf,0x0,0x12, + 0x0,0x18,0x0,0x1e,0x0,0x0,0xff,0xff,0x0,0x6,0x0,0x4,0x0,0xa,0x0,0x10,0x0,0x13,0x0,0x19,0x0,0x1f,0x0,0x0,0xff,0xff,0x0,0x6,0x0,0x5, + 0x0,0xb,0x0,0x11,0x0,0x14,0x0,0x1a,0x0,0x20,0x0,0x21,0x61,0x61,0x6c,0x74,0x0,0xc8,0x61,0x61,0x6c,0x74,0x0,0xce,0x61,0x61,0x6c,0x74,0x0,0xd4, + 0x61,0x61,0x6c,0x74,0x0,0xda,0x61,0x61,0x6c,0x74,0x0,0xe0,0x61,0x61,0x6c,0x74,0x0,0xe6,0x63,0x61,0x73,0x65,0x0,0xec,0x63,0x61,0x73,0x65,0x0,0xf2, + 0x63,0x61,0x73,0x65,0x0,0xf8,0x63,0x61,0x73,0x65,0x0,0xfe,0x63,0x61,0x73,0x65,0x1,0x4,0x63,0x61,0x73,0x65,0x1,0xa,0x66,0x72,0x61,0x63,0x1,0x10, + 0x66,0x72,0x61,0x63,0x1,0x16,0x66,0x72,0x61,0x63,0x1,0x1c,0x66,0x72,0x61,0x63,0x1,0x22,0x66,0x72,0x61,0x63,0x1,0x28,0x66,0x72,0x61,0x63,0x1,0x2e, + 0x6c,0x6f,0x63,0x6c,0x1,0x34,0x6c,0x6f,0x63,0x6c,0x1,0x3a,0x6c,0x6f,0x63,0x6c,0x1,0x40,0x6f,0x72,0x64,0x6e,0x1,0x46,0x6f,0x72,0x64,0x6e,0x1,0x4c, + 0x6f,0x72,0x64,0x6e,0x1,0x52,0x6f,0x72,0x64,0x6e,0x1,0x58,0x6f,0x72,0x64,0x6e,0x1,0x5e,0x6f,0x72,0x64,0x6e,0x1,0x64,0x73,0x75,0x70,0x73,0x1,0x6a, + 0x73,0x75,0x70,0x73,0x1,0x70,0x73,0x75,0x70,0x73,0x1,0x76,0x73,0x75,0x70,0x73,0x1,0x7c,0x73,0x75,0x70,0x73,0x1,0x82,0x73,0x75,0x70,0x73,0x1,0x88, + 0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0, + 0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x7, + 0x0,0x0,0x0,0x1,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x5, + 0x0,0x0,0x0,0x1,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x3,0x0,0x0,0x0,0x1,0x0,0x2, + 0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0x6, + 0x0,0x0,0x0,0x1,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x4, + 0x0,0x0,0x0,0x1,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x4,0x0,0xa,0x0,0x16,0x0,0x1e,0x0,0x26,0x0,0x2e,0x0,0x38, + 0x0,0x40,0x0,0x48,0x0,0x52,0x0,0x5a,0x0,0x62,0x0,0x1,0x0,0x0,0x0,0x1,0x1,0x10,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x4c,0x0,0x1,0x0,0x0, + 0x0,0x1,0x0,0x52,0x0,0x6,0x0,0x0,0x0,0x2,0x0,0x58,0x0,0x6c,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x76,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x74, + 0x0,0x6,0x0,0x0,0x0,0x2,0x0,0x98,0x0,0xaa,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0xb2,0x0,0x4,0x0,0x0,0x0,0x1,0x1,0x6,0x0,0x1,0x0,0x0, + 0x0,0x1,0x1,0x1c,0x0,0x2,0x1,0x22,0x0,0x4,0x0,0x5e,0x0,0x63,0x0,0xdd,0x0,0xe3,0x0,0x2,0x1,0x14,0x0,0x4,0x0,0x5e,0x0,0x63,0x0,0xdd, + 0x0,0xe3,0x0,0x3,0x0,0x0,0x0,0x2,0x1,0x12,0x1,0x18,0x0,0x1,0x1,0x12,0x0,0x1,0x0,0x0,0x0,0x8,0x0,0x3,0x0,0x0,0x0,0x2,0x1,0xa, + 0x1,0x4,0x0,0x1,0x1,0xa,0x0,0x1,0x0,0x0,0x0,0x8,0x0,0x1,0x0,0xfc,0x0,0xd,0x0,0x1,0x1,0x0,0x0,0x2,0x0,0xa,0x0,0x20,0x0,0x2, + 0x0,0x6,0x0,0xe,0x1,0x12,0x0,0x3,0x1,0x32,0x1,0x9,0x1,0x13,0x0,0x3,0x1,0x32,0x1,0xb,0x0,0x1,0x0,0x4,0x1,0x14,0x0,0x3,0x1,0x32, + 0x1,0xb,0x0,0x3,0x0,0x1,0x0,0xdc,0x0,0x1,0x0,0xe6,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x9,0x0,0x3,0x0,0x1,0x0,0xca,0x0,0x1,0x0,0xdc, + 0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x9,0x0,0x2,0x0,0xd2,0x0,0xe,0x1,0x7f,0x1,0x84,0x1,0x85,0x1,0x86,0x1,0x87,0x1,0x88,0x1,0x89,0x1,0x8a, + 0x1,0x8b,0x1,0x8c,0x1,0x8d,0x1,0x8e,0x1,0x8f,0x1,0x90,0x0,0x2,0x0,0xcc,0x0,0x1a,0x1,0x1,0x1,0x2,0x0,0x5e,0x0,0x63,0x1,0x1,0x1,0x2, + 0x0,0xdd,0x0,0xe3,0x1,0x15,0x1,0x16,0x1,0x17,0x1,0x18,0x1,0x7f,0x1,0x84,0x1,0x85,0x1,0x86,0x1,0x87,0x1,0x88,0x1,0x89,0x1,0x8a,0x1,0x8b, + 0x1,0x8c,0x1,0x8d,0x1,0x8e,0x1,0x8f,0x1,0x90,0x0,0x1,0x0,0xca,0x0,0x2,0x0,0xa,0x0,0x14,0x0,0x1,0x0,0x4,0x0,0x3e,0x0,0x2,0x1,0x24, + 0x0,0x1,0x0,0x4,0x0,0xbd,0x0,0x2,0x1,0x24,0x0,0x2,0x0,0xb4,0x0,0x4,0x1,0x1,0x1,0x2,0x1,0x1,0x1,0x2,0x0,0x1,0x0,0x4,0x0,0x5c, + 0x0,0x62,0x0,0xdb,0x0,0xe2,0x0,0x1,0x0,0x1,0x0,0xb9,0x0,0x1,0x0,0x1,0x1,0x24,0x0,0x1,0x0,0x1,0x0,0x3a,0x0,0x2,0x0,0x1,0x1,0x8, + 0x1,0xb,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x8,0x1,0xa,0x0,0x2,0x0,0x1,0x1,0x7,0x1,0x10,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x2,0x0,0x7f, + 0x0,0x1,0x0,0x2,0x0,0x47,0x0,0xc6,0x0,0x2,0x0,0x4,0x1,0x7e,0x1,0x7e,0x0,0x0,0x1,0x80,0x1,0x80,0x0,0x1,0x1,0x82,0x1,0x83,0x0,0x2, + 0x1,0x91,0x1,0x9a,0x0,0x4,0x0,0x1,0x0,0x1a,0x0,0x2,0x0,0x47,0x0,0x5c,0x0,0x62,0x0,0x7f,0x0,0xc6,0x0,0xdb,0x0,0xe2,0x1,0x8,0x1,0x9, + 0x1,0xa,0x1,0xb,0x1,0x7e,0x1,0x80,0x1,0x82,0x1,0x83,0x1,0x91,0x1,0x92,0x1,0x93,0x1,0x94,0x1,0x95,0x1,0x96,0x1,0x97,0x1,0x98,0x1,0x99, + 0x1,0x9a,0x0,0x1,0x0,0x2,0x0,0x3a,0x0,0xb9,0x0,0x1,0x0,0x4,0x0,0x2,0x0,0x47,0x0,0x7f,0x0,0xc6,0x0,0x0,0x0,0x3,0x4,0xe0,0x1,0x90, + 0x0,0x5,0x0,0x8,0x5,0x33,0x4,0xcc,0x0,0x0,0x0,0x99,0x5,0x33,0x4,0xcc,0x0,0x0,0x2,0xcc,0x0,0x82,0x2,0x2a,0x0,0x0,0x0,0x0,0x5,0x9, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x51,0x55,0x51,0x41,0x0,0x40,0x0,0x20, + 0xfb,0x2,0x5,0x8d,0xfd,0x7d,0x0,0xc2,0x7,0x5,0x3,0x47,0x20,0x0,0x0,0x93,0x0,0x0,0x0,0x0,0x3,0x9c,0x4,0xa3,0x0,0x0,0x0,0x20,0x0,0x3, + 0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x3,0x0,0x0,0x2,0x14,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1c,0x0,0x3,0x0,0x1,0x0,0x0,0x2,0x14,0x0,0x6, + 0x1,0xf8,0x0,0x0,0x0,0x9,0x0,0xf7,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x29,0x1,0x2f, + 0x1,0x2b,0x1,0x51,0x1,0x67,0x1,0x72,0x1,0x30,0x1,0x38,0x1,0x39,0x1,0x22,0x1,0x69,0x1,0x27,0x1,0x41,0x1,0x2c,0x1,0x32,0x1,0x7,0x1,0x8, + 0x1,0x9,0x1,0xa,0x1,0xb,0x1,0xc,0x1,0xd,0x1,0xe,0x1,0xf,0x1,0x10,0x1,0x26,0x1,0x31,0x1,0x60,0x1,0x5b,0x1,0x5c,0x1,0x2d,0x1,0x71, + 0x0,0x2,0x0,0xd,0x0,0xe,0x0,0x14,0x0,0x18,0x0,0x22,0x0,0x23,0x0,0x28,0x0,0x2b,0x0,0x36,0x0,0x38,0x0,0x3a,0x0,0x40,0x0,0x41,0x0,0x47, + 0x0,0x52,0x0,0x54,0x0,0x55,0x0,0x59,0x0,0x5f,0x0,0x64,0x0,0x6f,0x0,0x70,0x0,0x75,0x0,0x76,0x0,0x7b,0x1,0x36,0x1,0x23,0x1,0x37,0x1,0x79, + 0x1,0x33,0x1,0x95,0x0,0x7f,0x0,0x8a,0x0,0x8b,0x0,0x91,0x0,0x95,0x0,0x9f,0x0,0xa0,0x0,0xa5,0x0,0xa8,0x0,0xb4,0x0,0xb7,0x0,0xb9,0x0,0xbf, + 0x0,0xc0,0x0,0xc6,0x0,0xd1,0x0,0xd3,0x0,0xd4,0x0,0xd8,0x0,0xdf,0x0,0xe4,0x0,0xef,0x0,0xf0,0x0,0xf5,0x0,0xf6,0x0,0xfb,0x1,0x34,0x1,0x6f, + 0x1,0x35,0x1,0x59,0x0,0x0,0x0,0x6,0x0,0xa,0x0,0x11,0x0,0x19,0x0,0x46,0x0,0x4b,0x0,0x68,0x0,0x80,0x0,0x84,0x0,0x82,0x0,0x83,0x0,0x88, + 0x0,0x87,0x0,0x8e,0x0,0x96,0x0,0x9c,0x0,0x99,0x0,0x9a,0x0,0xaa,0x0,0xaf,0x0,0xac,0x0,0xad,0x0,0xc5,0x0,0xc7,0x0,0xcb,0x0,0xc9,0x0,0xca, + 0x0,0xcf,0x0,0xe5,0x0,0xe9,0x0,0xe7,0x0,0xe8,0x1,0x7a,0x1,0x78,0x1,0x4f,0x1,0x55,0x1,0x76,0x1,0x25,0x1,0x73,0x0,0xde,0x1,0x75,0x1,0x74, + 0x1,0x77,0x1,0x80,0x1,0x93,0x1,0x65,0x0,0xc,0x0,0x4f,0x1,0x5e,0x1,0x6a,0x1,0x61,0x1,0x5d,0x1,0x57,0x0,0x0,0x1,0x66,0x1,0x6d,0x1,0x6b, + 0x1,0x6,0x1,0x5f,0x1,0x1,0x1,0x2,0x1,0x4,0x0,0x89,0x0,0xce,0x1,0x2e,0x1,0x2a,0x1,0x62,0x1,0x6c,0x1,0x53,0x1,0x58,0x0,0x0,0x1,0x44, + 0x1,0x45,0x1,0x28,0x1,0x4e,0x0,0x7,0x0,0xb,0x0,0x50,0x0,0x51,0x0,0xd0,0x1,0x40,0x1,0x3f,0x1,0x49,0x1,0x4a,0x1,0x4b,0x1,0x4c,0x1,0x5a, + 0x1,0x6e,0x0,0xf9,0x0,0x79,0x1,0x11,0x1,0x52,0x1,0x46,0x1,0x47,0x0,0xff,0x1,0x0,0x1,0x7b,0x1,0x24,0x1,0x4d,0x1,0x48,0x1,0x68,0x0,0x5, + 0x0,0x1c,0x0,0x3,0x0,0x1d,0x0,0x1f,0x0,0x2d,0x0,0x2f,0x0,0x30,0x0,0x32,0x0,0x48,0x0,0x4a,0x0,0x0,0x0,0x4c,0x0,0x65,0x0,0x67,0x0,0x69, + 0x0,0xa9,0x1,0x92,0x1,0x9a,0x1,0x97,0x1,0x82,0x1,0x94,0x1,0x99,0x1,0x91,0x1,0x96,0x1,0x98,0x1,0x83,0x0,0x4,0x4,0x32,0x0,0x0,0x0,0x5a, + 0x0,0x40,0x0,0x5,0x0,0x1a,0x0,0x2f,0x0,0x7e,0x0,0xb4,0x1,0x37,0x1,0x48,0x1,0x7e,0x1,0x92,0x2,0x1b,0x2,0x37,0x2,0xc7,0x2,0xdd,0x3,0x26, + 0x3,0x94,0x3,0xa9,0x3,0xbc,0x3,0xc0,0x1e,0x85,0x1e,0xf3,0x20,0x11,0x20,0x14,0x20,0x1a,0x20,0x1e,0x20,0x22,0x20,0x26,0x20,0x30,0x20,0x33,0x20,0x3a, + 0x20,0x44,0x20,0x74,0x20,0xa3,0x20,0xa9,0x20,0xac,0x21,0x22,0x22,0x2,0x22,0xf,0x22,0x12,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60,0x22,0x65, + 0x25,0xca,0xfb,0x2,0xff,0xff,0x0,0x0,0x0,0x20,0x0,0x30,0x0,0xa0,0x0,0xb6,0x1,0x39,0x1,0x4a,0x1,0x92,0x2,0x18,0x2,0x37,0x2,0xc6,0x2,0xd8, + 0x3,0x26,0x3,0x94,0x3,0xa9,0x3,0xbc,0x3,0xc0,0x1e,0x80,0x1e,0xf2,0x20,0x11,0x20,0x13,0x20,0x18,0x20,0x1c,0x20,0x20,0x20,0x26,0x20,0x30,0x20,0x32, + 0x20,0x39,0x20,0x44,0x20,0x74,0x20,0xa3,0x20,0xa9,0x20,0xac,0x21,0x22,0x22,0x2,0x22,0xf,0x22,0x11,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60, + 0x22,0x64,0x25,0xca,0xfb,0x1,0xff,0xff,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xc1,0x0,0x0,0xfe,0x7e,0x0,0x0,0x0,0x0, + 0xfe,0x58,0xfd,0x6f,0xfd,0x5b,0xfd,0x49,0xfd,0x46,0x0,0x0,0x0,0x0,0xe1,0x31,0x0,0x0,0xe1,0x33,0x0,0x0,0x0,0x0,0xe1,0x2,0xe1,0x38,0xe1,0x4a, + 0xe1,0xd,0xe0,0xcd,0xe0,0xa4,0xe0,0xb1,0xe0,0xad,0xe0,0xa6,0xe0,0x55,0xdf,0x64,0xdf,0x5c,0x0,0x0,0xdf,0x52,0xdf,0x40,0xdf,0x34,0xdf,0x10,0xdf,0x5, + 0x0,0x0,0xdb,0xa4,0x0,0x0,0x0,0x1,0x0,0x5a,0x0,0x78,0x1,0x14,0x1,0x3c,0x2,0x3e,0x2,0x5c,0x0,0x0,0x2,0xc2,0x0,0x0,0x2,0xc6,0x2,0xc8, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0xc8,0x2,0xd2,0x0,0x0,0x2,0xd2,0x0,0x0,0x2,0xd2,0x2,0xd6,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0xc2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x2,0xba,0x0,0x0,0x2,0xba,0x0,0x0,0x0,0x1,0x1,0x29,0x1,0x2f,0x1,0x2b,0x1,0x51,0x1,0x67,0x1,0x72,0x1,0x30,0x1,0x38,0x1,0x39,0x1,0x22, + 0x1,0x69,0x1,0x27,0x1,0x41,0x1,0x2c,0x1,0x32,0x1,0x7,0x1,0x8,0x1,0x9,0x1,0xa,0x1,0xb,0x1,0xc,0x1,0xd,0x1,0xe,0x1,0xf,0x1,0x10, + 0x1,0x26,0x1,0x31,0x1,0x60,0x1,0x5b,0x1,0x5c,0x1,0x2d,0x1,0x71,0x0,0x2,0x0,0xd,0x0,0xe,0x0,0x14,0x0,0x18,0x0,0x22,0x0,0x23,0x0,0x28, + 0x0,0x2b,0x0,0x36,0x0,0x38,0x0,0x3a,0x0,0x40,0x0,0x41,0x0,0x47,0x0,0x52,0x0,0x54,0x0,0x55,0x0,0x59,0x0,0x5f,0x0,0x64,0x0,0x6f,0x0,0x70, + 0x0,0x75,0x0,0x76,0x0,0x7b,0x1,0x36,0x1,0x23,0x1,0x37,0x1,0x79,0x1,0x33,0x1,0x95,0x0,0x7f,0x0,0x8a,0x0,0x8b,0x0,0x91,0x0,0x95,0x0,0x9f, + 0x0,0xa0,0x0,0xa5,0x0,0xa8,0x0,0xb4,0x0,0xb7,0x0,0xb9,0x0,0xbf,0x0,0xc0,0x0,0xc6,0x0,0xd1,0x0,0xd3,0x0,0xd4,0x0,0xd8,0x0,0xdf,0x0,0xe4, + 0x0,0xef,0x0,0xf0,0x0,0xf5,0x0,0xf6,0x0,0xfb,0x1,0x34,0x1,0x6f,0x1,0x35,0x1,0x59,0x1,0x4e,0x1,0x2a,0x1,0x4f,0x1,0x55,0x1,0x50,0x1,0x57, + 0x1,0x70,0x1,0x76,0x1,0x93,0x1,0x74,0x1,0x1,0x1,0x44,0x1,0x62,0x1,0x43,0x1,0x75,0x1,0x97,0x1,0x78,0x1,0x6a,0x1,0x16,0x1,0x17,0x1,0x80, + 0x1,0x73,0x1,0x24,0x1,0x91,0x1,0x15,0x1,0x2,0x1,0x45,0x1,0x13,0x1,0x12,0x1,0x14,0x1,0x2e,0x0,0x7,0x0,0x3,0x0,0x5,0x0,0xb,0x0,0x6, + 0x0,0xa,0x0,0xc,0x0,0x11,0x0,0x1f,0x0,0x19,0x0,0x1c,0x0,0x1d,0x0,0x32,0x0,0x2d,0x0,0x2f,0x0,0x30,0x0,0x15,0x0,0x46,0x0,0x4c,0x0,0x48, + 0x0,0x4a,0x0,0x50,0x0,0x4b,0x1,0x64,0x0,0x4f,0x0,0x69,0x0,0x65,0x0,0x67,0x0,0x68,0x0,0x77,0x0,0x53,0x0,0xde,0x0,0x84,0x0,0x80,0x0,0x82, + 0x0,0x88,0x0,0x83,0x0,0x87,0x0,0x89,0x0,0x8e,0x0,0x9c,0x0,0x96,0x0,0x99,0x0,0x9a,0x0,0xaf,0x0,0xaa,0x0,0xac,0x0,0xad,0x0,0x92,0x0,0xc5, + 0x0,0xcb,0x0,0xc7,0x0,0xc9,0x0,0xcf,0x0,0xca,0x1,0x5a,0x0,0xce,0x0,0xe9,0x0,0xe5,0x0,0xe7,0x0,0xe8,0x0,0xf7,0x0,0xd2,0x0,0xf9,0x0,0x8, + 0x0,0x85,0x0,0x4,0x0,0x81,0x0,0x9,0x0,0x86,0x0,0xf,0x0,0x8c,0x0,0x12,0x0,0x8f,0x0,0x13,0x0,0x90,0x0,0x10,0x0,0x8d,0x0,0x16,0x0,0x93, + 0x0,0x17,0x0,0x94,0x0,0x20,0x0,0x9d,0x0,0x1a,0x0,0x97,0x0,0x1e,0x0,0x9b,0x0,0x21,0x0,0x9e,0x0,0x1b,0x0,0x98,0x0,0x25,0x0,0xa2,0x0,0x24, + 0x0,0xa1,0x0,0x27,0x0,0xa4,0x0,0x26,0x0,0xa3,0x0,0x2a,0x0,0xa7,0x0,0x29,0x0,0xa6,0x0,0x35,0x0,0xb3,0x0,0x33,0x0,0xb1,0x0,0x2e,0x0,0xab, + 0x0,0x34,0x0,0xb2,0x0,0x31,0x0,0xa9,0x0,0x2c,0x0,0xb0,0x0,0x37,0x0,0xb6,0x0,0x39,0x0,0xb8,0x0,0x3b,0x0,0xba,0x0,0x3d,0x0,0xbc,0x0,0x3c, + 0x0,0xbb,0x0,0x3e,0x0,0xbd,0x0,0x3f,0x0,0xbe,0x0,0x42,0x0,0xc1,0x0,0x44,0x0,0xc3,0x0,0x43,0x0,0xc2,0x0,0x45,0x0,0xc4,0x0,0x4e,0x0,0xcd, + 0x0,0x49,0x0,0xc8,0x0,0x4d,0x0,0xcc,0x0,0x51,0x0,0xd0,0x0,0x56,0x0,0xd5,0x0,0x58,0x0,0xd7,0x0,0x57,0x0,0xd6,0x0,0x5a,0x0,0xd9,0x0,0x5d, + 0x0,0xdc,0x0,0x5c,0x0,0xdb,0x0,0x5b,0x0,0xda,0x0,0x62,0x0,0xe2,0x0,0x61,0x0,0xe1,0x0,0x60,0x0,0xe0,0x0,0x6e,0x0,0xee,0x0,0x6b,0x0,0xeb, + 0x0,0x66,0x0,0xe6,0x0,0x6d,0x0,0xed,0x0,0x6a,0x0,0xea,0x0,0x6c,0x0,0xec,0x0,0x72,0x0,0xf2,0x0,0x78,0x0,0xf8,0x0,0x79,0x0,0x7c,0x0,0xfc, + 0x0,0x7e,0x0,0xfe,0x0,0x7d,0x0,0xfd,0x0,0x5e,0x0,0xdd,0x0,0x63,0x0,0xe3,0x1,0x92,0x1,0x83,0x1,0x82,0x1,0x94,0x1,0x99,0x1,0x98,0x1,0x9a, + 0x1,0x96,0x0,0x74,0x0,0xf4,0x0,0x71,0x0,0xf1,0x0,0x73,0x0,0xf3,0x0,0x7a,0x0,0xfa,0x1,0x40,0x1,0x3f,0x1,0x49,0x1,0x4a,0x1,0x48,0x1,0x7a, + 0x1,0x7b,0x1,0x25,0x1,0x6d,0x1,0x63,0x1,0x61,0x1,0x5d,0x0,0xff,0x1,0x0,0x0,0x0,0x0,0xa,0x0,0xd3,0xfd,0x7d,0x3,0xa0,0x6,0x55,0x0,0x3, + 0x0,0xf,0x0,0x15,0x0,0x19,0x0,0x23,0x0,0x29,0x0,0x35,0x0,0x39,0x0,0x3d,0x0,0x48,0x0,0x19,0x40,0x16,0x42,0x3e,0x3c,0x3a,0x37,0x36,0x33,0x2a, + 0x27,0x24,0x1f,0x1a,0x18,0x16,0x11,0x10,0x9,0x4,0x2,0x0,0xa,0x30,0x2b,0x1,0x21,0x11,0x21,0x5,0x15,0x33,0x15,0x23,0x15,0x21,0x35,0x23,0x35,0x33, + 0x35,0x1,0x15,0x21,0x35,0x23,0x35,0x7,0x23,0x35,0x33,0x7,0x15,0x33,0x15,0x23,0x15,0x33,0x35,0x33,0x35,0x7,0x15,0x21,0x15,0x21,0x35,0x3,0x15,0x33, + 0x35,0x33,0x15,0x23,0x35,0x23,0x11,0x21,0x11,0x1,0x11,0x21,0x11,0x7,0x23,0x35,0x33,0x5,0x15,0x33,0x7,0x15,0x21,0x35,0x23,0x37,0x33,0x35,0x3,0xa0, + 0xfd,0x33,0x2,0xcd,0xfd,0xdc,0x94,0x96,0x1,0x78,0x96,0x96,0xfe,0x88,0x1,0x78,0x96,0x4c,0x4b,0x4b,0x96,0x96,0x96,0xe2,0x96,0x4b,0xfe,0xd3,0x1,0x78, + 0xe2,0x4c,0x4b,0xe2,0x4b,0x1,0x78,0xfe,0x88,0x1,0x78,0x4b,0xe2,0xe2,0xfe,0xd3,0x9f,0x9f,0x1,0x78,0xe7,0x9e,0x49,0xfd,0x7d,0x8,0xd8,0x98,0x4a,0x54, + 0x4b,0x4b,0x54,0x4a,0xfe,0xdc,0xeb,0x4d,0x9e,0x9e,0x51,0xdb,0x4b,0x54,0x4b,0x9f,0x4b,0x88,0x96,0x4d,0xe3,0xfe,0xec,0x7f,0x34,0x6a,0xb5,0xff,0x0,0x1, + 0x0,0xfe,0x78,0xff,0x0,0x1,0x0,0xb5,0x6a,0xe9,0x4b,0x6a,0x4b,0x4b,0x6a,0x4b,0x0,0x0,0x0,0x2,0x0,0x64,0xff,0xf6,0x4,0x64,0x4,0xb9,0x0,0x1e, + 0x0,0x22,0x0,0x25,0x40,0x22,0x21,0x1,0x4,0x3,0x1,0x4a,0x0,0x4,0x0,0x1,0x0,0x4,0x1,0x62,0x0,0x3,0x3,0x16,0x4b,0x2,0x1,0x0,0x0,0xf, + 0x0,0x4c,0x14,0x2a,0x13,0x13,0x25,0x5,0x7,0x19,0x2b,0x24,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x21,0x3,0x6,0x6,0x23,0x22,0x27,0x26, + 0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x32,0x16,0x17,0x1,0x1,0x21,0x3,0x23,0x4,0x64,0x1b,0x1e,0x1a,0xe,0x14,0x1a,0x8,0x6d,0xfe,0x8,0x6d,0x8, + 0x1a,0x14,0xe,0x1a,0x1e,0x1b,0x6,0x1,0x8a,0xd,0x34,0x2f,0x2f,0x34,0xd,0x1,0x8a,0xfd,0x3e,0x1,0x8f,0xc5,0x4,0x42,0xd,0x13,0x1a,0xa,0x8,0x16, + 0x18,0x1,0x26,0xfe,0xda,0x18,0x16,0x8,0xa,0x1a,0x13,0xd,0x12,0x4,0x24,0x23,0x1e,0x1e,0x23,0xfb,0xdc,0x1,0x86,0x2,0x39,0x0,0x0,0x0,0xff,0xff, + 0x0,0x64,0xff,0xf6,0x4,0x64,0x6,0x95,0x0,0x27,0x1,0x80,0x0,0x1c,0x1,0xe,0x1,0x2,0x0,0x2,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x64,0xff,0xf6,0x4,0x64,0x6,0x6a,0x0,0x27,0x1,0x82,0x0,0x0,0x1,0xe,0x1,0x2,0x0,0x2,0x0,0x0,0x0,0x9, + 0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x64,0xff,0xf6,0x4,0x64,0x6,0x82,0x0,0x27,0x1,0x92,0x0,0x0,0x1,0xe,0x1,0x2, + 0x0,0x2,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x64,0xff,0xf6,0x4,0x64,0x6,0x61,0x0,0x22,0x0,0x2, + 0x0,0x0,0x1,0x7,0x1,0x93,0xff,0xfe,0x1,0xe,0x0,0x9,0xb1,0x2,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x64,0xff,0xf6,0x4,0x64, + 0x6,0x95,0x0,0x27,0x1,0x95,0xff,0xe4,0x1,0xe,0x1,0x2,0x0,0x2,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0x64,0xff,0xf6,0x4,0x64,0x5,0xf0,0x0,0x27,0x1,0x97,0x0,0x0,0x1,0xe,0x1,0x2,0x0,0x2,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x64,0xfe,0x28,0x4,0x8c,0x4,0xb9,0x0,0x34,0x0,0x38,0x0,0x6d,0xb5,0x37,0x1,0x7,0x4,0x1,0x4a,0x4b,0xb0,0x1b, + 0x50,0x58,0x40,0x23,0x0,0x1,0x2,0x3,0x2,0x1,0x3,0x70,0x0,0x7,0x0,0x2,0x1,0x7,0x2,0x62,0x6,0x1,0x5,0x0,0x0,0x5,0x0,0x60,0x0,0x4, + 0x4,0x16,0x4b,0x0,0x3,0x3,0xf,0x3,0x4c,0x1b,0x40,0x2a,0x0,0x1,0x2,0x3,0x2,0x1,0x3,0x70,0x0,0x6,0x3,0x5,0x3,0x6,0x5,0x70,0x0,0x7, + 0x0,0x2,0x1,0x7,0x2,0x62,0x0,0x5,0x0,0x0,0x5,0x0,0x60,0x0,0x4,0x4,0x16,0x4b,0x0,0x3,0x3,0xf,0x3,0x4c,0x59,0x40,0xb,0x12,0x31,0x2d, + 0x2a,0x13,0x12,0x15,0x25,0x8,0x7,0x1c,0x2b,0x0,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x33,0x27,0x3,0x21,0x3,0x6,0x6,0x23, + 0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x32,0x16,0x17,0x1,0x16,0x15,0x14,0x7,0x33,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33, + 0x32,0x17,0x1,0x21,0x3,0x23,0x4,0x8c,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x61,0x5b,0x16,0x3,0x6d,0xfe,0x8,0x6d,0x8,0x1a,0x14,0xe,0x1a,0x1e,0x1b,0x6, + 0x1,0x8a,0xd,0x34,0x2f,0x2f,0x34,0xd,0x1,0x8a,0x7,0x8,0x2,0x6a,0x5b,0x2a,0x23,0x34,0x3d,0x8,0x3,0x1e,0x9,0xfd,0x12,0x1,0x8f,0xc5,0x4,0xfe, + 0x7e,0x7,0x16,0x19,0x6,0x1a,0x68,0x57,0x51,0x96,0x4e,0x8,0x1,0x26,0xfe,0xda,0x18,0x16,0x8,0xa,0x1a,0x13,0xd,0x12,0x4,0x24,0x23,0x1e,0x1e,0x23, + 0xfb,0xdc,0x15,0xa,0xe,0xb,0x5e,0x86,0x3c,0x23,0x26,0x11,0x2,0x36,0x3,0x4a,0x2,0x39,0xff,0xff,0x0,0x64,0xff,0xf6,0x4,0x64,0x7,0x5,0x0,0x27, + 0x1,0x99,0x0,0x0,0x0,0xf0,0x1,0x2,0x0,0x2,0x0,0x0,0x0,0x8,0xb1,0x0,0x2,0xb0,0xf0,0xb0,0x33,0x2b,0x0,0x0,0xff,0xff,0x0,0x64,0xff,0xf6, + 0x4,0x64,0x6,0x3b,0x0,0x27,0x1,0x9a,0x0,0x0,0x1,0xe,0x1,0x2,0x0,0x2,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0x0,0x2,0x0,0x14,0xff,0xf6,0x4,0x92,0x4,0xa3,0x0,0x30,0x0,0x34,0x0,0x7c,0x4b,0xb0,0x31,0x50,0x58,0x40,0x29,0x0,0x5,0x0,0x6,0x9,0x5,0x6, + 0x61,0xb,0x1,0x9,0x0,0x1,0x7,0x9,0x1,0x61,0x8,0x1,0x4,0x4,0x3,0x59,0x0,0x3,0x3,0xe,0x4b,0xa,0x1,0x7,0x7,0x0,0x5b,0x2,0x1,0x0, + 0x0,0xf,0x0,0x4c,0x1b,0x40,0x2d,0x0,0x5,0x0,0x6,0x9,0x5,0x6,0x61,0xb,0x1,0x9,0x0,0x1,0x7,0x9,0x1,0x61,0x8,0x1,0x4,0x4,0x3,0x59, + 0x0,0x3,0x3,0xe,0x4b,0xa,0x1,0x7,0x7,0x0,0x59,0x0,0x0,0x0,0xf,0x4b,0x0,0x2,0x2,0xf,0x2,0x4c,0x59,0x40,0x18,0x31,0x31,0x0,0x0,0x31, + 0x34,0x31,0x34,0x33,0x32,0x0,0x30,0x0,0x2f,0x24,0x21,0x24,0x5a,0x13,0x13,0x44,0xc,0x7,0x1b,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26, + 0x35,0x11,0x21,0x3,0x6,0x6,0x23,0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x3b,0x2,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x32, + 0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x1,0x11,0x23,0x3,0x4,0x75,0x1d,0x1d,0x22,0xfe,0x54,0x29,0x22,0x1d,0xfe,0xee,0x82,0x9,0x1a,0x14,0xe,0x1a, + 0x1d,0x1b,0x7,0x1,0x93,0xe,0x29,0x22,0x69,0x65,0x1,0x6a,0x22,0x1d,0x1d,0x22,0xfe,0x96,0x1,0x3d,0x22,0x1d,0x1d,0x22,0xfe,0xc3,0x1,0x7e,0xfd,0xec, + 0x19,0xc3,0x90,0x21,0x27,0x27,0x21,0x1f,0x25,0x1,0x2e,0xfe,0xb2,0x18,0x16,0x8,0x9,0x1a,0x13,0xf,0x11,0x4,0xb,0x25,0x1f,0x21,0x27,0x27,0x21,0xfe, + 0x99,0x21,0x27,0x27,0x21,0xfe,0x74,0x1,0x72,0x2,0x11,0xfd,0xef,0x0,0x0,0x3,0x0,0xcd,0x0,0x0,0x4,0x32,0x4,0xa3,0x0,0x16,0x0,0x1e,0x0,0x27, + 0x0,0x43,0x40,0x40,0x6,0x1,0x5,0x2,0x1,0x4a,0x0,0x2,0x8,0x1,0x5,0x4,0x2,0x5,0x61,0x7,0x1,0x3,0x3,0x1,0x59,0x6,0x1,0x1,0x1,0xe, + 0x4b,0x0,0x4,0x4,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x1f,0x1f,0x17,0x17,0x0,0x0,0x1f,0x27,0x1f,0x26,0x22,0x20,0x17,0x1e,0x17,0x1d,0x1a,0x18, + 0x0,0x16,0x0,0x14,0x3c,0x9,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36, + 0x33,0x21,0x5,0x11,0x21,0x32,0x36,0x35,0x34,0x23,0x1,0x11,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x2,0xf9,0xa4,0x53,0x46,0x40,0x60,0x68,0x5a,0xac,0x7a, + 0xfe,0x5a,0x22,0x1d,0x1d,0x22,0x1,0x78,0xfe,0xdf,0x1,0xb,0x73,0x75,0xe8,0xfe,0xf5,0x1,0x3b,0x77,0x83,0x81,0x7e,0x4,0xa3,0x53,0x94,0x62,0x4f,0x77, + 0x25,0x24,0x91,0x6a,0x69,0x97,0x50,0x1f,0x25,0x4,0x1b,0x25,0x1f,0x90,0xfe,0x90,0x5f,0x58,0xb9,0xfe,0x0,0xfe,0x7d,0x61,0x5f,0x62,0x61,0x0,0x0,0x0, + 0x0,0x1,0x0,0x96,0xff,0xea,0x4,0x32,0x4,0xb9,0x0,0x29,0x0,0x3c,0x40,0x39,0x4,0x1,0x0,0x1,0x1,0x4a,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70, + 0x0,0x3,0x2,0x1,0x3,0x2,0x6e,0x0,0x1,0x1,0x5,0x5b,0x6,0x1,0x5,0x5,0x16,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x0, + 0x0,0x0,0x29,0x0,0x28,0x27,0x22,0x26,0x23,0x17,0x7,0x7,0x19,0x2b,0x0,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6, + 0x15,0x14,0x16,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x2,0x35,0x34,0x12,0x36,0x33,0x2,0xfc,0xb6,0x5b, + 0x25,0xd,0x15,0x20,0xe,0x14,0x97,0x9f,0x6c,0xa3,0x59,0x59,0xa3,0x6c,0x9f,0x97,0x14,0xe,0x20,0x15,0xd,0x25,0x5b,0xb6,0x64,0x99,0xe9,0x80,0x80,0xe9, + 0x99,0x4,0xb9,0x31,0x34,0x16,0x22,0x13,0x1d,0x2c,0xb,0x5a,0x72,0xd3,0x8e,0x8e,0xd4,0x72,0x5a,0xb,0x2c,0x1d,0x13,0x22,0x16,0x34,0x31,0x99,0x1,0x18, + 0xb7,0xb7,0x1,0x17,0x99,0x0,0x0,0x0,0xff,0xff,0x0,0x96,0xff,0xea,0x4,0x32,0x6,0x95,0x0,0x27,0x1,0x80,0x0,0x1c,0x1,0xe,0x1,0x2,0x0,0xe, + 0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x96,0xff,0xea,0x4,0x32,0x6,0x84,0x0,0x22,0x0,0xe,0x0,0x0, + 0x1,0x7,0x1,0x83,0x0,0x32,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x96,0xfe,0x28,0x4,0x32,0x4,0xb9, + 0x0,0x48,0x0,0x9e,0x40,0xf,0x36,0x1,0x7,0x8,0x29,0x9,0x2,0x1,0x9,0x15,0x1,0x2,0x4,0x3,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0x38,0x0,0x7, + 0x8,0x0,0x8,0x7,0x0,0x70,0x0,0x0,0x9,0x8,0x0,0x9,0x6e,0x0,0x1,0x9,0x5,0x4,0x1,0x68,0x0,0x3,0x5,0x4,0x5,0x3,0x4,0x70,0x0,0x9, + 0x0,0x5,0x3,0x9,0x5,0x63,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0x16,0x8,0x4c,0x1b,0x40,0x39,0x0,0x7,0x8, + 0x0,0x8,0x7,0x0,0x70,0x0,0x0,0x9,0x8,0x0,0x9,0x6e,0x0,0x1,0x9,0x5,0x9,0x1,0x5,0x70,0x0,0x3,0x5,0x4,0x5,0x3,0x4,0x70,0x0,0x9, + 0x0,0x5,0x3,0x9,0x5,0x63,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0x16,0x8,0x4c,0x59,0x40,0xe,0x47,0x45,0x23, + 0x17,0x2b,0x24,0x24,0x17,0x24,0x18,0x20,0xa,0x7,0x1d,0x2b,0x24,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x7,0x15,0x36,0x16,0x15,0x14,0x6,0x23,0x22, + 0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x26,0x26,0x2,0x35,0x34,0x12, + 0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x37,0x3,0xe2,0xe,0x20,0x15, + 0xd,0x25,0x9c,0xa8,0x65,0x66,0x7c,0x79,0x44,0x80,0x33,0x17,0x8,0x11,0x1d,0x8,0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36,0x3e,0x27,0xf,0x13,0x82,0xc3,0x6a, + 0x80,0xe9,0x99,0x64,0xb6,0x5b,0x25,0xd,0x15,0x20,0xe,0x14,0x97,0x9f,0x6c,0xa3,0x59,0x59,0xa3,0x6c,0x9f,0x97,0xe3,0x2c,0x1d,0x13,0x22,0x16,0x58,0xc, + 0x5c,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19,0xe,0x15,0x2d,0x2,0x10,0x16,0x21,0x1f,0x21,0x20,0x1,0x15,0x17,0xa1,0x14,0xa2,0x1,0x6,0xa6,0xb7, + 0x1,0x17,0x99,0x31,0x34,0x16,0x22,0x13,0x1d,0x2c,0xb,0x5a,0x72,0xd3,0x8e,0x8e,0xd4,0x72,0x5a,0x0,0xff,0xff,0x0,0x96,0xff,0xea,0x4,0x32,0x6,0x82, + 0x0,0x27,0x1,0x92,0x0,0x3c,0x1,0xe,0x1,0x2,0x0,0xe,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x96, + 0xff,0xea,0x4,0x32,0x6,0x61,0x0,0x27,0x1,0x94,0x0,0x32,0x1,0xe,0x1,0x2,0x0,0xe,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33, + 0x2b,0x0,0x0,0x2,0x0,0xaf,0x0,0x0,0x4,0x4c,0x4,0xa3,0x0,0x10,0x0,0x1b,0x0,0x2c,0x40,0x29,0x5,0x1,0x3,0x3,0x1,0x59,0x4,0x1,0x1,0x1, + 0xe,0x4b,0x0,0x2,0x2,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x11,0x11,0x0,0x0,0x11,0x1b,0x11,0x1a,0x14,0x12,0x0,0x10,0x0,0xe,0x36,0x6,0x7, + 0x15,0x2b,0x0,0x16,0x12,0x15,0x14,0x2,0x6,0x23,0x21,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x21,0x7,0x11,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23, + 0x2,0xdb,0xee,0x83,0x83,0xee,0x9d,0xfe,0xb0,0x22,0x1d,0x1d,0x22,0x1,0x50,0xf9,0xe6,0x78,0xaf,0x60,0x60,0xaf,0x78,0x4,0xa3,0x8f,0xfe,0xf3,0xb6,0xb6, + 0xfe,0xf4,0x8f,0x1f,0x25,0x4,0x1b,0x25,0x1f,0x90,0xfc,0x7d,0x65,0xca,0x92,0x92,0xca,0x66,0x0,0x2,0x0,0x32,0x0,0x0,0x4,0x60,0x4,0xa3,0x0,0x19, + 0x0,0x2d,0x0,0x3c,0x40,0x39,0x5,0x1,0x2,0x6,0x1,0x1,0x7,0x2,0x1,0x63,0x0,0x4,0x4,0x3,0x59,0x8,0x1,0x3,0x3,0xe,0x4b,0x9,0x1,0x7, + 0x7,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x1a,0x1a,0x0,0x0,0x1a,0x2d,0x1a,0x2c,0x2b,0x29,0x25,0x23,0x22,0x20,0x0,0x19,0x0,0x17,0x24,0x23,0x36, + 0xa,0x7,0x17,0x2b,0x0,0x16,0x12,0x15,0x14,0x2,0x6,0x23,0x21,0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x11,0x34,0x36,0x33,0x21, + 0x12,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x23,0x11,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x33,0x2,0xef,0xee,0x83,0x83,0xee,0x9d,0xfe,0xce,0x22, + 0x1d,0x70,0x22,0x1d,0x1d,0x22,0x70,0x1d,0x22,0x1,0x32,0x65,0xaf,0x60,0x60,0xaf,0x78,0xc8,0xdc,0x22,0x1d,0x1d,0x22,0xdc,0xc8,0x4,0xa3,0x8f,0xfe,0xf3, + 0xb6,0xb6,0xfe,0xf4,0x8f,0x1f,0x25,0x1,0xd8,0x21,0x27,0x27,0x21,0x1,0xb3,0x25,0x1f,0xfb,0xed,0x65,0xca,0x92,0x92,0xca,0x66,0xfe,0x99,0x21,0x27,0x27, + 0x21,0xfe,0x74,0x0,0xff,0xff,0x0,0xaf,0x0,0x0,0x4,0x4c,0x6,0x84,0x0,0x22,0x0,0x14,0x0,0x0,0x1,0x7,0x1,0x83,0xff,0xe2,0x1,0xe,0x0,0x9, + 0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaf,0x0,0x0,0x4,0x4c,0x5,0xf0,0x0,0x22,0x0,0x14,0x0,0x0,0x1,0x7,0x1,0x97, + 0xff,0xe2,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xe1,0x0,0x0,0x4,0x10,0x4,0xa3,0x0,0x22,0x0,0x2f, + 0x40,0x2c,0x0,0x3,0x0,0x4,0x5,0x3,0x4,0x61,0x0,0x2,0x2,0x1,0x59,0x0,0x1,0x1,0xe,0x4b,0x6,0x1,0x5,0x5,0x0,0x59,0x0,0x0,0x0,0xf, + 0x0,0x4c,0x0,0x0,0x0,0x22,0x0,0x21,0x24,0x21,0x24,0x45,0x44,0x7,0x7,0x19,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26,0x35,0x11,0x34, + 0x36,0x33,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x3,0xf3,0x1d,0x1d,0x22,0xfd,0x78,0x29, + 0x22,0x1d,0x1d,0x22,0x57,0x2,0x46,0x22,0x1d,0x1d,0x22,0xfd,0xba,0x1,0xc9,0x22,0x1d,0x1d,0x22,0xfe,0x37,0x2,0x5a,0x90,0x21,0x27,0x27,0x21,0x1f,0x25, + 0x4,0x1b,0x25,0x1f,0x21,0x27,0x27,0x21,0xfe,0x99,0x21,0x27,0x27,0x21,0xfe,0x74,0x0,0x0,0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x6,0x95,0x0,0x22, + 0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x80,0xff,0xe0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xe1,0x0,0x0, + 0x4,0x10,0x6,0x6a,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0xa,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x6,0x84,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0xa,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x6,0x82,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x1e,0x1,0xe, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x6,0x61,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7, + 0x1,0x93,0x0,0x14,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x6,0x61,0x0,0x27, + 0x1,0x94,0x0,0x14,0x1,0xe,0x1,0x2,0x0,0x18,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xe1,0x0,0x0, + 0x4,0x10,0x6,0x95,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x95,0x0,0x20,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x5,0xf0,0x0,0x27,0x1,0x97,0x0,0xa,0x1,0xe,0x1,0x2,0x0,0x18,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xe1,0xfe,0x28,0x4,0x19,0x4,0xa3,0x0,0x3c,0x0,0x6f,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x26,0x0,0x4,0x0, + 0x5,0x6,0x4,0x5,0x61,0x9,0x1,0x8,0x0,0x0,0x8,0x0,0x5f,0x0,0x3,0x3,0x2,0x59,0x0,0x2,0x2,0xe,0x4b,0x0,0x6,0x6,0x1,0x5b,0x7,0x1, + 0x1,0x1,0xf,0x1,0x4c,0x1b,0x40,0x2d,0x0,0x9,0x1,0x8,0x1,0x9,0x8,0x70,0x0,0x4,0x0,0x5,0x6,0x4,0x5,0x61,0x0,0x8,0x0,0x0,0x8,0x0, + 0x5f,0x0,0x3,0x3,0x2,0x59,0x0,0x2,0x2,0xe,0x4b,0x0,0x6,0x6,0x1,0x5b,0x7,0x1,0x1,0x1,0xf,0x1,0x4c,0x59,0x40,0xe,0x3b,0x38,0x26,0x14, + 0x21,0x24,0x21,0x24,0x45,0x35,0x25,0xa,0x7,0x1d,0x2b,0x0,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x21,0x23,0x22,0x26,0x35,0x11, + 0x34,0x36,0x33,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x23, + 0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x4,0x19,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x50,0x4c,0xfe,0x22,0x29,0x22,0x1d,0x1d,0x22,0x57, + 0x2,0x46,0x22,0x1d,0x1d,0x22,0xfd,0xba,0x1,0xc9,0x22,0x1d,0x1d,0x22,0xfe,0x37,0x2,0x5a,0x22,0x1d,0x1d,0x22,0x4,0x59,0x4d,0x2a,0x23,0x34,0x3d,0x8, + 0x3,0x1e,0x9,0xfe,0x7e,0x7,0x16,0x19,0x6,0x1a,0x68,0x57,0x49,0x8a,0x46,0x1f,0x25,0x4,0x1b,0x25,0x1f,0x21,0x27,0x27,0x21,0xfe,0x99,0x21,0x27,0x27, + 0x21,0xfe,0x74,0x21,0x27,0x27,0x21,0x53,0x7a,0x37,0x23,0x26,0x11,0x2,0x36,0x0,0x0,0x1,0x0,0xf5,0xff,0xf6,0x4,0x10,0x4,0xa3,0x0,0x1d,0x0,0x29, + 0x40,0x26,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x0,0x0,0x0,0x4,0x59,0x5,0x1,0x4,0x4,0xe,0x4b,0x0,0x3,0x3,0xf,0x3,0x4c,0x0,0x0,0x0, + 0x1d,0x0,0x1a,0x33,0x24,0x21,0x24,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x6, + 0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x21,0x3,0xf3,0x1d,0x1d,0x22,0xfd,0xba,0x1,0xd3,0x22,0x1d,0x1d,0x22,0xfe,0x2d,0x21,0x29,0x2,0x29, + 0x21,0x1f,0x20,0x57,0x2,0x46,0x4,0xa3,0x21,0x27,0x27,0x21,0xfe,0x71,0x21,0x27,0x27,0x21,0xfe,0x43,0x23,0x1e,0x1e,0x23,0x4,0x28,0x25,0x1f,0x0,0x1, + 0x0,0x6e,0xff,0xea,0x4,0x3b,0x4,0xb9,0x0,0x31,0x0,0x43,0x40,0x40,0x27,0x1,0x4,0x5,0x1,0x4a,0x15,0x1,0x3,0x1,0x49,0x0,0x2,0x3,0x6,0x3, + 0x2,0x6,0x70,0x7,0x1,0x6,0x0,0x5,0x4,0x6,0x5,0x61,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x16,0x4b,0x0,0x4,0x4,0x0,0x5b,0x0,0x0,0x0, + 0x17,0x0,0x4c,0x0,0x0,0x0,0x31,0x0,0x2e,0x22,0x26,0x23,0x17,0x26,0x27,0x8,0x7,0x1a,0x2b,0x0,0x16,0x15,0x11,0x14,0x7,0x6,0x6,0x23,0x22,0x26, + 0x2,0x35,0x34,0x12,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x37,0x11, + 0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x33,0x4,0x1e,0x1d,0x24,0x52,0xd6,0x75,0x9c,0xee,0x82,0x89,0xf3,0x9a,0x67,0xb3,0x59,0x26,0xb,0x14,0x21,0x10, + 0x12,0x8e,0xa9,0x6d,0xac,0x63,0x5c,0xa8,0x6e,0xaf,0x7c,0xfe,0xf5,0x22,0x1d,0x1d,0x22,0x1,0x46,0x1c,0x2,0x52,0x1f,0x25,0xfe,0x81,0x31,0x14,0x2f,0x31, + 0x99,0x1,0x18,0xb7,0xb6,0x1,0x17,0x9a,0x2b,0x30,0x15,0x24,0x13,0x1b,0x2d,0xa,0x51,0x72,0xd4,0x8d,0x8e,0xd4,0x72,0x39,0x1,0xb,0x21,0x27,0x27,0x21, + 0xff,0xff,0x0,0x6e,0xff,0xea,0x4,0x3b,0x6,0x6a,0x0,0x22,0x0,0x23,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x6e,0xff,0xea,0x4,0x3b,0x6,0x82,0x0,0x27,0x1,0x92,0x0,0x28,0x1,0xe,0x1,0x2,0x0,0x23,0x0,0x0, + 0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x6e,0xfd,0xf2,0x4,0x3b,0x4,0xb9,0x0,0x22,0x0,0x23,0x0,0x0,0x0,0x3, + 0x1,0x7e,0x4,0xdc,0x0,0x0,0xff,0xff,0x0,0x6e,0xff,0xea,0x4,0x3b,0x6,0x61,0x0,0x27,0x1,0x94,0x0,0x1e,0x1,0xe,0x1,0x2,0x0,0x23,0x0,0x0, + 0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xaf,0xff,0xf6,0x4,0x1d,0x4,0xad,0x0,0x23,0x0,0x27,0x40,0x24,0x0,0x4, + 0x0,0x1,0x0,0x4,0x1,0x61,0x6,0x5,0x2,0x3,0x3,0xe,0x4b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x23,0x0,0x21,0x13,0x35,0x33,0x13, + 0x35,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x21,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33, + 0x33,0x32,0x16,0x15,0x11,0x21,0x11,0x34,0x36,0x33,0x33,0x3,0xfc,0x21,0x21,0x29,0x2,0x29,0x21,0xfd,0xbe,0x21,0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x29, + 0x21,0x2,0x42,0x21,0x29,0x2,0x4,0xad,0x1e,0x23,0xfb,0xcb,0x23,0x1e,0x1e,0x23,0x1,0xe5,0xfe,0x1b,0x23,0x1e,0x1e,0x23,0x4,0x35,0x23,0x1e,0x1e,0x23, + 0xfe,0x40,0x1,0xc0,0x23,0x1e,0x0,0x2,0x0,0x1e,0xff,0xf6,0x4,0xae,0x4,0xad,0x0,0x35,0x0,0x39,0x0,0x6a,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x0, + 0xb,0x0,0x2,0x1,0xb,0x2,0x61,0x8,0x1,0x6,0x6,0xe,0x4b,0xa,0x4,0x2,0x0,0x0,0x5,0x5b,0xc,0x9,0x7,0x3,0x5,0x5,0x19,0x4b,0x3,0x1, + 0x1,0x1,0xf,0x1,0x4c,0x1b,0x40,0x22,0xc,0x9,0x7,0x3,0x5,0xa,0x4,0x2,0x0,0xb,0x5,0x0,0x63,0x0,0xb,0x0,0x2,0x1,0xb,0x2,0x61,0x8, + 0x1,0x6,0x6,0xe,0x4b,0x3,0x1,0x1,0x1,0xf,0x1,0x4c,0x59,0x40,0x16,0x0,0x0,0x39,0x38,0x37,0x36,0x0,0x35,0x0,0x34,0x33,0x13,0x33,0x24,0x23, + 0x33,0x13,0x33,0x24,0xd,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x21,0x11,0x14,0x6,0x23,0x23, + 0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x21,0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x15, + 0x15,0x33,0x7,0x21,0x15,0x21,0x4,0x91,0x1d,0x1d,0x22,0x52,0x21,0x29,0x2,0x29,0x21,0xfd,0xbe,0x21,0x29,0x2,0x29,0x21,0x52,0x22,0x1d,0x1d,0x22,0x52, + 0x21,0x29,0x2,0x29,0x21,0x2,0x42,0x21,0x29,0x2,0x29,0x21,0x52,0xe8,0xfd,0xbe,0x2,0x42,0x3,0xce,0x21,0x27,0x27,0x21,0xfc,0xf9,0x23,0x1e,0x1e,0x23, + 0x1,0xe5,0xfe,0x1b,0x23,0x1e,0x1e,0x23,0x3,0x7,0x21,0x27,0x27,0x21,0x9e,0x23,0x1e,0x1e,0x23,0x9e,0x9e,0x23,0x1e,0x1e,0x23,0x9e,0x90,0x92,0x0,0x0, + 0xff,0xff,0x0,0xaf,0xff,0xf6,0x4,0x1d,0x6,0x82,0x0,0x22,0x0,0x28,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xc8,0x0,0x0,0x4,0x4,0x4,0xa3,0x0,0x1f,0x0,0x29,0x40,0x26,0x4,0x1,0x2,0x2,0x3,0x59,0x0,0x3, + 0x3,0xe,0x4b,0x6,0x5,0x2,0x1,0x1,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x1f,0x0,0x1e,0x24,0x34,0x21,0x24,0x34,0x7,0x7,0x19, + 0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23, + 0x21,0x11,0x21,0x3,0xe7,0x1d,0x1d,0x22,0xfd,0x42,0x22,0x1d,0x1d,0x22,0x1,0x14,0xff,0x0,0x22,0x1d,0x1d,0x22,0x2,0x96,0x22,0x1d,0x1d,0x22,0xff,0x0, + 0x1,0x14,0x90,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x3,0x83,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0xfc,0x7d,0x0,0x0,0x0,0x0,0x2,0x0,0xb3, + 0xff,0xea,0x4,0x1e,0x4,0xad,0x0,0xf,0x0,0x2c,0x0,0x67,0xb5,0x1b,0x1,0x0,0x4,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1c,0x0,0x3,0x1,0x4, + 0x1,0x3,0x4,0x70,0x7,0x5,0x6,0x3,0x1,0x1,0xe,0x4b,0x0,0x4,0x4,0x0,0x5b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40,0x20,0x0,0x3,0x1, + 0x4,0x1,0x3,0x4,0x70,0x7,0x5,0x6,0x3,0x1,0x1,0xe,0x4b,0x0,0x0,0x0,0xf,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x59, + 0x40,0x16,0x10,0x10,0x0,0x0,0x10,0x2c,0x10,0x2a,0x25,0x23,0x1f,0x1e,0x17,0x15,0x0,0xf,0x0,0xd,0x35,0x8,0x7,0x15,0x2b,0x0,0x16,0x15,0x11,0x14, + 0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x20,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16, + 0x16,0x33,0x32,0x36,0x35,0x11,0x34,0x36,0x33,0x33,0x1,0x28,0x21,0x21,0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x2,0xfe,0x21,0x8d,0x84,0x37,0x80,0x30,0x27, + 0xb,0x15,0x24,0xc,0x10,0x27,0x5c,0x2c,0x3f,0x3b,0x21,0x29,0x2,0x4,0xad,0x1e,0x23,0xfb,0xcb,0x23,0x1e,0x1e,0x23,0x4,0x35,0x23,0x1e,0x1e,0x23,0xfc, + 0x91,0x86,0x8d,0x1a,0x18,0x14,0x21,0x11,0x1b,0x31,0x7,0x13,0x16,0x4a,0x53,0x3,0x51,0x23,0x1e,0x0,0x0,0x0,0xff,0xff,0x0,0xc8,0x0,0x0,0x4,0x4, + 0x6,0x95,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0xc8,0x0,0x0,0x4,0x4,0x6,0x6a,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xc8,0x0,0x0,0x4,0x4,0x6,0x82,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x0,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xc8,0x0,0x0,0x4,0x4,0x6,0x61,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x93, + 0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xc8,0x0,0x0,0x4,0x4,0x6,0x61,0x0,0x22,0x0,0x2b, + 0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xc8,0x0,0x0,0x4,0x4, + 0x6,0x95,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x95,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0xc8,0x0,0x0,0x4,0x4,0x5,0xf0,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xc8,0xfe,0x28,0x4,0x4,0x4,0xa3,0x0,0x39,0x0,0x69,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x21,0x2,0x1,0x1,0x0,0x3, + 0x1,0x3,0x5f,0x8,0x1,0x6,0x6,0x7,0x59,0x0,0x7,0x7,0xe,0x4b,0xa,0x9,0x2,0x5,0x5,0x0,0x59,0x4,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40, + 0x28,0x0,0x2,0x0,0x1,0x0,0x2,0x1,0x70,0x0,0x1,0x0,0x3,0x1,0x3,0x5f,0x8,0x1,0x6,0x6,0x7,0x59,0x0,0x7,0x7,0xe,0x4b,0xa,0x9,0x2, + 0x5,0x5,0x0,0x59,0x4,0x1,0x0,0x0,0xf,0x0,0x4c,0x59,0x40,0x12,0x0,0x0,0x0,0x39,0x0,0x38,0x24,0x34,0x21,0x24,0x25,0x27,0x31,0x25,0x24,0xb, + 0x7,0x1d,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22, + 0x26,0x35,0x34,0x36,0x37,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11, + 0x21,0x3,0xe7,0x1d,0x1d,0x22,0xfe,0xf0,0x59,0x4d,0x2a,0x23,0x34,0x3d,0x8,0x3,0x1e,0x9,0x2,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x50,0x4c,0xfe,0xf8,0x22, + 0x1d,0x1d,0x22,0x1,0x14,0xff,0x0,0x22,0x1d,0x1d,0x22,0x2,0x96,0x22,0x1d,0x1d,0x22,0xff,0x0,0x1,0x14,0x90,0x21,0x27,0x27,0x21,0x53,0x7a,0x37,0x23, + 0x26,0x11,0x2,0x36,0x12,0x7,0x16,0x19,0x6,0x1a,0x68,0x57,0x49,0x8a,0x46,0x21,0x27,0x27,0x21,0x3,0x83,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0xfc, + 0x7d,0x0,0xff,0xff,0x0,0xc8,0x0,0x0,0x4,0x4,0x6,0x3b,0x0,0x27,0x1,0x9a,0x0,0x0,0x1,0xe,0x1,0x2,0x0,0x2b,0x0,0x0,0x0,0x9,0xb1,0x0, + 0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xb8,0xff,0xea,0x3,0xba,0x4,0xa3,0x0,0x20,0x0,0x2e,0x40,0x2b,0x0,0x1,0x3,0x2,0x3,0x1, + 0x2,0x70,0x0,0x3,0x3,0x4,0x59,0x5,0x1,0x4,0x4,0xe,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x20,0x0,0x1d, + 0x22,0x24,0x17,0x25,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32, + 0x35,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x33,0x3,0x9b,0x1f,0xc3,0xb2,0x65,0xbf,0x4b,0x1e,0x12,0x1a,0x1e,0x11,0x13,0x3e,0x94,0x4e,0xde,0xfe, + 0x97,0x22,0x1d,0x1d,0x22,0x1,0xa2,0x1e,0x4,0xa3,0x1f,0x25,0xfc,0xee,0xab,0xb8,0x3b,0x37,0x17,0x1d,0x17,0x1e,0x27,0xe,0x2f,0x31,0xed,0x2,0xa8,0x21, + 0x27,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x45,0x6,0x82,0x0,0x27,0x1,0x92,0x0,0xa0,0x1,0xe,0x1,0x2,0x0,0x36,0x0,0x0, + 0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xd7,0xff,0xed,0x4,0x47,0x4,0xb8,0x0,0x25,0x0,0x3d,0x40,0x9,0x24,0x1a, + 0x9,0x8,0x4,0x0,0x2,0x1,0x4a,0x4b,0xb0,0x2d,0x50,0x58,0x40,0xd,0x3,0x1,0x2,0x2,0xe,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x11, + 0x0,0x3,0x3,0x16,0x4b,0x0,0x2,0x2,0xe,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x59,0xb6,0x25,0x35,0x36,0x24,0x4,0x7,0x18,0x2b,0x24,0x15,0x14, + 0x7,0x6,0x23,0x22,0x27,0x1,0x7,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x1,0x36,0x33,0x32,0x17,0x16, + 0x15,0x14,0x7,0x1,0x1,0x4,0x47,0x2b,0x21,0x16,0x19,0x13,0xfe,0x62,0xae,0x21,0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x29,0x21,0x2,0x3b,0x10,0x18,0x1c, + 0x20,0x27,0x16,0xfe,0x67,0x1,0xb2,0x45,0x11,0x1c,0x18,0x13,0x19,0x2,0x20,0xb8,0xfe,0xc9,0x23,0x1e,0x1e,0x23,0x4,0x35,0x23,0x1e,0x1e,0x23,0xfd,0xdc, + 0x2,0x5f,0x11,0x15,0x19,0x1a,0x14,0x16,0xfe,0x4f,0xfd,0xc7,0xff,0xff,0x0,0xd7,0xfd,0xf2,0x4,0x47,0x4,0xb8,0x0,0x22,0x0,0x38,0x0,0x0,0x0,0x3, + 0x1,0x7e,0x4,0xc8,0x0,0x0,0x0,0x1,0x0,0xf5,0x0,0x0,0x4,0x10,0x4,0xad,0x0,0x14,0x0,0x1f,0x40,0x1c,0x0,0x1,0x1,0xe,0x4b,0x3,0x1,0x2, + 0x2,0x0,0x5a,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x14,0x0,0x13,0x35,0x44,0x4,0x7,0x16,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22, + 0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x21,0x3,0xf3,0x1d,0x1d,0x22,0xfd,0x8c,0x29,0x23,0x1c,0x21,0x29,0x2,0x29,0x21,0x2,0x46,0x90, + 0x21,0x27,0x27,0x21,0x1f,0x25,0x4,0x28,0x23,0x1e,0x1e,0x23,0xfc,0x24,0x0,0x0,0xff,0xff,0x0,0xe1,0x0,0x0,0x4,0x10,0x6,0x95,0x0,0x27,0x1,0x80, + 0xff,0x40,0x1,0xe,0x1,0x2,0x0,0x3a,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xf5,0x0,0x0,0x4,0x10, + 0x4,0xad,0x0,0x22,0x0,0x3a,0x0,0x0,0x1,0x7,0x1,0x81,0x1,0xcc,0xff,0x83,0x0,0x9,0xb1,0x1,0x1,0xb8,0xff,0x83,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0xf5,0xfd,0xf2,0x4,0x10,0x4,0xad,0x0,0x22,0x0,0x3a,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xc8,0x0,0x0,0xff,0xff,0x0,0xf5,0x0,0x0,0x4,0x10, + 0x4,0xad,0x0,0x22,0x0,0x3a,0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x82,0xfe,0x2,0x0,0x9,0xb1,0x1,0x1,0xb8,0xfe,0x2,0xb0,0x33,0x2b,0x0,0x0,0x1, + 0x0,0x3c,0x0,0x0,0x4,0x10,0x4,0xad,0x0,0x2a,0x0,0x39,0x40,0x36,0x28,0x1e,0x15,0xb,0x4,0x1,0x3,0x1,0x4a,0x0,0x3,0x2,0x1,0x2,0x3,0x1, + 0x70,0x0,0x1,0x4,0x2,0x1,0x4,0x6e,0x0,0x2,0x2,0xe,0x4b,0x5,0x1,0x4,0x4,0x0,0x5a,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x2a,0x0, + 0x29,0x25,0x39,0x25,0x44,0x6,0x7,0x18,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26,0x35,0x11,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37, + 0x37,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x5,0x11,0x21,0x3,0xf3,0x1d,0x1d,0x22,0xfd,0xc8,0x29, + 0x23,0x1c,0x88,0x18,0x10,0x1a,0x19,0x12,0x20,0xd5,0x21,0x29,0x2,0x29,0x21,0xce,0x18,0x10,0x1a,0x19,0x12,0x20,0xfe,0xe5,0x2,0xa,0x90,0x21,0x27,0x27, + 0x21,0x1f,0x25,0x1,0x7c,0x5c,0x10,0x25,0x1b,0x12,0x19,0x15,0x91,0x2,0x7,0x23,0x1e,0x1e,0x23,0xfe,0x5f,0x8c,0x10,0x25,0x1b,0x12,0x19,0x15,0xc0,0xfe, + 0x69,0x0,0x0,0x1,0x0,0x90,0xff,0xf6,0x4,0x3c,0x4,0xad,0x0,0x29,0x0,0x2e,0x40,0x2b,0x24,0x13,0xb,0x3,0x1,0x3,0x1,0x4a,0x0,0x1,0x3,0x0, + 0x3,0x1,0x0,0x70,0x5,0x4,0x2,0x3,0x3,0xe,0x4b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x29,0x0,0x27,0x35,0x36,0x26,0x35,0x6,0x7, + 0x18,0x2b,0x0,0x16,0x17,0x13,0x16,0x6,0x23,0x23,0x22,0x26,0x27,0x3,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x37, + 0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x17,0x1,0x1,0x36,0x36,0x33,0x33,0x3,0xf7,0x25,0x1,0x1e,0x1,0x21,0x29,0x2,0x29,0x20,0x1,0x15,0xcf,0x10,0x2a, + 0x22,0x22,0x2a,0x10,0xcf,0x15,0x1,0x20,0x29,0x2,0x29,0x21,0x1,0x1e,0x1,0x26,0x25,0x2,0x23,0x2d,0x10,0x1,0x9,0x1,0x9,0x10,0x2e,0x23,0x2,0x4, + 0xad,0x1d,0x24,0xfb,0xcb,0x23,0x1e,0x1e,0x23,0x3,0x2d,0xfe,0x42,0x23,0x1d,0x1d,0x23,0x1,0xbe,0xfc,0xd3,0x23,0x1e,0x1e,0x23,0x4,0x35,0x24,0x1d,0x1f, + 0x22,0xfd,0xc6,0x2,0x3a,0x22,0x1f,0x0,0x0,0x0,0x0,0x1,0x0,0xaf,0xff,0xea,0x4,0x1d,0x4,0xad,0x0,0x21,0x0,0x51,0x4b,0xb0,0x28,0x50,0x58,0xb6, + 0x1b,0xa,0x2,0x0,0x2,0x1,0x4a,0x1b,0xb6,0x1b,0xa,0x2,0x1,0x2,0x1,0x4a,0x59,0x4b,0xb0,0x28,0x50,0x58,0x40,0xe,0x4,0x3,0x2,0x2,0x2,0xe, + 0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x12,0x4,0x3,0x2,0x2,0x2,0xe,0x4b,0x0,0x1,0x1,0xf,0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59, + 0x40,0xc,0x0,0x0,0x0,0x21,0x0,0x1f,0x35,0x37,0x25,0x5,0x7,0x17,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x1,0x23,0x11,0x14,0x6, + 0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x17,0x1,0x33,0x11,0x34,0x36,0x33,0x33,0x3,0xfd,0x20,0x25,0x26,0x1b,0x27,0x12,0xfd,0xc7,0x4, + 0x20,0x28,0x2,0x28,0x20,0x22,0x29,0x1b,0x2b,0x13,0x2,0x34,0x4,0x20,0x28,0x2,0x4,0xad,0x1e,0x23,0xfb,0xb9,0x1b,0x20,0x1c,0x1b,0x3,0x78,0xfc,0x9e, + 0x23,0x1e,0x1e,0x23,0x4,0x35,0x23,0x1e,0x1c,0xfc,0x8e,0x3,0x4d,0x23,0x1e,0x0,0x0,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x95,0x0,0x27, + 0x1,0x80,0xff,0xfe,0x1,0xe,0x1,0x2,0x0,0x41,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaf,0xff,0xea, + 0x4,0x1d,0x6,0x84,0x0,0x22,0x0,0x41,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0xa,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0xaf,0xfd,0xf2,0x4,0x1d,0x4,0xad,0x0,0x22,0x0,0x41,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xd2,0x0,0x0,0x0,0x1,0x0,0xaf,0xfe,0x66, + 0x4,0x1d,0x4,0xad,0x0,0x2f,0x0,0x3c,0x40,0x39,0x29,0x18,0x17,0x3,0x3,0x4,0xb,0x1,0x0,0x2,0x2,0x4a,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70, + 0x6,0x5,0x2,0x4,0x4,0xe,0x4b,0x0,0x3,0x3,0xf,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x0,0x0,0x0,0x2f,0x0,0x2d,0x35, + 0x38,0x23,0x17,0x25,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x33,0x32,0x36, + 0x35,0x35,0x1,0x23,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x17,0x1,0x33,0x11,0x34,0x36,0x33,0x33,0x3,0xfd,0x20,0x8d, + 0x84,0x3a,0x78,0x35,0x27,0xb,0x15,0x22,0xf,0xd,0x60,0x51,0x3f,0x3b,0xfd,0xbe,0x4,0x20,0x28,0x2,0x28,0x20,0x22,0x29,0x1b,0x2b,0x13,0x2,0x34,0x4, + 0x20,0x28,0x2,0x4,0xad,0x1e,0x23,0xfb,0xd,0x86,0x8d,0x1b,0x17,0x11,0x23,0x10,0x1b,0x2f,0x6,0x28,0x4a,0x53,0x7e,0x3,0x86,0xfc,0x9e,0x23,0x1e,0x1e, + 0x23,0x4,0x35,0x23,0x1e,0x1c,0xfc,0x8e,0x3,0x4d,0x23,0x1e,0x0,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x3b,0x0,0x22,0x0,0x41,0x0,0x0, + 0x1,0x7,0x1,0x9a,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x5a,0xff,0xea,0x4,0x72,0x4,0xb9, + 0x0,0xf,0x0,0x1f,0x0,0x2c,0x40,0x29,0x5,0x1,0x3,0x3,0x1,0x5b,0x4,0x1,0x1,0x1,0x16,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0, + 0x4c,0x10,0x10,0x0,0x0,0x10,0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0x6,0x7,0x15,0x2b,0x0,0x16,0x12,0x15,0x14,0x2,0x6,0x23,0x22,0x26, + 0x2,0x35,0x34,0x12,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0x2,0xee,0x82,0x82,0xee,0x9c,0x9c,0xee, + 0x82,0x82,0xee,0x9c,0x6f,0xa8,0x5b,0x5b,0xa7,0x70,0x70,0xa7,0x5b,0x5b,0xa8,0x6f,0x4,0xb9,0x99,0xfe,0xe8,0xb7,0xb7,0xfe,0xe9,0x99,0x99,0x1,0x17,0xb7, + 0xb7,0x1,0x18,0x99,0x94,0x71,0xd4,0x8f,0x8f,0xd3,0x71,0x71,0xd3,0x8f,0x8f,0xd4,0x71,0x0,0xff,0xff,0x0,0x5a,0xff,0xea,0x4,0x72,0x6,0x95,0x0,0x22, + 0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x80,0xff,0xea,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x5a,0xff,0xea, + 0x4,0x72,0x6,0x6a,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0x5a,0xff,0xea,0x4,0x72,0x6,0x82,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x5a,0xff,0xea,0x4,0x72,0x6,0x61,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x0,0x1,0xe, + 0x0,0x9,0xb1,0x2,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x5a,0xff,0xea,0x4,0x72,0x6,0x95,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7, + 0x1,0x95,0x0,0x16,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x5a,0xff,0xea,0x4,0x72,0x6,0x84,0x0,0x22, + 0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x96,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x2,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x5a,0xff,0xea, + 0x4,0x72,0x5,0xf0,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0x0,0x3,0x0,0x5a,0xff,0xae,0x4,0x72,0x4,0xf7,0x0,0x25,0x0,0x2e,0x0,0x37,0x0,0x46,0x40,0x43,0x22,0x1b,0x2,0x4,0x2,0x35,0x34,0x28,0x27,0x25, + 0x12,0x6,0x5,0x4,0xf,0x8,0x2,0x0,0x5,0x3,0x4a,0x0,0x3,0x2,0x3,0x72,0x0,0x1,0x0,0x1,0x73,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x16, + 0x4b,0x6,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x2f,0x2f,0x2f,0x37,0x2f,0x36,0x2b,0x13,0x2d,0x13,0x25,0x7,0x7,0x19,0x2b,0x0,0x16, + 0x15,0x14,0x2,0x6,0x23,0x22,0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x26,0x35,0x34,0x12,0x36,0x33,0x32,0x17,0x37,0x36,0x33,0x32, + 0x17,0x16,0x15,0x14,0x7,0x7,0x0,0x17,0x1,0x26,0x23,0x22,0x6,0x6,0x15,0x0,0x36,0x36,0x35,0x34,0x27,0x1,0x16,0x33,0x4,0x2c,0x46,0x82,0xee,0x9c, + 0xa2,0x7b,0x4d,0x17,0x18,0x12,0x1d,0x25,0x10,0x58,0x41,0x46,0x82,0xee,0x9c,0xa3,0x79,0x4e,0x17,0x19,0x13,0x1c,0x23,0xf,0x59,0xfd,0xa,0x49,0x1,0xef, + 0x53,0x73,0x6f,0xa8,0x5b,0x1,0xe2,0xa7,0x5b,0x4a,0xfe,0x11,0x57,0x70,0x3,0xb5,0xde,0x86,0xb7,0xfe,0xe9,0x99,0x53,0x6f,0x20,0x13,0x19,0x1b,0x11,0x18, + 0x7f,0x51,0xde,0x85,0xb7,0x1,0x18,0x99,0x53,0x71,0x20,0x13,0x19,0x1b,0x12,0x17,0x81,0xfd,0x95,0x79,0x2,0xc8,0x3b,0x71,0xd4,0x8f,0xfe,0x2d,0x71,0xd3, + 0x8f,0xb6,0x7b,0xfd,0x37,0x3b,0x0,0x0,0xff,0xff,0x0,0x5a,0xff,0xea,0x4,0x72,0x6,0x3b,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x9a,0x0,0x0, + 0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x54,0xff,0xfc,0x4,0x75,0x4,0xa7,0x0,0x23,0x0,0x2c,0x0,0x35, + 0x40,0x32,0x0,0x3,0x0,0x4,0x5,0x3,0x4,0x61,0x7,0x1,0x2,0x2,0x1,0x59,0x0,0x1,0x1,0xe,0x4b,0x6,0x8,0x2,0x5,0x5,0x0,0x59,0x0,0x0, + 0x0,0xf,0x0,0x4c,0x0,0x0,0x29,0x28,0x27,0x26,0x0,0x23,0x0,0x22,0x24,0x21,0x24,0x46,0x44,0x9,0x7,0x19,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21, + 0x23,0x6,0x26,0x2,0x35,0x34,0x12,0x36,0x17,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x21,0x0, + 0x16,0x16,0x17,0x11,0xe,0x2,0x15,0x4,0x58,0x1d,0x1d,0x22,0xfe,0x72,0x45,0x9f,0xee,0x82,0x82,0xee,0x9f,0x7d,0x1,0x42,0x22,0x1d,0x1d,0x22,0xfe,0xbe, + 0xf7,0x22,0x1d,0x1d,0x22,0xf7,0x1,0x56,0xfc,0xb8,0x56,0x9d,0x69,0x69,0x9d,0x56,0x90,0x21,0x27,0x27,0x21,0x4,0x8c,0x1,0xf,0xba,0xba,0x1,0xf,0x8d, + 0x4,0x21,0x27,0x27,0x21,0xfe,0x99,0x21,0x27,0x27,0x21,0xfe,0x74,0x1,0x32,0xca,0x6c,0x4,0x3,0x92,0x4,0x6b,0xcb,0x8f,0x0,0x0,0x0,0x2,0x0,0xeb, + 0xff,0xf6,0x4,0x30,0x4,0xa3,0x0,0x16,0x0,0x1f,0x0,0x30,0x40,0x2d,0x6,0x1,0x4,0x0,0x0,0x1,0x4,0x0,0x61,0x0,0x3,0x3,0x2,0x59,0x5,0x1, + 0x2,0x2,0xe,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x17,0x17,0x0,0x0,0x17,0x1f,0x17,0x1e,0x1d,0x1b,0x0,0x16,0x0,0x13,0x33,0x26,0x7,0x7,0x16,0x2b, + 0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x21,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x21,0x12,0x36,0x35,0x34,0x26,0x23,0x23, + 0x11,0x33,0x3,0x9,0xc3,0x64,0x64,0xc3,0x89,0xff,0x1,0x21,0x29,0x2,0x29,0x21,0x1d,0x22,0x57,0x0,0xff,0x7d,0x99,0x99,0x92,0xea,0xea,0x4,0xa3,0x64, + 0xb4,0x77,0x76,0xb3,0x62,0xfe,0xae,0x23,0x1e,0x1e,0x23,0x4,0x28,0x25,0x1f,0xfd,0x76,0x83,0x78,0x7a,0x85,0xfe,0x6,0x0,0x0,0x2,0x0,0xeb,0xff,0xf6, + 0x4,0x26,0x4,0xad,0x0,0x1a,0x0,0x23,0x0,0x5e,0x4b,0xb0,0x2f,0x50,0x58,0x40,0x1f,0x7,0x1,0x5,0x0,0x0,0x1,0x5,0x0,0x61,0x0,0x2,0x2,0xe, + 0x4b,0x0,0x4,0x4,0x3,0x59,0x6,0x1,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x1b,0x40,0x1d,0x6,0x1,0x3,0x0,0x4,0x5,0x3,0x4,0x61, + 0x7,0x1,0x5,0x0,0x0,0x1,0x5,0x0,0x61,0x0,0x2,0x2,0xe,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x59,0x40,0x14,0x1b,0x1b,0x0,0x0,0x1b,0x23,0x1b, + 0x22,0x21,0x1f,0x0,0x1a,0x0,0x19,0x35,0x33,0x26,0x8,0x7,0x17,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x21,0x15,0x14,0x6,0x23,0x23,0x22,0x26, + 0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x21,0x12,0x36,0x35,0x34,0x26,0x23,0x21,0x11,0x21,0x3,0x21,0xad,0x58,0x58,0xac,0x7a,0xfe,0xd9,0x21, + 0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x29,0x21,0x1,0x27,0x61,0x7f,0x7c,0x79,0xfe,0xee,0x1,0x12,0x3,0xb2,0x5b,0x9d,0x64,0x63,0x9c,0x59,0xc7,0x23,0x1e, + 0x1e,0x23,0x4,0x35,0x23,0x1e,0x1e,0x23,0xba,0xfd,0xdc,0x67,0x61,0x5e,0x6e,0xfe,0x6c,0x0,0x0,0x2,0x0,0x5a,0xff,0x58,0x4,0x72,0x4,0xb9,0x0,0x1a, + 0x0,0x35,0x0,0x68,0x40,0xc,0x2a,0x20,0x2,0x3,0x4,0x1a,0x9,0x2,0x1,0x3,0x2,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0x21,0x0,0x4,0x5,0x3,0x3, + 0x4,0x68,0x0,0x0,0x1,0x0,0x73,0x0,0x5,0x5,0x2,0x5b,0x0,0x2,0x2,0x16,0x4b,0x0,0x3,0x3,0x1,0x5c,0x0,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40, + 0x22,0x0,0x4,0x5,0x3,0x5,0x4,0x3,0x70,0x0,0x0,0x1,0x0,0x73,0x0,0x5,0x5,0x2,0x5b,0x0,0x2,0x2,0x16,0x4b,0x0,0x3,0x3,0x1,0x5c,0x0, + 0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x9,0x28,0x27,0x29,0x26,0x23,0x25,0x6,0x7,0x1a,0x2b,0x5,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x27,0x6,0x23, + 0x22,0x26,0x2,0x35,0x34,0x12,0x36,0x33,0x32,0x16,0x12,0x15,0x14,0x2,0x7,0x0,0x16,0x16,0x33,0x32,0x37,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17, + 0x17,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x3,0xea,0xf,0x2b,0x1d,0x15,0x1b,0x15,0x5a,0x4f,0x5d,0x9c,0xee,0x82,0x82,0xee,0x9c,0x9c, + 0xee,0x82,0x72,0x69,0xfd,0x5d,0x5b,0xa7,0x70,0x30,0x28,0x69,0xf,0x2b,0x1d,0x15,0x1a,0x16,0x72,0x47,0x4c,0x5b,0xa8,0x6f,0x6f,0xa8,0x5b,0x36,0x17,0x11, + 0x1d,0x1a,0x13,0x21,0x8c,0x1b,0x99,0x1,0x17,0xb7,0xb7,0x1,0x18,0x99,0x99,0xfe,0xe8,0xb7,0xac,0xfe,0xf6,0x4f,0x1,0x76,0xd3,0x71,0xa,0xa4,0x19,0xf, + 0x1c,0x1c,0x13,0x22,0xb2,0x3c,0xc7,0x83,0x8f,0xd4,0x71,0x71,0xd4,0x8f,0x0,0x0,0x0,0x2,0x0,0xeb,0xff,0xf1,0x4,0x19,0x4,0xa3,0x0,0x20,0x0,0x28, + 0x0,0x2b,0x40,0x28,0x1f,0x1,0x1,0x4,0x1,0x4a,0x0,0x4,0x0,0x1,0x0,0x4,0x1,0x61,0x0,0x5,0x5,0x3,0x59,0x0,0x3,0x3,0xe,0x4b,0x2,0x1, + 0x0,0x0,0x17,0x0,0x4c,0x23,0x28,0x45,0x33,0x12,0x25,0x6,0x7,0x1a,0x2b,0x24,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x27,0x1,0x23,0x11,0x14,0x6,0x23, + 0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x3b,0x2,0x32,0x16,0x16,0x15,0x14,0x6,0x7,0x1,0x1,0x33,0x20,0x35,0x34,0x26,0x23,0x23,0x4,0x19,0x17,0x18,0x23, + 0x11,0x1b,0x12,0xfe,0xd6,0xde,0x21,0x29,0x2,0x29,0x21,0x1d,0x22,0x57,0xeb,0x85,0xb9,0x5e,0x85,0x80,0x1,0x8,0xfd,0x76,0xd6,0x1,0x17,0x8b,0x8c,0xd6, + 0x42,0x10,0xf,0x18,0xb,0xf,0x1c,0x1,0xcc,0xfe,0x5e,0x23,0x1e,0x1e,0x23,0x4,0x28,0x25,0x1f,0x59,0xa1,0x6d,0x82,0xaf,0x21,0xfe,0x6e,0x2,0x11,0xd3, + 0x6a,0x6d,0x0,0x0,0xff,0xff,0x0,0xeb,0xff,0xf1,0x4,0x19,0x6,0x95,0x0,0x27,0x1,0x80,0xff,0xf6,0x1,0xe,0x1,0x2,0x0,0x55,0x0,0x0,0x0,0x9, + 0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xeb,0xff,0xf1,0x4,0x19,0x6,0x84,0x0,0x22,0x0,0x55,0x0,0x0,0x1,0x7,0x1,0x83, + 0xff,0xf6,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xeb,0xfd,0xf2,0x4,0x19,0x4,0xa3,0x0,0x22,0x0,0x55, + 0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xd2,0x0,0x0,0x0,0x1,0x0,0xa7,0xff,0xea,0x4,0x26,0x4,0xb9,0x0,0x3f,0x0,0x39,0x40,0x36,0x0,0x0,0x1,0x3, + 0x1,0x0,0x3,0x70,0x0,0x3,0x4,0x1,0x3,0x4,0x6e,0x0,0x1,0x1,0x5,0x5b,0x6,0x1,0x5,0x5,0x16,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2, + 0x17,0x2,0x4c,0x0,0x0,0x0,0x3f,0x0,0x3e,0x2d,0x2b,0x27,0x26,0x1f,0x1d,0x23,0x16,0x7,0x7,0x16,0x2b,0x0,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22, + 0x27,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36, + 0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x3,0x2d,0xaf,0x24,0xd, + 0x14,0x23,0xf,0x12,0x9a,0xbf,0x77,0x85,0x27,0x26,0x23,0x5b,0x55,0x52,0x6e,0x32,0x61,0x6d,0x63,0xc5,0x90,0x72,0xda,0x59,0x22,0xe,0x17,0x20,0x11,0x11, + 0x4b,0xb7,0x5e,0x8d,0x91,0x3f,0x3a,0x27,0x5a,0x4e,0x54,0x70,0x30,0x4e,0x56,0x66,0xb8,0x78,0x4,0xb9,0x64,0x15,0x23,0x16,0x1b,0x2d,0xa,0x5c,0x6a,0x5c, + 0x28,0x38,0x13,0x12,0x16,0xf,0xe,0x19,0x14,0x27,0x90,0x7c,0x69,0x9d,0x57,0x3d,0x37,0x15,0x22,0x17,0x1b,0x2c,0xb,0x30,0x3a,0x6d,0x5c,0x3e,0x4e,0x19, + 0x11,0x15,0xe,0xf,0x1b,0x16,0x23,0x7a,0x62,0x6b,0x9c,0x53,0x0,0x0,0xff,0xff,0x0,0xa7,0xff,0xea,0x4,0x26,0x6,0x95,0x0,0x22,0x0,0x59,0x0,0x0, + 0x1,0x7,0x1,0x80,0xff,0xea,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa7,0xff,0xea,0x4,0x26,0x6,0x84, + 0x0,0x22,0x0,0x59,0x0,0x0,0x1,0x7,0x1,0x83,0xff,0xfb,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xa7, + 0xfe,0x28,0x4,0x26,0x4,0xb9,0x0,0x5f,0x0,0xf4,0x40,0xa,0x23,0x1,0x1,0x0,0xf,0x1,0x2,0x4,0x2,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0x3f,0x0, + 0x9,0xa,0x6,0xa,0x9,0x6,0x70,0x0,0x6,0x7,0xa,0x6,0x7,0x6e,0x0,0x1,0x0,0x5,0x4,0x1,0x68,0x0,0x5,0x3,0x0,0x5,0x66,0x0,0x3,0x4, + 0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0xa,0xa,0x8,0x5b,0x0,0x8,0x8,0x16,0x4b,0x0,0x7,0x7,0x0,0x5b,0x0,0x0,0x0,0x17, + 0x0,0x4c,0x1b,0x4b,0xb0,0xc,0x50,0x58,0x40,0x40,0x0,0x9,0xa,0x6,0xa,0x9,0x6,0x70,0x0,0x6,0x7,0xa,0x6,0x7,0x6e,0x0,0x1,0x0,0x5,0x0, + 0x1,0x5,0x70,0x0,0x5,0x3,0x0,0x5,0x66,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0xa,0xa,0x8,0x5b,0x0,0x8, + 0x8,0x16,0x4b,0x0,0x7,0x7,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x41,0x0,0x9,0xa,0x6,0xa,0x9,0x6,0x70,0x0,0x6,0x7,0xa,0x6, + 0x7,0x6e,0x0,0x1,0x0,0x5,0x0,0x1,0x5,0x70,0x0,0x5,0x3,0x0,0x5,0x3,0x6e,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2, + 0x60,0x0,0xa,0xa,0x8,0x5b,0x0,0x8,0x8,0x16,0x4b,0x0,0x7,0x7,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x59,0x40,0x11,0x51,0x4f,0x4c,0x4b, + 0x45,0x43,0x24,0x1c,0x24,0x24,0x17,0x24,0x11,0x12,0xb,0x7,0x1c,0x2b,0x24,0x6,0x6,0x7,0x15,0x36,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35, + 0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x26,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32, + 0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6, + 0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x4,0x26,0x57,0xaf,0x7f,0x65,0x66,0x7c,0x79,0x44, + 0x80,0x33,0x17,0x8,0x11,0x1d,0x8,0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36,0x3e,0x27,0xf,0x13,0x5c,0xaf,0x49,0x22,0xe,0x17,0x20,0x11,0x11,0x4b,0xb7,0x5e, + 0x8d,0x91,0x3f,0x3a,0x27,0x5a,0x4e,0x54,0x70,0x30,0x4e,0x56,0x66,0xb8,0x78,0xeb,0xaf,0x24,0xd,0x14,0x23,0xf,0x12,0x9a,0xbf,0x77,0x85,0x27,0x26,0x23, + 0x5b,0x55,0x52,0x6e,0x32,0x61,0x6d,0xe5,0x97,0x5b,0x7,0x5d,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19,0xe,0x15,0x2d,0x2,0x10,0x16,0x21,0x1f,0x21, + 0x20,0x1,0x15,0x17,0x9f,0x9,0x3a,0x2d,0x15,0x22,0x17,0x1b,0x2c,0xb,0x30,0x3a,0x6d,0x5c,0x3e,0x4e,0x19,0x11,0x15,0xe,0xf,0x1b,0x16,0x23,0x7a,0x62, + 0x6b,0x9c,0x53,0x64,0x15,0x23,0x16,0x1b,0x2d,0xa,0x5c,0x6a,0x5c,0x28,0x38,0x13,0x12,0x16,0xf,0xe,0x19,0x14,0x27,0x90,0x7c,0x0,0x0,0x0,0xff,0xff, + 0x0,0xa7,0xff,0xea,0x4,0x26,0x6,0x82,0x0,0x27,0x1,0x92,0x0,0x6,0x1,0xe,0x1,0x2,0x0,0x59,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa7,0xfd,0xf2,0x4,0x26,0x4,0xb9,0x0,0x22,0x0,0x59,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xc2,0x0,0x0,0x0,0x1, + 0x0,0x7a,0xff,0xf6,0x4,0x52,0x4,0xa3,0x0,0x17,0x0,0x21,0x40,0x1e,0x2,0x1,0x0,0x0,0x3,0x59,0x4,0x1,0x3,0x3,0xe,0x4b,0x0,0x1,0x1,0xf, + 0x1,0x4c,0x0,0x0,0x0,0x17,0x0,0x15,0x23,0x33,0x24,0x5,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35, + 0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0x35,0x1d,0x1d,0x22,0xfe,0x9e,0x21,0x29,0x2,0x29,0x21,0xfe,0x9e,0x22,0x1d,0x1d,0x22,0x3,0x5a,0x4, + 0xa3,0x21,0x27,0x27,0x21,0xfc,0x24,0x23,0x1e,0x1e,0x23,0x3,0xdc,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0x7a,0xff,0xf6,0x4,0x52,0x4,0xa3, + 0x0,0x29,0x0,0x2f,0x40,0x2c,0x5,0x1,0x1,0x4,0x1,0x2,0x3,0x1,0x2,0x61,0x6,0x1,0x0,0x0,0x7,0x59,0x8,0x1,0x7,0x7,0xe,0x4b,0x0,0x3, + 0x3,0xf,0x3,0x4c,0x0,0x0,0x0,0x29,0x0,0x27,0x21,0x24,0x23,0x33,0x24,0x21,0x24,0x9,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x33, + 0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x11,0x21,0x22,0x26,0x35,0x34, + 0x36,0x33,0x21,0x4,0x35,0x1d,0x1d,0x22,0xfe,0x9e,0xce,0x22,0x1d,0x1d,0x22,0xce,0x21,0x29,0x2,0x29,0x21,0xce,0x22,0x1d,0x1d,0x22,0xce,0xfe,0x9e,0x22, + 0x1d,0x1d,0x22,0x3,0x5a,0x4,0xa3,0x21,0x27,0x27,0x21,0xfe,0x3b,0x21,0x27,0x27,0x21,0xfe,0x79,0x23,0x1e,0x1e,0x23,0x1,0x87,0x21,0x27,0x27,0x21,0x1, + 0xc5,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0x7a,0xff,0xf6,0x4,0x52,0x6,0x84,0x0,0x22,0x0,0x5f,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x0, + 0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x7a,0xfe,0x28,0x4,0x52,0x4,0xa3,0x0,0x34,0x0,0x7e,0x40,0xb, + 0x29,0x9,0x2,0x1,0x0,0x15,0x1,0x2,0x4,0x2,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0x29,0x0,0x1,0x0,0x5,0x4,0x1,0x68,0x0,0x5,0x3,0x0,0x5, + 0x3,0x6e,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x6,0x1,0x0,0x0,0x7,0x59,0x8,0x1,0x7,0x7,0xe,0x0,0x4c,0x1b, + 0x40,0x2a,0x0,0x1,0x0,0x5,0x0,0x1,0x5,0x70,0x0,0x5,0x3,0x0,0x5,0x3,0x6e,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2, + 0x60,0x6,0x1,0x0,0x0,0x7,0x59,0x8,0x1,0x7,0x7,0xe,0x0,0x4c,0x59,0x40,0x10,0x0,0x0,0x0,0x34,0x0,0x32,0x27,0x24,0x24,0x17,0x24,0x14,0x24, + 0x9,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x7,0x15,0x36,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33, + 0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x26,0x35,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0x35,0x1d, + 0x1d,0x22,0xfe,0x9e,0x9,0x65,0x66,0x7c,0x79,0x44,0x80,0x33,0x17,0x8,0x11,0x1d,0x8,0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36,0x3e,0x27,0xf,0x13,0x9,0xfe, + 0x9e,0x22,0x1d,0x1d,0x22,0x3,0x5a,0x4,0xa3,0x21,0x27,0x27,0x21,0xfc,0x24,0x1a,0xf,0x7f,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19,0xe,0x15,0x2d, + 0x2,0x10,0x16,0x21,0x1f,0x21,0x20,0x1,0x15,0x17,0xbf,0xf,0x1a,0x3,0xdc,0x21,0x27,0x27,0x21,0x0,0xff,0xff,0x0,0x7a,0xfd,0xf2,0x4,0x52,0x4,0xa3, + 0x0,0x22,0x0,0x5f,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xc8,0x0,0x0,0x0,0x1,0x0,0xaf,0xff,0xea,0x4,0x1d,0x4,0xad,0x0,0x1f,0x0,0x21,0x40,0x1e, + 0x4,0x3,0x2,0x1,0x1,0xe,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x1f,0x0,0x1d,0x25,0x36,0x26,0x5,0x7,0x17, + 0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x11,0x34, + 0x36,0x33,0x33,0x3,0xfc,0x21,0x6e,0xc6,0x83,0x83,0xc6,0x6e,0x21,0x29,0x2,0x29,0x21,0x96,0x8b,0x8b,0x96,0x21,0x29,0x2,0x4,0xad,0x1e,0x23,0xfd,0x31, + 0x8c,0xc3,0x64,0x64,0xc3,0x8c,0x2,0xcf,0x23,0x1e,0x1e,0x23,0xfd,0x45,0x99,0x9a,0x9a,0x99,0x2,0xbb,0x23,0x1e,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d, + 0x6,0x95,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x1c,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x6a,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x82,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x0,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x61,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x93, + 0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x95,0x0,0x22,0x0,0x64, + 0x0,0x0,0x1,0x7,0x1,0x95,0xff,0xe4,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x4f, + 0x6,0x84,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x96,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0xaf,0xff,0xea,0x4,0x1d,0x5,0xf0,0x0,0x27,0x1,0x97,0x0,0x0,0x1,0xe,0x1,0x2,0x0,0x64,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xaf,0xfe,0x28,0x4,0x1d,0x4,0xad,0x0,0x38,0x0,0x58,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x1a,0x1,0x1,0x0,0x0,0x2, + 0x0,0x2,0x5f,0x7,0x6,0x2,0x4,0x4,0xe,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x17,0x3,0x4c,0x1b,0x40,0x21,0x0,0x1,0x3,0x0,0x3,0x1, + 0x0,0x70,0x0,0x0,0x0,0x2,0x0,0x2,0x5f,0x7,0x6,0x2,0x4,0x4,0xe,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x17,0x3,0x4c,0x59,0x40,0xf, + 0x0,0x0,0x0,0x38,0x0,0x36,0x25,0x36,0x25,0x27,0x31,0x2b,0x8,0x7,0x1a,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32, + 0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x23,0x22,0x26,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16, + 0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x35,0x11,0x34,0x36,0x33,0x33,0x3,0xfc,0x21,0x6e,0x64,0x69,0x5b,0x2a,0x23,0x34,0x3d,0x8,0x3,0x1e,0x9,0x2,0x11, + 0x11,0x4b,0x59,0x5d,0x6b,0x44,0x41,0xa,0x83,0xc6,0x6e,0x21,0x29,0x2,0x29,0x21,0x96,0x8b,0x8b,0x96,0x21,0x29,0x2,0x4,0xad,0x1e,0x23,0xfd,0x31,0x8b, + 0xc4,0x33,0x5d,0x86,0x3c,0x23,0x26,0x11,0x2,0x36,0x12,0x7,0x16,0x19,0x6,0x1a,0x68,0x57,0x44,0x7f,0x40,0x64,0xc3,0x8c,0x2,0xcf,0x23,0x1e,0x1e,0x23, + 0xfd,0x45,0x99,0x9a,0x9a,0x99,0x2,0xbb,0x23,0x1e,0x0,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x7,0x5,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7, + 0x1,0x99,0x0,0x0,0x0,0xf0,0x0,0x8,0xb1,0x1,0x2,0xb0,0xf0,0xb0,0x33,0x2b,0x0,0x0,0xff,0xff,0x0,0xaf,0xff,0xea,0x4,0x1d,0x6,0x3b,0x0,0x27, + 0x1,0x9a,0x0,0x0,0x1,0xe,0x1,0x2,0x0,0x64,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x63,0xff,0xea, + 0x4,0x65,0x4,0xad,0x0,0x1d,0x0,0x1b,0x40,0x18,0x17,0x1,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x1,0xe,0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x16,0x29, + 0x27,0x3,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x1,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x1,0x1, + 0x36,0x36,0x33,0x32,0x17,0x4,0x49,0x1c,0x7,0xfe,0x71,0xd,0x33,0x2b,0x2b,0x33,0xd,0xfe,0x71,0x7,0x1c,0x1e,0x1a,0xe,0x14,0x1a,0x8,0x1,0x69,0x1, + 0x69,0x8,0x1a,0x14,0xe,0x1a,0x4,0x9b,0x1a,0x13,0xa,0x15,0xfb,0xdc,0x23,0x1e,0x1e,0x23,0x4,0x24,0x15,0xa,0x13,0x1a,0xa,0x8,0x16,0x18,0xfc,0x37, + 0x3,0xc9,0x18,0x16,0x8,0x0,0x0,0x1,0x0,0x43,0xff,0xea,0x4,0x81,0x4,0xad,0x0,0x2b,0x0,0x4b,0x40,0xd,0x12,0x2,0x2,0x3,0x2,0x25,0x1d,0xb, + 0x3,0x0,0x3,0x2,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x12,0x4,0x1,0x2,0x2,0xe,0x4b,0x0,0x3,0x3,0x11,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c, + 0x1b,0x40,0x15,0x0,0x3,0x2,0x0,0x2,0x3,0x0,0x70,0x4,0x1,0x2,0x2,0xe,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x59,0xb7,0x36,0x26,0x38,0x24, + 0x27,0x5,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x27,0x3,0x3,0x6,0x23,0x22,0x26,0x27,0x3,0x26,0x35,0x34,0x36,0x37,0x36, + 0x33,0x32,0x16,0x17,0x13,0x13,0x36,0x36,0x33,0x32,0x16,0x17,0x13,0x13,0x36,0x36,0x33,0x32,0x17,0x4,0x61,0x20,0x1,0x95,0x5,0x29,0x28,0x4d,0x17,0xcf, + 0xcf,0x17,0x4d,0x28,0x29,0x5,0x95,0x1,0x20,0x24,0x7,0xd,0x1e,0x1c,0x4,0x70,0xcf,0x7,0x23,0x20,0x20,0x23,0x7,0xcf,0x70,0x4,0x1c,0x1e,0xd,0x7, + 0x4,0xa7,0x1a,0x19,0xc,0x6,0xfb,0xc9,0x24,0x1d,0x41,0x2,0x4a,0xfd,0xb6,0x41,0x1d,0x24,0x4,0x37,0x6,0xc,0x19,0x1a,0x5,0x1,0x1b,0x1f,0xfc,0x8f, + 0x2,0x4b,0x14,0x14,0x14,0x14,0xfd,0xb5,0x3,0x71,0x1f,0x1b,0x1,0x0,0x0,0x0,0xff,0xff,0x0,0x43,0xff,0xea,0x4,0x81,0x6,0x95,0x0,0x22,0x0,0x70, + 0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x43,0xff,0xea,0x4,0x81, + 0x6,0x82,0x0,0x22,0x0,0x70,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0x43,0xff,0xea,0x4,0x81,0x6,0x61,0x0,0x22,0x0,0x70,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x43,0xff,0xea,0x4,0x81,0x6,0x95,0x0,0x22,0x0,0x70,0x0,0x0,0x1,0x7,0x1,0x95,0xff,0xe2,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x95,0xff,0xf0,0x4,0x43,0x4,0xb3,0x0,0x28,0x0,0x22,0x40,0x1f,0x27,0x24,0x1d,0x13, + 0x10,0x8,0x6,0x0,0x2,0x1,0x4a,0x3,0x1,0x2,0x2,0x16,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x24,0x2c,0x25,0x24,0x4,0x7,0x18,0x2b,0x24,0x15, + 0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x1,0x6,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x1,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x1,0x1,0x36, + 0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x1,0x4,0x43,0x2d,0x25,0x14,0x1e,0x14,0xfe,0xbf,0xfe,0xc3,0xb,0x18,0xf,0x14,0x25,0x2d,0xf,0x1,0x6a,0xfe, + 0xad,0xf,0x2d,0x25,0x14,0x1d,0x15,0x1,0x29,0x1,0x27,0x15,0x1d,0x14,0x25,0x2d,0xf,0xfe,0xac,0x1,0x6b,0x44,0x11,0x1f,0x14,0x10,0x1f,0x1,0xd8,0xfe, + 0x28,0x10,0xf,0x10,0x14,0x1e,0x12,0x15,0x2,0x4,0x1,0xed,0x15,0x12,0x1e,0x14,0x10,0x1f,0xfe,0x41,0x1,0xbf,0x1f,0x10,0x14,0x1e,0x12,0x15,0xfe,0x12, + 0xfd,0xfd,0x0,0x1,0x0,0x7d,0xff,0xf6,0x4,0x4f,0x4,0xb1,0x0,0x1e,0x0,0x1d,0x40,0x1a,0x19,0xe,0x5,0x3,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x1, + 0x16,0x4b,0x0,0x0,0x0,0xf,0x0,0x4c,0x14,0x2a,0x38,0x3,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11, + 0x1,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x17,0x1,0x1,0x36,0x33,0x32,0x17,0x4,0x38,0x17,0xf,0xfe,0x71,0x21,0x29,0x2,0x29,0x21,0xfe,0x71,0xf, + 0x17,0x19,0x21,0x13,0x1e,0x12,0x1,0x55,0x1,0x55,0x14,0x1c,0x13,0x21,0x4,0x98,0x19,0x10,0x10,0x17,0xfd,0x9f,0xfe,0x50,0x23,0x1e,0x1e,0x23,0x1,0xb0, + 0x2,0x61,0x17,0x10,0x10,0x19,0xb,0xe,0x1d,0xfd,0xf2,0x2,0xe,0x1d,0xe,0x0,0x0,0x0,0xff,0xff,0x0,0x7d,0xff,0xf6,0x4,0x4f,0x6,0x95,0x0,0x27, + 0x1,0x80,0x0,0x1c,0x1,0xe,0x1,0x2,0x0,0x76,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x7d,0xff,0xf6, + 0x4,0x4f,0x6,0x82,0x0,0x22,0x0,0x76,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x1,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0x7d,0xff,0xf6,0x4,0x4f,0x6,0x61,0x0,0x22,0x0,0x76,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x7d,0xff,0xf6,0x4,0x4f,0x6,0x95,0x0,0x22,0x0,0x76,0x0,0x0,0x1,0x7,0x1,0x95,0xff,0xe4,0x1,0xe, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xa7,0x0,0x0,0x4,0x23,0x4,0xa3,0x0,0x1d,0x0,0x25,0x40,0x22,0x0,0x1, + 0x1,0x2,0x59,0x0,0x2,0x2,0xe,0x4b,0x4,0x1,0x3,0x3,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x1d,0x0,0x1c,0x44,0x25,0x44,0x5, + 0x7,0x17,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x33,0x32,0x16,0x15,0x14, + 0x7,0x1,0x21,0x4,0x6,0x1d,0x1d,0x22,0xfd,0x52,0x50,0x22,0x1d,0xe,0x2,0x81,0xfd,0xca,0x22,0x1d,0x1d,0x22,0x2,0x7b,0x57,0x22,0x1d,0xa,0xfd,0x7d, + 0x2,0x60,0x90,0x21,0x27,0x27,0x21,0x1f,0x25,0x16,0x15,0x3,0xa4,0x21,0x27,0x27,0x21,0x1f,0x25,0x19,0xe,0xfc,0x58,0x0,0xff,0xff,0x0,0xa7,0x0,0x0, + 0x4,0x23,0x6,0x95,0x0,0x22,0x0,0x7b,0x0,0x0,0x1,0x7,0x1,0x80,0xff,0xfe,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0xa7,0x0,0x0,0x4,0x23,0x6,0x84,0x0,0x22,0x0,0x7b,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x8,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa7,0x0,0x0,0x4,0x23,0x6,0x61,0x0,0x27,0x1,0x94,0x0,0xa,0x1,0xe,0x1,0x2,0x0,0x7b,0x0,0x0, + 0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x9f,0xff,0xea,0x3,0xf6,0x3,0xb2,0x0,0x29,0x0,0x35,0x0,0x86,0x40,0xc, + 0x17,0x1,0x6,0x2,0x2c,0x2b,0xb,0x3,0x7,0x6,0x2,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x28,0x0,0x4,0x3,0x2,0x3,0x4,0x2,0x70,0x0,0x2,0x0, + 0x6,0x7,0x2,0x6,0x63,0x0,0x3,0x3,0x5,0x5b,0x8,0x1,0x5,0x5,0x19,0x4b,0x9,0x1,0x7,0x7,0x0,0x5b,0x1,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b, + 0x40,0x2c,0x0,0x4,0x3,0x2,0x3,0x4,0x2,0x70,0x0,0x2,0x0,0x6,0x7,0x2,0x6,0x63,0x0,0x3,0x3,0x5,0x5b,0x8,0x1,0x5,0x5,0x19,0x4b,0x0, + 0x0,0x0,0xf,0x4b,0x9,0x1,0x7,0x7,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x16,0x2a,0x2a,0x0,0x0,0x2a,0x35,0x2a,0x34,0x30,0x2e,0x0, + 0x29,0x0,0x28,0x23,0x24,0x25,0x25,0x35,0xa,0x7,0x19,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x6,0x23,0x22,0x26,0x26, + 0x35,0x34,0x36,0x33,0x32,0x17,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x12,0x37,0x35,0x26,0x26,0x23, + 0x22,0x6,0x15,0x14,0x16,0x33,0x3,0x3a,0xbc,0x1e,0x27,0x2,0x27,0x1e,0x51,0xbd,0x69,0x64,0x9a,0x56,0xdf,0xb2,0x9f,0x91,0x6d,0x79,0x4b,0xa2,0x49,0x10, + 0xf,0x20,0x17,0xb,0x25,0x54,0xc1,0x61,0x42,0xa0,0x44,0x9c,0x4f,0x73,0x85,0x65,0x5b,0x3,0xb2,0xa8,0xa5,0xfd,0xd2,0x23,0x1e,0x1e,0x23,0x44,0x45,0x4c, + 0x45,0x84,0x5b,0x9f,0x96,0x33,0x55,0x61,0x5b,0x2a,0x25,0x9,0x30,0x18,0x10,0x23,0x13,0x2c,0x2f,0xfc,0xc5,0xa5,0x6d,0x16,0x17,0x4f,0x56,0x49,0x51,0x0, + 0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x5,0x87,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x80,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x9f,0xff,0xea, + 0x3,0xf6,0x5,0x5c,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x82,0xd,0x0,0x0,0x0,0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x5,0x74,0x0,0x22, + 0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x92,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x5,0x53,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2, + 0x1,0x93,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x5,0x87,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x95,0x32,0x0,0x0,0x0, + 0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x4,0xe2,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x97,0x14,0x0,0x0,0x0,0x0,0x2,0x0,0x9f,0xfe,0x28, + 0x4,0x2d,0x3,0xb2,0x0,0x3b,0x0,0x47,0x0,0x59,0x40,0x56,0x29,0x1,0x8,0x3,0x44,0x43,0x1d,0x3,0x7,0x8,0x1c,0x3,0x2,0x2,0x7,0x3,0x4a,0x0, + 0x5,0x4,0x3,0x4,0x5,0x3,0x70,0x0,0x3,0xa,0x1,0x8,0x7,0x3,0x8,0x63,0x0,0x0,0x0,0x1,0x0,0x1,0x5f,0x0,0x4,0x4,0x6,0x5b,0x9,0x1, + 0x6,0x6,0x19,0x4b,0x0,0x7,0x7,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x3c,0x3c,0x0,0x0,0x3c,0x47,0x3c,0x46,0x42,0x40,0x0,0x3b,0x0,0x3a,0x23, + 0x24,0x25,0x28,0x28,0x2b,0xb,0x7,0x1a,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x16,0x15,0x14,0x6,0x7, + 0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x35,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x33,0x32,0x17,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23, + 0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x2,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x35,0x26,0x26,0x23,0x3,0x3a,0xbc,0x7,0x9,0x5b,0x50,0x2a,0x23, + 0x37,0x3a,0x18,0x1c,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x67,0x64,0x51,0xbd,0x69,0x64,0x9a,0x56,0xdf,0xb2,0x9f,0x91,0x6d,0x79,0x4b,0xa2,0x49,0x10,0xf,0x20, + 0x17,0xb,0x25,0x54,0xc1,0x61,0xc0,0x85,0x65,0x5b,0xc7,0xa0,0x44,0x9c,0x4f,0x3,0xb2,0xa8,0xa5,0xfd,0xd2,0x13,0x18,0x8,0x54,0x7d,0x38,0x24,0x27,0xa, + 0x4,0x23,0x27,0x14,0x18,0x6,0x1a,0x68,0x57,0x51,0x98,0x50,0x5b,0x45,0x4c,0x45,0x84,0x5b,0x9f,0x96,0x33,0x55,0x61,0x5b,0x2a,0x25,0x9,0x30,0x18,0x10, + 0x23,0x13,0x2c,0x2f,0xfe,0x4,0x4f,0x56,0x49,0x51,0xa5,0x6d,0x16,0x17,0x0,0x0,0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x6,0x15,0x0,0x22,0x0,0x7f, + 0x0,0x0,0x0,0x2,0x1,0x99,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0x9f,0xff,0xea,0x3,0xf6,0x5,0x2d,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x9a, + 0xa,0x0,0x0,0x0,0x0,0x3,0x0,0x4b,0xff,0xea,0x4,0x80,0x3,0xb2,0x0,0x38,0x0,0x3f,0x0,0x4a,0x0,0x65,0x40,0x62,0x35,0x1,0x6,0x8,0x18,0x1, + 0x3,0x1,0x2,0x4a,0x0,0x7,0x6,0x5,0x6,0x7,0x5,0x70,0x0,0x2,0x0,0x1,0x0,0x2,0x1,0x70,0xa,0x1,0x5,0x10,0xd,0x2,0x0,0x2,0x5,0x0, + 0x63,0xf,0xb,0x2,0x6,0x6,0x8,0x5b,0xe,0x9,0x2,0x8,0x8,0x19,0x4b,0xc,0x1,0x1,0x1,0x3,0x5b,0x4,0x1,0x3,0x3,0x17,0x3,0x4c,0x40,0x40, + 0x39,0x39,0x0,0x0,0x40,0x4a,0x40,0x4a,0x46,0x44,0x39,0x3f,0x39,0x3e,0x3c,0x3b,0x0,0x38,0x0,0x37,0x26,0x23,0x23,0x15,0x23,0x27,0x23,0x21,0x24,0x11, + 0x7,0x1d,0x2b,0x0,0x16,0x17,0x16,0x6,0x23,0x21,0x12,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x27,0x6,0x6, + 0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x33,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x36,0x36,0x33, + 0x6,0x6,0x7,0x21,0x26,0x26,0x23,0x0,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x35,0x3,0xed,0x8c,0x6,0x1,0x1e,0x22,0xfe,0x71,0x5,0x9f,0x30, + 0x50,0x2a,0x11,0x16,0x1f,0x19,0x15,0x1b,0x37,0x84,0x48,0xa3,0x51,0x30,0x91,0x51,0x4e,0x76,0x40,0xf9,0xd7,0x38,0x4b,0x2d,0x56,0x2e,0x13,0x17,0x1c,0x18, + 0x15,0x17,0x7b,0x92,0x99,0x44,0x28,0x71,0x47,0x45,0x4e,0xc,0x1,0x2c,0x7,0x42,0x42,0xfe,0x24,0x97,0x3c,0x33,0x38,0x5b,0x35,0x3,0xb2,0xe8,0xd4,0x21, + 0x1d,0xfe,0xc3,0x25,0x29,0x11,0x1f,0x19,0x19,0x1c,0x19,0x34,0x36,0x90,0x43,0x4d,0x40,0x76,0x50,0xa7,0xad,0x16,0x65,0x62,0x22,0x23,0xf,0x19,0x18,0x1a, + 0x1c,0x14,0x6a,0x74,0x39,0x3b,0x91,0x68,0x75,0x6c,0x71,0xfe,0x97,0x64,0x64,0x39,0x40,0x39,0x65,0x3f,0x64,0x0,0x0,0x0,0x0,0x2,0x0,0xc0,0xff,0xea, + 0x4,0x41,0x5,0x2a,0x0,0x1d,0x0,0x2d,0x0,0x68,0xb6,0x10,0x3,0x2,0x4,0x5,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1d,0x6,0x1,0x3,0x3,0x10, + 0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x0,0x4,0x4,0x1,0x5b,0x2,0x1,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x21,0x6,0x1,0x3, + 0x3,0x10,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x0,0x2,0x2,0xf,0x4b,0x0,0x4,0x4,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c, + 0x59,0x40,0x14,0x1e,0x1e,0x0,0x0,0x1e,0x2d,0x1e,0x2c,0x26,0x24,0x0,0x1d,0x0,0x1b,0x35,0x26,0x24,0x8,0x7,0x17,0x2b,0x0,0x16,0x15,0x11,0x36,0x33, + 0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x15,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x0,0x6,0x6,0x15,0x14,0x16, + 0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x1,0x35,0x21,0x81,0xbc,0x7c,0xc3,0x6f,0x6f,0xc3,0x7c,0x62,0xa6,0x3f,0x1e,0x27,0x2,0x27,0x1e,0x21, + 0x29,0x2,0x1,0x24,0x8b,0x4f,0x4f,0x8b,0x59,0x59,0x81,0x44,0x44,0x81,0x59,0x5,0x2a,0x1e,0x23,0xfe,0x24,0xa5,0x75,0xdb,0x94,0x94,0xdb,0x75,0x58,0x52, + 0x5d,0x23,0x1e,0x1e,0x23,0x4,0xb2,0x23,0x1e,0xfd,0xf4,0x50,0x98,0x68,0x68,0x98,0x50,0x55,0x99,0x62,0x62,0x99,0x55,0x0,0x0,0x1,0x0,0x93,0xff,0xea, + 0x4,0x31,0x3,0xb2,0x0,0x2a,0x0,0x36,0x40,0x33,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x0,0x3,0x2,0x1,0x3,0x2,0x6e,0x0,0x1,0x1,0x5,0x5b, + 0x6,0x1,0x5,0x5,0x19,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x0,0x0,0x0,0x2a,0x0,0x29,0x27,0x23,0x26,0x23,0x17,0x7,0x7, + 0x19,0x2b,0x0,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17, + 0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x2,0xe0,0xc5,0x54,0x23,0xf,0x14,0x20,0x13,0x12,0x8d,0xb2,0x60,0x93,0x51, + 0x51,0x93,0x60,0x5c,0xad,0x47,0x14,0x12,0x1f,0x16,0x11,0x20,0x52,0xd9,0x71,0x8f,0xdb,0x78,0x78,0xdb,0x8f,0x3,0xb2,0x38,0x36,0x16,0x23,0x17,0x1b,0x29, + 0xd,0x61,0x56,0x99,0x61,0x61,0x99,0x56,0x39,0x36,0xf,0x26,0x1d,0x17,0x21,0x17,0x3c,0x44,0x7e,0xdc,0x8a,0x8a,0xdc,0x7e,0xff,0xff,0x0,0x93,0xff,0xea, + 0x4,0x31,0x5,0x87,0x0,0x22,0x0,0x8b,0x0,0x0,0x0,0x2,0x1,0x80,0xfd,0x0,0x0,0x0,0xff,0xff,0x0,0x93,0xff,0xea,0x4,0x31,0x5,0x76,0x0,0x22, + 0x0,0x8b,0x0,0x0,0x0,0x2,0x1,0x83,0x1e,0x0,0x0,0x0,0x0,0x1,0x0,0x93,0xfe,0x28,0x4,0x31,0x3,0xb2,0x0,0x4a,0x0,0x9a,0x40,0xb,0x26,0x6, + 0x2,0x0,0x8,0x12,0x1,0x1,0x3,0x2,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0x38,0x0,0x6,0x7,0x9,0x7,0x6,0x9,0x70,0x0,0x9,0x8,0x7,0x9,0x8, + 0x6e,0x0,0x0,0x8,0x4,0x3,0x0,0x68,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x8,0x0,0x4,0x2,0x8,0x4,0x63,0x0,0x3,0x0,0x1,0x3,0x1, + 0x60,0x0,0x7,0x7,0x5,0x5b,0x0,0x5,0x5,0x19,0x7,0x4c,0x1b,0x40,0x39,0x0,0x6,0x7,0x9,0x7,0x6,0x9,0x70,0x0,0x9,0x8,0x7,0x9,0x8,0x6e, + 0x0,0x0,0x8,0x4,0x8,0x0,0x4,0x70,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x8,0x0,0x4,0x2,0x8,0x4,0x63,0x0,0x3,0x0,0x1,0x3,0x1, + 0x60,0x0,0x7,0x7,0x5,0x5b,0x0,0x5,0x5,0x19,0x7,0x4c,0x59,0x40,0xe,0x49,0x47,0x26,0x23,0x17,0x2b,0x24,0x24,0x17,0x24,0x17,0xa,0x7,0x1d,0x2b, + 0x24,0x15,0x14,0x7,0x6,0x6,0x7,0x15,0x36,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36, + 0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x2e,0x2,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22, + 0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x4,0x31,0x20,0x46,0xb5,0x61,0x65,0x66,0x7c,0x79,0x44,0x80,0x33,0x17,0x8,0x11, + 0x1d,0x8,0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36,0x3e,0x27,0xf,0x13,0x7d,0xbb,0x66,0x78,0xdb,0x8f,0x6b,0xc5,0x54,0x23,0xf,0x14,0x20,0x13,0x12,0x8d,0xb2, + 0x60,0x93,0x51,0x51,0x93,0x60,0x5c,0xad,0x47,0x14,0x12,0x1f,0x16,0xb9,0x17,0x21,0x17,0x33,0x42,0x8,0x5e,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19, + 0xe,0x15,0x2d,0x2,0x10,0x16,0x21,0x1f,0x21,0x20,0x1,0x15,0x17,0x9f,0xf,0x83,0xcf,0x7f,0x8a,0xdc,0x7e,0x38,0x36,0x16,0x23,0x17,0x1b,0x29,0xd,0x61, + 0x56,0x99,0x61,0x61,0x99,0x56,0x39,0x36,0xf,0x26,0x0,0x0,0xff,0xff,0x0,0x93,0xff,0xea,0x4,0x31,0x5,0x74,0x0,0x22,0x1,0x92,0x1e,0x0,0x0,0x2, + 0x0,0x8b,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x93,0xff,0xea,0x4,0x31,0x5,0x53,0x0,0x22,0x0,0x8b,0x0,0x0,0x0,0x2,0x1,0x94,0x1e,0x0,0x0,0x0, + 0x0,0x2,0x0,0x8b,0xff,0xea,0x4,0xc,0x5,0x2a,0x0,0x1d,0x0,0x2d,0x0,0x68,0xb6,0x18,0xb,0x2,0x4,0x5,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40, + 0x1d,0x6,0x1,0x3,0x3,0x10,0x4b,0x7,0x1,0x5,0x5,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x4,0x4,0x0,0x5b,0x1,0x1,0x0,0x0,0xf,0x0,0x4c, + 0x1b,0x40,0x21,0x6,0x1,0x3,0x3,0x10,0x4b,0x7,0x1,0x5,0x5,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x0,0x0,0xf,0x4b,0x0,0x4,0x4,0x1,0x5b, + 0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x14,0x1e,0x1e,0x0,0x0,0x1e,0x2d,0x1e,0x2c,0x26,0x24,0x0,0x1d,0x0,0x1b,0x26,0x25,0x35,0x8,0x7,0x17,0x2b, + 0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x11,0x34,0x36,0x33,0x33, + 0x0,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0xeb,0x21,0x1e,0x27,0x2,0x27,0x1e,0x3f,0xa6,0x62,0x7c,0xc3,0x6f, + 0x6f,0xc3,0x7c,0xbc,0x81,0x21,0x29,0x2,0xfe,0x28,0x81,0x44,0x44,0x81,0x59,0x59,0x8b,0x4f,0x4f,0x8b,0x59,0x5,0x2a,0x1e,0x23,0xfb,0x4e,0x23,0x1e,0x1e, + 0x23,0x5d,0x52,0x58,0x75,0xdb,0x94,0x94,0xdb,0x75,0xa5,0x1,0xdc,0x23,0x1e,0xfd,0xf4,0x55,0x99,0x62,0x62,0x99,0x55,0x50,0x98,0x68,0x68,0x98,0x50,0x0, + 0x0,0x2,0x0,0x8c,0xff,0xea,0x4,0x40,0x5,0x34,0x0,0x33,0x0,0x43,0x0,0xac,0x40,0xe,0x33,0x28,0x20,0x1c,0x11,0x5,0x2,0x4,0xf,0x1,0x5,0x1, + 0x2,0x4a,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x28,0x0,0x2,0x4,0x1,0x4,0x2,0x1,0x70,0x0,0x3,0x3,0x10,0x4b,0x0,0x4,0x4,0x10,0x4b,0x0,0x5,0x5, + 0x1,0x5b,0x0,0x1,0x1,0x11,0x4b,0x7,0x1,0x6,0x6,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x4b,0xb0,0x20,0x50,0x58,0x40,0x26,0x0,0x2,0x4, + 0x1,0x4,0x2,0x1,0x70,0x0,0x1,0x0,0x5,0x6,0x1,0x5,0x63,0x0,0x3,0x3,0x10,0x4b,0x0,0x4,0x4,0x10,0x4b,0x7,0x1,0x6,0x6,0x0,0x5b,0x0, + 0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x28,0x0,0x4,0x3,0x2,0x3,0x4,0x2,0x70,0x0,0x2,0x1,0x3,0x2,0x1,0x6e,0x0,0x1,0x0,0x5,0x6,0x1,0x5, + 0x63,0x0,0x3,0x3,0x10,0x4b,0x7,0x1,0x6,0x6,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x59,0x40,0xf,0x34,0x34,0x34,0x43,0x34,0x42,0x2e,0x26, + 0x1e,0x25,0x26,0x24,0x8,0x7,0x1a,0x2b,0x0,0x11,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x26,0x27,0x7,0x6,0x23,0x22, + 0x26,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x17,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x7, + 0x2,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x4,0x40,0x7b,0xd8,0x87,0x87,0xd8,0x7b,0x7b,0xd8,0x87,0x79,0x76,0x49, + 0x88,0xf0,0x11,0xe,0x12,0x18,0xa,0x8,0x2b,0x95,0x2d,0x4d,0x25,0xe,0x18,0x22,0x11,0x12,0x7d,0x60,0xed,0x11,0xe,0x12,0x18,0xa,0x8,0x2b,0xa1,0x5a, + 0x8f,0x4f,0x4f,0x8f,0x5e,0x5e,0x8f,0x4f,0x4f,0x8f,0x5e,0x3,0x3b,0xfe,0x75,0x86,0xce,0x72,0x72,0xce,0x86,0x86,0xce,0x72,0x4d,0x78,0x6b,0x5a,0x7,0x17, + 0x1a,0x13,0x12,0x21,0x10,0x38,0x1a,0x27,0x12,0x1d,0x13,0x1a,0x2d,0x9,0x3d,0x45,0x59,0x7,0x17,0x1a,0x13,0x12,0x21,0x10,0x3c,0xfc,0x38,0x4c,0x8a,0x5c, + 0x5c,0x8a,0x4c,0x4c,0x8a,0x5c,0x5c,0x8a,0x4c,0x0,0x0,0x0,0x0,0x3,0x0,0x89,0xff,0xea,0x5,0x29,0x5,0x2a,0x0,0x1e,0x0,0x2f,0x0,0x3d,0x0,0xb1, + 0x40,0xb,0x29,0x1,0x4,0x2,0x19,0xb,0x2,0x6,0x7,0x2,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x23,0x0,0x4,0x4,0x3,0x5b,0x5,0x8,0x2,0x3,0x3, + 0x10,0x4b,0x9,0x1,0x7,0x7,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x6,0x6,0x0,0x5b,0x1,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x4b,0xb0,0x31,0x50, + 0x58,0x40,0x27,0x0,0x4,0x4,0x3,0x5b,0x5,0x8,0x2,0x3,0x3,0x10,0x4b,0x9,0x1,0x7,0x7,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x0,0x0,0xf, + 0x4b,0x0,0x6,0x6,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x2b,0x8,0x1,0x3,0x3,0x10,0x4b,0x0,0x4,0x4,0x5,0x5b,0x0,0x5,0x5,0x10, + 0x4b,0x9,0x1,0x7,0x7,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x0,0x0,0xf,0x4b,0x0,0x6,0x6,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x59, + 0x40,0x18,0x30,0x30,0x0,0x0,0x30,0x3d,0x30,0x3c,0x36,0x34,0x2f,0x2d,0x27,0x25,0x0,0x1e,0x0,0x1c,0x26,0x25,0x35,0xa,0x7,0x17,0x2b,0x0,0x16,0x15, + 0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x11,0x34,0x36,0x33,0x33,0x4,0x16, + 0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x33,0x33,0x0,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3, + 0x85,0x21,0x1e,0x27,0x2,0x27,0x1e,0x37,0x85,0x59,0x71,0xac,0x5f,0x5f,0xac,0x71,0x58,0x7d,0x36,0x21,0x29,0x2,0x1,0xbf,0xe,0x5,0x86,0xd,0x3d,0x1c, + 0x1e,0x2,0x52,0x8,0x22,0x76,0xfc,0x8c,0x77,0x77,0x75,0x4e,0x74,0x3f,0x3f,0x74,0x4e,0x5,0x2a,0x1e,0x23,0xfb,0x4e,0x23,0x1e,0x1e,0x23,0x53,0x50,0x50, + 0x75,0xda,0x95,0x95,0xda,0x75,0x4d,0x4e,0x1,0xd2,0x23,0x1e,0xa,0xf,0xc,0x9,0xf,0xfe,0x95,0x24,0x16,0x14,0x4,0xa,0x1,0x6a,0x20,0xfd,0xfe,0xb7, + 0x99,0x99,0xb7,0x50,0x97,0x69,0x69,0x97,0x50,0x0,0x0,0x0,0x0,0x2,0x0,0x9f,0xff,0xea,0x4,0xc2,0x5,0x2a,0x0,0x2f,0x0,0x3f,0x0,0xb2,0x40,0xa, + 0x1c,0x1,0x8,0x3,0xf,0x1,0x9,0x8,0x2,0x4a,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x29,0x0,0x6,0x6,0x10,0x4b,0x4,0x1,0x0,0x0,0x5,0x5b,0xa,0x7, + 0x2,0x5,0x5,0xe,0x4b,0x0,0x8,0x8,0x3,0x5b,0x0,0x3,0x3,0x11,0x4b,0xb,0x1,0x9,0x9,0x1,0x5b,0x2,0x1,0x1,0x1,0xf,0x1,0x4c,0x1b,0x4b, + 0xb0,0x28,0x50,0x58,0x40,0x25,0xa,0x7,0x2,0x5,0x4,0x1,0x0,0x3,0x5,0x0,0x63,0x0,0x3,0x0,0x8,0x9,0x3,0x8,0x63,0x0,0x6,0x6,0x10,0x4b, + 0xb,0x1,0x9,0x9,0x1,0x5b,0x2,0x1,0x1,0x1,0xf,0x1,0x4c,0x1b,0x40,0x29,0xa,0x7,0x2,0x5,0x4,0x1,0x0,0x3,0x5,0x0,0x63,0x0,0x3,0x0, + 0x8,0x9,0x3,0x8,0x63,0x0,0x6,0x6,0x10,0x4b,0x0,0x1,0x1,0xf,0x4b,0xb,0x1,0x9,0x9,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x59,0x59,0x40, + 0x18,0x30,0x30,0x0,0x0,0x30,0x3f,0x30,0x3e,0x38,0x36,0x0,0x2f,0x0,0x2e,0x33,0x24,0x22,0x26,0x25,0x33,0x24,0xc,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14, + 0x6,0x23,0x23,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x11,0x23,0x22,0x26,0x35, + 0x34,0x36,0x33,0x33,0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x33,0x0,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33, + 0x4,0xa5,0x1d,0x1d,0x22,0x8b,0x1e,0x27,0x2,0x27,0x1e,0x3c,0x9b,0x5c,0x76,0xba,0x6a,0x6a,0xba,0x76,0xb0,0x79,0xfd,0x22,0x1d,0x1d,0x22,0xfd,0x21,0x29, + 0x2,0x29,0x21,0x8b,0xfe,0x13,0x82,0x4a,0x4a,0x82,0x53,0x53,0x78,0x3f,0x3f,0x78,0x53,0x4,0x7e,0x21,0x27,0x27,0x21,0xfc,0x49,0x23,0x1e,0x1e,0x23,0x53, + 0x4d,0x53,0x6d,0xce,0x8b,0x8b,0xce,0x6d,0x93,0x1,0xb,0x21,0x27,0x27,0x21,0x6b,0x23,0x1e,0x1e,0x23,0x6b,0xfc,0x0,0x49,0x8a,0x5f,0x5f,0x8a,0x49,0x4e, + 0x8b,0x59,0x59,0x8b,0x4e,0x0,0x0,0x0,0x0,0x2,0x0,0x94,0xff,0xea,0x4,0x43,0x3,0xb2,0x0,0x21,0x0,0x28,0x0,0x3f,0x40,0x3c,0x0,0x2,0x0,0x1, + 0x0,0x2,0x1,0x70,0x0,0x5,0x0,0x0,0x2,0x5,0x0,0x61,0x8,0x1,0x6,0x6,0x4,0x5b,0x7,0x1,0x4,0x4,0x19,0x4b,0x0,0x1,0x1,0x3,0x5b,0x0, + 0x3,0x3,0x17,0x3,0x4c,0x22,0x22,0x0,0x0,0x22,0x28,0x22,0x27,0x25,0x24,0x0,0x21,0x0,0x20,0x28,0x23,0x22,0x25,0x9,0x7,0x18,0x2b,0x0,0x16,0x16, + 0x17,0x16,0x6,0x23,0x21,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36, + 0x33,0x6,0x6,0x7,0x21,0x26,0x26,0x23,0x3,0x0,0xcc,0x6d,0x8,0x2,0x1f,0x22,0xfd,0x2c,0x7,0x9a,0x8c,0x64,0xbf,0x45,0x11,0xe,0x13,0x1f,0x9,0x7, + 0x2c,0x51,0xdc,0x70,0x91,0xcc,0x6a,0x79,0xd8,0x8a,0x7c,0xa2,0x19,0x2,0x67,0x15,0x99,0x82,0x3,0xb2,0x75,0xce,0x88,0x21,0x1d,0x95,0x99,0x2e,0x28,0x9, + 0x1d,0x1b,0x12,0x12,0x28,0x15,0x27,0x30,0x74,0xda,0x96,0x8f,0xdc,0x79,0x91,0x7d,0x6f,0x72,0x7a,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x5,0x87, + 0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x80,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x5,0x5c,0x0,0x22,0x0,0x95,0x0,0x0, + 0x0,0x2,0x1,0x82,0x14,0x0,0x0,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x5,0x76,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x83,0x10,0x0, + 0x0,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x5,0x74,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x92,0x14,0x0,0x0,0x0,0xff,0xff,0x0,0x94, + 0xff,0xea,0x4,0x43,0x5,0x53,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x93,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x5,0x53, + 0x0,0x22,0x1,0x94,0x14,0x0,0x0,0x2,0x0,0x95,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x5,0x87,0x0,0x22,0x0,0x95,0x0,0x0, + 0x0,0x2,0x1,0x95,0x28,0x0,0x0,0x0,0xff,0xff,0x0,0x94,0xff,0xea,0x4,0x43,0x4,0xe2,0x0,0x22,0x1,0x97,0xa,0x0,0x0,0x2,0x0,0x95,0x0,0x0, + 0x0,0x0,0x0,0x2,0x0,0x94,0xfe,0x28,0x4,0x43,0x3,0xb2,0x0,0x37,0x0,0x3e,0x0,0x4e,0x40,0x4b,0x2d,0x1,0x5,0x1,0x1,0x4a,0x0,0x2,0x0,0x1, + 0x0,0x2,0x1,0x70,0x0,0x7,0x0,0x0,0x2,0x7,0x0,0x61,0x0,0x3,0x0,0x4,0x3,0x4,0x5f,0xa,0x1,0x8,0x8,0x6,0x5b,0x9,0x1,0x6,0x6,0x19, + 0x4b,0x0,0x1,0x1,0x5,0x5b,0x0,0x5,0x5,0x17,0x5,0x4c,0x38,0x38,0x0,0x0,0x38,0x3e,0x38,0x3d,0x3b,0x3a,0x0,0x37,0x0,0x36,0x26,0x28,0x2c,0x23, + 0x22,0x25,0xb,0x7,0x1a,0x2b,0x0,0x16,0x16,0x17,0x16,0x6,0x23,0x21,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x7, + 0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36, + 0x36,0x33,0x6,0x6,0x7,0x21,0x26,0x26,0x23,0x3,0x0,0xcc,0x6d,0x8,0x2,0x1f,0x22,0xfd,0x2c,0x7,0x9a,0x8c,0x64,0xbf,0x45,0x11,0xe,0x23,0x16,0x9, + 0x2c,0x1b,0x3d,0x56,0x4b,0x2a,0x23,0x37,0x3a,0x18,0x1c,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x4f,0x4b,0x54,0x4e,0x91,0xcc,0x6a,0x79,0xd8,0x8a,0x7c,0xa2,0x19, + 0x2,0x67,0x15,0x99,0x82,0x3,0xb2,0x75,0xce,0x88,0x21,0x1d,0x95,0x99,0x2e,0x28,0x9,0x35,0x15,0x11,0x28,0x16,0xd,0x39,0x51,0x7a,0x35,0x24,0x27,0xa, + 0x4,0x23,0x27,0x14,0x18,0x6,0x1a,0x68,0x57,0x47,0x85,0x44,0xd,0x74,0xda,0x96,0x8f,0xdc,0x79,0x91,0x7d,0x6f,0x72,0x7a,0x0,0x0,0x0,0x1,0x0,0xbb, + 0xff,0xf6,0x4,0x5b,0x5,0x25,0x0,0x2b,0x0,0x36,0x40,0x33,0x1,0x1,0x1,0x7,0x1,0x4a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x6,0x1,0x2,0x5, + 0x1,0x3,0x4,0x2,0x3,0x61,0x0,0x1,0x1,0x7,0x5b,0x0,0x7,0x7,0x10,0x4b,0x0,0x4,0x4,0xf,0x4,0x4c,0x23,0x24,0x23,0x33,0x24,0x22,0x23,0x14, + 0x8,0x7,0x1c,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x15,0x15,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x6,0x23,0x23, + 0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x35,0x34,0x36,0x33,0x32,0x17,0x4,0x5b,0x4,0xe,0x26,0x9,0xd,0x7f,0x6e,0xca,0x1,0x5a, + 0x22,0x1d,0x1d,0x22,0xfe,0xa6,0x21,0x29,0x2,0x29,0x21,0xc6,0x22,0x1d,0x1d,0x22,0xc6,0xb9,0xa7,0x86,0x84,0x4,0xdf,0x2e,0x8,0x14,0x38,0x5,0x31,0xd9, + 0x6e,0x21,0x27,0x27,0x21,0xfd,0x7b,0x23,0x1e,0x1e,0x23,0x2,0x85,0x21,0x27,0x27,0x21,0x7b,0xa5,0xb9,0x33,0x0,0x0,0x2,0x0,0x8b,0xfe,0x66,0x4,0xc, + 0x3,0xb2,0x0,0x2b,0x0,0x3b,0x0,0xb8,0x40,0xb,0x21,0x2,0x2,0x6,0x7,0x14,0x1,0x1,0x3,0x2,0x4a,0x4b,0xb0,0x24,0x50,0x58,0x40,0x2a,0x0,0x2, + 0x4,0x3,0x4,0x2,0x3,0x70,0x9,0x1,0x7,0x7,0x0,0x5b,0x8,0x5,0x2,0x0,0x0,0x11,0x4b,0x0,0x6,0x6,0x4,0x5b,0x0,0x4,0x4,0xf,0x4b,0x0, + 0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x13,0x1,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x28,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x6,0x0,0x4, + 0x2,0x6,0x4,0x63,0x9,0x1,0x7,0x7,0x0,0x5b,0x8,0x5,0x2,0x0,0x0,0x11,0x4b,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x13,0x1,0x4c,0x1b,0x40, + 0x2c,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x6,0x0,0x4,0x2,0x6,0x4,0x63,0x0,0x0,0x0,0x11,0x4b,0x9,0x1,0x7,0x7,0x5,0x5b,0x8,0x1, + 0x5,0x5,0x19,0x4b,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x13,0x1,0x4c,0x59,0x59,0x40,0x16,0x2c,0x2c,0x0,0x0,0x2c,0x3b,0x2c,0x3a,0x34,0x32,0x0, + 0x2b,0x0,0x2a,0x24,0x24,0x17,0x26,0x35,0xa,0x7,0x19,0x2b,0x0,0x16,0x17,0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x14,0x6,0x6,0x23,0x22,0x26, + 0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x35,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14, + 0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x2,0x9b,0xa6,0x3f,0x1e,0x27,0x2,0x27,0x1e,0x65,0xc0,0x87,0x60,0xc4,0x55,0x27,0x8,0x12,0x27, + 0xb,0xb,0x4e,0xac,0x4f,0x8a,0x8c,0x7c,0xc1,0x7c,0xc3,0x6f,0x6f,0xc3,0x7c,0x4f,0x81,0x44,0x44,0x81,0x59,0x59,0x8b,0x4f,0x4f,0x8b,0x59,0x3,0xb2,0x58, + 0x52,0x5d,0x23,0x1e,0x1e,0x23,0xfc,0x7d,0x77,0xab,0x5a,0x21,0x1f,0xe,0x27,0x10,0x18,0x37,0x4,0x1c,0x20,0x83,0x72,0xc9,0x9c,0x6f,0xd0,0x8c,0x8c,0xd0, + 0x6f,0x94,0x4f,0x8d,0x5b,0x5b,0x8d,0x4f,0x4a,0x8d,0x60,0x60,0x8d,0x4a,0xff,0xff,0x0,0x8b,0xfe,0x66,0x4,0xc,0x5,0x5c,0x0,0x22,0x0,0xa0,0x0,0x0, + 0x0,0x2,0x1,0x82,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0x8b,0xfe,0x66,0x4,0xc,0x5,0x74,0x0,0x22,0x0,0xa0,0x0,0x0,0x0,0x2,0x1,0x92,0xa,0x0, + 0x0,0x0,0x0,0x3,0x0,0x8b,0xfe,0x66,0x4,0xc,0x5,0xa4,0x0,0x10,0x0,0x3c,0x0,0x4c,0x0,0xe4,0x40,0x10,0xa,0x1,0x2,0x1,0x0,0x32,0x13,0x2, + 0x8,0x9,0x25,0x1,0x3,0x5,0x3,0x4a,0x4b,0xb0,0x24,0x50,0x58,0x40,0x33,0x0,0x4,0x6,0x5,0x6,0x4,0x5,0x70,0x0,0x0,0xa,0x1,0x1,0x2,0x0, + 0x1,0x63,0xc,0x1,0x9,0x9,0x2,0x5b,0xb,0x7,0x2,0x2,0x2,0x11,0x4b,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0xf,0x4b,0x0,0x5,0x5,0x3,0x5b, + 0x0,0x3,0x3,0x13,0x3,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x31,0x0,0x4,0x6,0x5,0x6,0x4,0x5,0x70,0x0,0x0,0xa,0x1,0x1,0x2,0x0,0x1, + 0x63,0x0,0x8,0x0,0x6,0x4,0x8,0x6,0x63,0xc,0x1,0x9,0x9,0x2,0x5b,0xb,0x7,0x2,0x2,0x2,0x11,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3, + 0x13,0x3,0x4c,0x1b,0x40,0x35,0x0,0x4,0x6,0x5,0x6,0x4,0x5,0x70,0x0,0x0,0xa,0x1,0x1,0x7,0x0,0x1,0x63,0x0,0x8,0x0,0x6,0x4,0x8,0x6, + 0x63,0x0,0x2,0x2,0x11,0x4b,0xc,0x1,0x9,0x9,0x7,0x5b,0xb,0x1,0x7,0x7,0x19,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x13,0x3,0x4c,0x59, + 0x59,0x40,0x22,0x3d,0x3d,0x11,0x11,0x0,0x0,0x3d,0x4c,0x3d,0x4b,0x45,0x43,0x11,0x3c,0x11,0x3b,0x35,0x33,0x2f,0x2d,0x29,0x28,0x21,0x1f,0x19,0x16,0x0, + 0x10,0x0,0xe,0x15,0xd,0x7,0x15,0x2b,0x0,0x35,0x34,0x37,0x13,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x23,0x16,0x16,0x17,0x35,0x34, + 0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x35,0x6, + 0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x2,0xf,0x6,0x75,0xf,0x2c, + 0xb,0x6,0x34,0x2,0x3f,0x8,0x22,0x74,0x70,0xa6,0x3f,0x1e,0x27,0x2,0x27,0x1e,0x65,0xc0,0x87,0x60,0xc4,0x55,0x27,0x8,0x12,0x27,0xb,0xb,0x4e,0xac, + 0x4f,0x8a,0x8c,0x7c,0xc1,0x7c,0xc3,0x6f,0x6f,0xc3,0x7c,0x4f,0x81,0x44,0x44,0x81,0x59,0x59,0x8b,0x4f,0x4f,0x8b,0x59,0x4,0x28,0x1a,0xc,0xd,0x1,0x23, + 0x26,0x1,0x7,0x25,0x4,0xc,0xfe,0xe1,0x20,0x76,0x58,0x52,0x5d,0x23,0x1e,0x1e,0x23,0xfc,0x7d,0x77,0xab,0x5a,0x21,0x1f,0xe,0x27,0x10,0x18,0x37,0x4, + 0x1c,0x20,0x83,0x72,0xc9,0x9c,0x6f,0xd0,0x8c,0x8c,0xd0,0x6f,0x94,0x4f,0x8d,0x5b,0x5b,0x8d,0x4f,0x4a,0x8d,0x60,0x60,0x8d,0x4a,0x0,0xff,0xff,0x0,0x8b, + 0xfe,0x66,0x4,0xc,0x5,0x53,0x0,0x22,0x0,0xa0,0x0,0x0,0x0,0x2,0x1,0x94,0xa,0x0,0x0,0x0,0x0,0x1,0x0,0xca,0xff,0xf6,0x4,0x14,0x5,0x2a, + 0x0,0x26,0x0,0x2d,0x40,0x2a,0x3,0x1,0x1,0x2,0x1,0x4a,0x5,0x1,0x4,0x4,0x10,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x3,0x1, + 0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x0,0x26,0x0,0x24,0x36,0x25,0x35,0x25,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x11,0x36,0x36,0x33,0x32,0x16,0x15,0x11, + 0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x1,0x3f, + 0x21,0x45,0xcd,0x65,0x97,0xa6,0x21,0x29,0x2,0x29,0x21,0x59,0x5d,0x56,0xa7,0x6b,0x21,0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x5,0x2a,0x1e,0x23,0xfd,0xe7, + 0x66,0x7c,0xae,0x98,0xfd,0xcb,0x23,0x1e,0x1e,0x23,0x2,0x26,0x5a,0x67,0x6d,0xbb,0x6e,0xfe,0xaf,0x23,0x1e,0x1e,0x23,0x4,0xb2,0x23,0x1e,0x0,0x0,0x0, + 0x0,0x1,0x0,0x14,0xff,0xf6,0x4,0x0,0x5,0x2a,0x0,0x38,0x0,0x68,0xb5,0x35,0x1,0x0,0x1,0x1,0x4a,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x23,0x0,0x5, + 0x5,0x10,0x4b,0x7,0x1,0x3,0x3,0x4,0x5b,0x6,0x1,0x4,0x4,0xe,0x4b,0x0,0x1,0x1,0x8,0x5b,0x9,0x1,0x8,0x8,0x11,0x4b,0x2,0x1,0x0,0x0, + 0xf,0x0,0x4c,0x1b,0x40,0x1f,0x6,0x1,0x4,0x7,0x1,0x3,0x8,0x4,0x3,0x63,0x9,0x1,0x8,0x0,0x1,0x0,0x8,0x1,0x63,0x0,0x5,0x5,0x10,0x4b, + 0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x59,0x40,0x11,0x0,0x0,0x0,0x38,0x0,0x37,0x24,0x23,0x33,0x24,0x23,0x36,0x25,0x35,0xa,0x7,0x1c,0x2b,0x0,0x16, + 0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35, + 0x34,0x36,0x33,0x33,0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x36,0x36,0x33,0x3,0x60,0xa0,0x21,0x29, + 0x2,0x29,0x21,0x54,0x58,0x4e,0x9a,0x62,0x21,0x29,0x2,0x29,0x21,0x8b,0x22,0x1d,0x1d,0x22,0x8b,0x21,0x29,0x2,0x29,0x21,0xfd,0x22,0x1d,0x1d,0x22,0xfd, + 0x42,0xb9,0x5e,0x3,0x76,0xae,0x98,0xfe,0x7,0x23,0x1e,0x1e,0x23,0x1,0xea,0x5a,0x67,0x68,0xb2,0x68,0xfe,0xd7,0x23,0x1e,0x1e,0x23,0x3,0xb7,0x21,0x27, + 0x27,0x21,0x6b,0x23,0x1e,0x1e,0x23,0x6b,0x21,0x27,0x27,0x21,0xfe,0xba,0x5e,0x70,0xff,0xff,0x0,0xca,0xff,0xf6,0x4,0x14,0x6,0xe6,0x0,0x27,0x1,0x92, + 0xff,0xf6,0x1,0x72,0x1,0x2,0x0,0xa5,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0x72,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xbb,0x0,0x0,0x4,0x49, + 0x5,0x53,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x94,0x4,0x0,0x0,0x0,0x0,0x1,0x0,0xbb,0x0,0x0,0x4,0x49,0x3,0x9c,0x0,0x1b,0x0,0x27, + 0x40,0x24,0x0,0x3,0x3,0x4,0x59,0x5,0x1,0x4,0x4,0x11,0x4b,0x2,0x1,0x0,0x0,0x1,0x59,0x0,0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x0,0x1b,0x0, + 0x19,0x21,0x24,0x34,0x23,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x11,0x23, + 0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x2,0xac,0x1d,0x1,0x41,0x22,0x1d,0x1d,0x22,0xfc,0xf0,0x22,0x1d,0x1d,0x22,0x1,0x39,0xfd,0x22,0x1d,0x1d,0x22,0x1, + 0x54,0x3,0x9c,0x1f,0x25,0xfd,0x38,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x2,0x7c,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0xbb,0x0,0x0, + 0x4,0x49,0x5,0x87,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x80,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xbb,0x0,0x0,0x4,0x49,0x5,0x5c,0x0,0x22, + 0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x82,0xf6,0x0,0x0,0x0,0xff,0xff,0x0,0xbb,0x0,0x0,0x4,0x49,0x5,0x74,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2, + 0x1,0x92,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xbb,0x0,0x0,0x4,0x49,0x5,0x53,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x93,0x0,0x0,0x0,0x0, + 0xff,0xff,0x0,0xbb,0x0,0x0,0x4,0x49,0x5,0x53,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x94,0x4,0x0,0x0,0x0,0xff,0xff,0x0,0xbb,0x0,0x0, + 0x4,0x49,0x5,0x87,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x95,0xda,0x0,0x0,0x0,0x0,0x4,0x0,0xde,0xfe,0x66,0x3,0xee,0x5,0x53,0x0,0xd, + 0x0,0x1b,0x0,0x2b,0x0,0x48,0x0,0x85,0xb5,0x37,0x1,0x6,0x8,0x1,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x2c,0x0,0x7,0x4,0x8,0x4,0x7,0x8,0x70, + 0x2,0x1,0x0,0x0,0x1,0x5b,0x3,0x1,0x1,0x1,0x10,0x4b,0xb,0x9,0xa,0x3,0x5,0x5,0x11,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x8,0x8,0x6,0x5b, + 0x0,0x6,0x6,0x13,0x6,0x4c,0x1b,0x40,0x2a,0x0,0x7,0x4,0x8,0x4,0x7,0x8,0x70,0x3,0x1,0x1,0x2,0x1,0x0,0x5,0x1,0x0,0x63,0xb,0x9,0xa, + 0x3,0x5,0x5,0x11,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0x13,0x6,0x4c,0x59,0x40,0x1a,0x2c,0x2c,0x1c,0x1c,0x2c,0x48, + 0x2c,0x46,0x41,0x3f,0x3b,0x3a,0x33,0x31,0x1c,0x2b,0x1c,0x29,0x39,0x25,0x25,0x25,0x21,0xc,0x7,0x19,0x2b,0x0,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36, + 0x33,0x32,0x16,0x15,0x15,0x4,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x4,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35, + 0x11,0x34,0x36,0x33,0x33,0x20,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x11, + 0x34,0x36,0x33,0x33,0x1,0x9c,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x2,0x52,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0xfd,0x79,0x21,0x21,0x29,0x2, + 0x29,0x21,0x21,0x29,0x2,0x2,0x7b,0x21,0x8d,0x84,0x37,0x80,0x30,0x27,0xb,0x15,0x24,0xc,0x10,0x27,0x5c,0x2c,0x3f,0x3b,0x21,0x29,0x2,0x4,0x6c,0x1d, + 0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0xea,0x1e,0x23,0xfc,0xd2,0x23,0x1e,0x1e,0x23,0x3,0x2e,0x23, + 0x1e,0x1e,0x23,0xfc,0x14,0x86,0x8d,0x1a,0x18,0x14,0x21,0x11,0x1b,0x31,0x7,0x13,0x16,0x4a,0x53,0x3,0xce,0x23,0x1e,0x0,0xff,0xff,0x0,0xbb,0x0,0x0, + 0x4,0x49,0x4,0xe2,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x97,0xf6,0x0,0x0,0x0,0x0,0x2,0x0,0xbb,0xfe,0x28,0x4,0x49,0x5,0x53,0x0,0xd, + 0x0,0x43,0x0,0xbb,0x4b,0xb0,0x19,0x50,0x58,0x40,0x2b,0x4,0x1,0x3,0x0,0x5,0x3,0x5,0x5f,0xb,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x10,0x4b, + 0x0,0x8,0x8,0x9,0x59,0x0,0x9,0x9,0x11,0x4b,0xc,0xa,0x2,0x7,0x7,0x2,0x59,0x6,0x1,0x2,0x2,0xf,0x2,0x4c,0x1b,0x4b,0xb0,0x1b,0x50,0x58, + 0x40,0x29,0x0,0x0,0xb,0x1,0x1,0x9,0x0,0x1,0x63,0x4,0x1,0x3,0x0,0x5,0x3,0x5,0x5f,0x0,0x8,0x8,0x9,0x59,0x0,0x9,0x9,0x11,0x4b,0xc, + 0xa,0x2,0x7,0x7,0x2,0x59,0x6,0x1,0x2,0x2,0xf,0x2,0x4c,0x1b,0x40,0x30,0x0,0x4,0x2,0x3,0x2,0x4,0x3,0x70,0x0,0x0,0xb,0x1,0x1,0x9, + 0x0,0x1,0x63,0x0,0x3,0x0,0x5,0x3,0x5,0x5f,0x0,0x8,0x8,0x9,0x59,0x0,0x9,0x9,0x11,0x4b,0xc,0xa,0x2,0x7,0x7,0x2,0x59,0x6,0x1,0x2, + 0x2,0xf,0x2,0x4c,0x59,0x59,0x40,0x20,0xe,0xe,0x0,0x0,0xe,0x43,0xe,0x42,0x3f,0x3c,0x38,0x36,0x35,0x33,0x2f,0x2d,0x28,0x26,0x1f,0x1c,0x1b,0x19, + 0x14,0x12,0x0,0xd,0x0,0xc,0x25,0xd,0x7,0x15,0x2b,0x0,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x14,0x6,0x23,0x0,0x16,0x15,0x14,0x6, + 0x23,0x21,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x21,0x22,0x26, + 0x35,0x34,0x36,0x33,0x21,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x32,0x16,0x15,0x11,0x21,0x2,0x33,0x28,0x28,0x37,0x37,0x28,0x28,0x37,0x1,0xc2, + 0x1d,0x1d,0x22,0xfe,0xbf,0x59,0x4d,0x2a,0x23,0x34,0x3d,0x8,0x3,0x1e,0x9,0x2,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x50,0x4c,0xfe,0xd7,0x22,0x1d,0x1d,0x22, + 0x1,0x39,0xfd,0x22,0x1d,0x1d,0x22,0x1,0x54,0x22,0x1d,0x1,0x41,0x4,0x4f,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0x24,0x1d,0xfc,0x41,0x21,0x27,0x27, + 0x21,0x53,0x7a,0x37,0x23,0x26,0x11,0x2,0x36,0x12,0x7,0x16,0x19,0x6,0x1a,0x68,0x57,0x49,0x8a,0x46,0x21,0x27,0x27,0x21,0x2,0x7c,0x21,0x27,0x27,0x21, + 0x1f,0x25,0xfd,0x38,0xff,0xff,0x0,0xbb,0x0,0x0,0x4,0x49,0x5,0x2d,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x9a,0xec,0x0,0x0,0x0,0xff,0xff, + 0x0,0xbe,0xfe,0x66,0x3,0x87,0x5,0x53,0x0,0x22,0x0,0xb5,0x0,0x0,0x0,0x3,0x1,0x94,0x0,0xc2,0x0,0x0,0x0,0x1,0x0,0xbe,0xfe,0x66,0x3,0x87, + 0x3,0x9c,0x0,0x21,0x0,0x34,0x40,0x31,0xb,0x1,0x2,0x1,0x1,0x4a,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70,0x0,0x3,0x3,0x4,0x59,0x5,0x1,0x4, + 0x4,0x11,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x0,0x0,0x0,0x21,0x0,0x1e,0x23,0x24,0x17,0x25,0x6,0x7,0x18,0x2b,0x0,0x16, + 0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33, + 0x21,0x33,0x3,0x6a,0x1d,0x9d,0xaa,0x53,0xc0,0x4e,0x21,0xd,0x18,0x22,0x11,0xe,0x45,0x94,0x43,0x62,0x4f,0xfe,0x59,0x22,0x1d,0x1d,0x22,0x1,0xd0,0x2e, + 0x3,0x9c,0x1f,0x25,0xfc,0x6f,0xb0,0xb1,0x3f,0x31,0x14,0x20,0x13,0x1a,0x2e,0xa,0x2d,0x36,0x6a,0x72,0x3,0x38,0x21,0x27,0x27,0x21,0x0,0x0,0xff,0xff, + 0x0,0xbe,0xfe,0x66,0x4,0x13,0x5,0x74,0x0,0x22,0x1,0x92,0x6e,0x0,0x0,0x2,0x0,0xb5,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0xe8,0xff,0xf0,0x4,0x38, + 0x5,0x2a,0x0,0x25,0x0,0x24,0x40,0x21,0x24,0x1a,0x9,0x8,0x4,0x0,0x3,0x1,0x4a,0x0,0x2,0x2,0x10,0x4b,0x0,0x3,0x3,0x19,0x4b,0x1,0x1,0x0, + 0x0,0x17,0x0,0x4c,0x25,0x35,0x36,0x24,0x4,0x7,0x18,0x2b,0x24,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x7,0x15,0x14,0x6,0x23,0x23,0x22,0x26,0x35, + 0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x1,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x1,0x4,0x38,0x2a,0x24,0x18,0x16,0x12,0xfe,0x88,0xb4, + 0x21,0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x29,0x21,0x2,0x11,0x15,0x1a,0x1a,0x1e,0x2a,0x15,0xfe,0x98,0x1,0x81,0x49,0x12,0x1b,0x17,0x15,0x13,0x1,0x9e, + 0x9e,0xcc,0x23,0x1e,0x1e,0x23,0x4,0xb2,0x23,0x1e,0x1e,0x23,0xfc,0xdc,0x1,0xd7,0x12,0x12,0x19,0x1c,0x14,0x12,0xfe,0xc3,0xfe,0x5b,0x0,0x0,0xff,0xff, + 0x0,0xe8,0xfd,0xf2,0x4,0x38,0x5,0x2a,0x0,0x22,0x0,0xb7,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xd2,0x0,0x0,0x0,0x1,0x0,0xb1,0x0,0x0,0x4,0x3f, + 0x5,0x20,0x0,0x1c,0x0,0x27,0x40,0x24,0x0,0x2,0x2,0x3,0x59,0x0,0x3,0x3,0x10,0x4b,0x5,0x4,0x2,0x1,0x1,0x0,0x59,0x0,0x0,0x0,0xf,0x0, + 0x4c,0x0,0x0,0x0,0x1c,0x0,0x1b,0x44,0x21,0x24,0x34,0x6,0x7,0x18,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x11, + 0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x33,0x32,0x16,0x15,0x11,0x21,0x4,0x22,0x1d,0x1d,0x22,0xfc,0xf0,0x22,0x1d,0x1d,0x22,0x1,0x39,0xfe,0xef,0x22, + 0x1d,0x1d,0x22,0x1,0x4e,0x1a,0x22,0x1d,0x1,0x41,0x90,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x4,0x0,0x21,0x27,0x27,0x21,0x1f,0x25,0xfb,0xb4,0x0, + 0xff,0xff,0x0,0xb1,0x0,0x0,0x4,0x3f,0x6,0xf9,0x0,0x27,0x1,0x80,0xff,0xe0,0x1,0x72,0x1,0x2,0x0,0xb9,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8, + 0x1,0x72,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x93,0x0,0x0,0x4,0x68,0x5,0x20,0x0,0x22,0x0,0xb9,0xe2,0x0,0x0,0x3,0x1,0x81,0x2,0x5f,0x0,0x0, + 0xff,0xff,0x0,0xb1,0xfd,0xf2,0x4,0x3f,0x5,0x20,0x0,0x22,0x0,0xb9,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xcc,0x0,0x0,0xff,0xff,0x0,0x93,0x0,0x0, + 0x4,0x2d,0x5,0x20,0x0,0x22,0x0,0xb9,0xe2,0x0,0x1,0x7,0x1,0x94,0x1,0x68,0xfe,0xc,0x0,0x9,0xb1,0x1,0x1,0xb8,0xfe,0xc,0xb0,0x33,0x2b,0x0, + 0x0,0x1,0x0,0xb1,0x0,0x0,0x4,0x3f,0x5,0x20,0x0,0x32,0x0,0x3f,0x40,0x3c,0x30,0x26,0x18,0xe,0x4,0x2,0x5,0x1,0x4a,0x0,0x2,0x5,0x1,0x5, + 0x2,0x1,0x70,0x0,0x3,0x3,0x4,0x59,0x0,0x4,0x4,0x10,0x4b,0x0,0x5,0x5,0x19,0x4b,0x7,0x6,0x2,0x1,0x1,0x0,0x5a,0x0,0x0,0x0,0xf,0x0, + 0x4c,0x0,0x0,0x0,0x32,0x0,0x31,0x25,0x44,0x27,0x23,0x24,0x34,0x8,0x7,0x1a,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33, + 0x21,0x11,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x33,0x32,0x16,0x15,0x11,0x37,0x36,0x33,0x32, + 0x17,0x16,0x15,0x14,0x7,0x7,0x11,0x21,0x4,0x22,0x1d,0x1d,0x22,0xfc,0xf0,0x22,0x1d,0x1d,0x22,0x1,0x39,0xaf,0x18,0x10,0x1a,0x19,0x12,0x20,0xfc,0xfe, + 0xef,0x22,0x1d,0x1d,0x22,0x1,0x4e,0x1a,0x22,0x1d,0xa7,0x18,0x10,0x1a,0x19,0x12,0x20,0xf4,0x1,0x41,0x90,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x1, + 0x9d,0x77,0x10,0x25,0x1b,0x12,0x19,0x15,0xab,0x1,0xbf,0x21,0x27,0x27,0x21,0x1f,0x25,0xfe,0x5b,0x72,0x10,0x25,0x1b,0x12,0x19,0x15,0xa6,0xfd,0xfd,0x0, + 0x0,0x0,0x0,0x1,0x0,0x79,0xff,0xf6,0x4,0x55,0x3,0xb2,0x0,0x3c,0x0,0x56,0xb6,0x3a,0x34,0x2,0x0,0x1,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40, + 0x16,0x3,0x1,0x1,0x1,0x5,0x5b,0x8,0x7,0x6,0x3,0x5,0x5,0x11,0x4b,0x4,0x2,0x2,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40,0x1a,0x0,0x5,0x5,0x11, + 0x4b,0x3,0x1,0x1,0x1,0x6,0x5b,0x8,0x7,0x2,0x6,0x6,0x19,0x4b,0x4,0x2,0x2,0x0,0x0,0xf,0x0,0x4c,0x59,0x40,0x10,0x0,0x0,0x0,0x3c,0x0, + 0x3b,0x25,0x35,0x36,0x25,0x36,0x25,0x36,0x9,0x7,0x1b,0x2b,0x0,0x16,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x26,0x23,0x22,0x6, + 0x6,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33, + 0x33,0x32,0x16,0x15,0x15,0x36,0x36,0x33,0x32,0x16,0x17,0x36,0x33,0x3,0xc1,0x5d,0x37,0x21,0x29,0x2,0x29,0x21,0x2d,0x32,0x2f,0x50,0x2f,0x21,0x29,0x2, + 0x29,0x21,0x2d,0x32,0x2f,0x50,0x2f,0x21,0x29,0x2,0x29,0x21,0x1b,0x25,0x2,0x25,0x1b,0x2b,0x78,0x46,0x44,0x66,0x12,0x59,0x8d,0x3,0xb2,0x3b,0x79,0x58, + 0xfd,0x91,0x23,0x1e,0x1e,0x23,0x2,0x5d,0x45,0x45,0x57,0x9b,0x63,0xfe,0x6e,0x23,0x1e,0x1e,0x23,0x2,0x5d,0x45,0x45,0x57,0x9b,0x63,0xfe,0x6e,0x23,0x1e, + 0x1e,0x23,0x3,0x2e,0x23,0x1e,0x1e,0x23,0x70,0x5e,0x5f,0x5c,0x59,0xb5,0x0,0x1,0x0,0xca,0xff,0xf6,0x4,0x14,0x3,0xb2,0x0,0x26,0x0,0x4c,0xb5,0x23, + 0x1,0x0,0x1,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x13,0x0,0x1,0x1,0x3,0x5b,0x5,0x4,0x2,0x3,0x3,0x11,0x4b,0x2,0x1,0x0,0x0,0xf,0x0, + 0x4c,0x1b,0x40,0x17,0x0,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0x4,0x5b,0x5,0x1,0x4,0x4,0x19,0x4b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x59,0x40,0xd, + 0x0,0x0,0x0,0x26,0x0,0x25,0x35,0x36,0x25,0x35,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x26,0x23,0x22, + 0x6,0x6,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x36,0x36,0x33,0x3,0x6e,0xa6,0x21,0x29,0x2,0x29, + 0x21,0x59,0x5d,0x56,0xa7,0x6b,0x21,0x29,0x2,0x29,0x21,0x1e,0x27,0x2,0x27,0x1e,0x44,0xd2,0x6b,0x3,0xb2,0xae,0x98,0xfd,0xcb,0x23,0x1e,0x1e,0x23,0x2, + 0x26,0x5a,0x67,0x6d,0xbb,0x6e,0xfe,0xaf,0x23,0x1e,0x1e,0x23,0x3,0x2e,0x23,0x1e,0x1e,0x23,0xa3,0x69,0x87,0x0,0xff,0xff,0x0,0xca,0xff,0xf6,0x4,0x14, + 0x5,0x87,0x0,0x22,0x0,0xc0,0x0,0x0,0x0,0x2,0x1,0x80,0xfe,0x0,0x0,0x0,0xff,0xff,0x0,0xca,0xff,0xf6,0x4,0x14,0x5,0x76,0x0,0x22,0x0,0xc0, + 0x0,0x0,0x0,0x2,0x1,0x83,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0xca,0xfd,0xf2,0x4,0x14,0x3,0xb2,0x0,0x22,0x0,0xc0,0x0,0x0,0x0,0x3,0x1,0x7e, + 0x4,0xc8,0x0,0x0,0x0,0x1,0x0,0xca,0xfe,0x66,0x4,0x14,0x3,0xb2,0x0,0x32,0x0,0x75,0x40,0xa,0x2f,0x1,0x4,0x3,0xb,0x1,0x0,0x2,0x2,0x4a, + 0x4b,0xb0,0x28,0x50,0x58,0x40,0x24,0x0,0x1,0x4,0x2,0x4,0x1,0x2,0x70,0x0,0x3,0x3,0x5,0x5b,0x7,0x6,0x2,0x5,0x5,0x11,0x4b,0x0,0x4,0x4, + 0xf,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x1b,0x40,0x28,0x0,0x1,0x4,0x2,0x4,0x1,0x2,0x70,0x0,0x5,0x5,0x11,0x4b,0x0, + 0x3,0x3,0x6,0x5b,0x7,0x1,0x6,0x6,0x19,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x59,0x40,0xf,0x0, + 0x0,0x0,0x32,0x0,0x31,0x35,0x36,0x25,0x23,0x17,0x25,0x8,0x7,0x1a,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36, + 0x33,0x32,0x17,0x16,0x33,0x32,0x36,0x35,0x11,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32, + 0x16,0x15,0x15,0x36,0x36,0x33,0x3,0x6e,0xa6,0x8d,0x84,0x3a,0x78,0x35,0x27,0xb,0x15,0x22,0xf,0xd,0x60,0x51,0x3f,0x3b,0x59,0x5d,0x56,0xa7,0x6b,0x21, + 0x29,0x2,0x29,0x21,0x1e,0x27,0x2,0x27,0x1e,0x44,0xd2,0x6b,0x3,0xb2,0xae,0x98,0xfd,0xd,0x86,0x8d,0x1b,0x17,0x11,0x23,0x10,0x1b,0x2f,0x6,0x28,0x4a, + 0x53,0x2,0xc8,0x5a,0x67,0x6d,0xbb,0x6e,0xfe,0xaf,0x23,0x1e,0x1e,0x23,0x3,0x2e,0x23,0x1e,0x1e,0x23,0xa3,0x69,0x87,0x0,0xff,0xff,0x0,0xca,0xff,0xf6, + 0x4,0x14,0x5,0x2d,0x0,0x22,0x0,0xc0,0x0,0x0,0x0,0x2,0x1,0x9a,0xa,0x0,0x0,0x0,0x0,0x2,0x0,0x86,0xff,0xea,0x4,0x46,0x3,0xb2,0x0,0xf, + 0x0,0x1f,0x0,0x2c,0x40,0x29,0x5,0x1,0x3,0x3,0x1,0x5b,0x4,0x1,0x1,0x1,0x19,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x10, + 0x10,0x0,0x0,0x10,0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0x6,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35, + 0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x2,0xee,0xdb,0x7d,0x7d,0xdb,0x88,0x88,0xdb,0x7d,0x7d, + 0xdb,0x88,0x61,0x94,0x51,0x51,0x94,0x61,0x61,0x94,0x51,0x51,0x94,0x61,0x3,0xb2,0x7c,0xdd,0x8b,0x8b,0xdd,0x7c,0x7c,0xdd,0x8b,0x8b,0xdd,0x7c,0x94,0x55, + 0x99,0x62,0x62,0x99,0x55,0x55,0x99,0x62,0x62,0x99,0x55,0x0,0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x46,0x5,0x87,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2, + 0x1,0x80,0xea,0x0,0x0,0x0,0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x46,0x5,0x5c,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x82,0x0,0x0,0x0,0x0, + 0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x46,0x5,0x74,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x92,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x86,0xff,0xea, + 0x4,0x46,0x5,0x53,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x93,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x46,0x5,0x87,0x0,0x22, + 0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x95,0x16,0x0,0x0,0x0,0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x4f,0x5,0x76,0x0,0x22,0x1,0x96,0x0,0x0,0x0,0x2, + 0x0,0xc6,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x46,0x4,0xe2,0x0,0x22,0x1,0x97,0x0,0x0,0x0,0x2,0x0,0xc6,0x0,0x0,0x0,0x0, + 0x0,0x3,0x0,0x54,0xff,0xcc,0x4,0x78,0x3,0xd0,0x0,0x27,0x0,0x30,0x0,0x39,0x0,0x6a,0x40,0x13,0x22,0x1,0x4,0x2,0x33,0x32,0x2a,0x29,0x18,0x4, + 0x6,0x5,0x4,0xe,0x1,0x0,0x5,0x3,0x4a,0x4b,0xb0,0x22,0x50,0x58,0x40,0x1f,0x0,0x3,0x3,0x19,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19, + 0x4b,0x0,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x4b,0x0,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x1f,0x0,0x3,0x2,0x3,0x72,0x0,0x1,0x0,0x1,0x73, + 0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x40,0x9,0x27,0x25,0x24,0x2c,0x24,0x2a, + 0x6,0x7,0x1a,0x2b,0x0,0x15,0x14,0x7,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26, + 0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x37,0x36,0x33,0x32,0x17,0x0,0x17,0x1,0x26,0x23,0x22,0x6,0x6,0x15,0x24,0x27,0x1,0x16,0x33,0x32,0x36, + 0x36,0x35,0x4,0x78,0x19,0x6d,0x28,0x2c,0x7d,0xdb,0x88,0x56,0x98,0x3e,0x6d,0x19,0x14,0x16,0x1c,0x1a,0x18,0x6e,0x28,0x2c,0x7d,0xdb,0x88,0x56,0x98,0x3e, + 0x6c,0x19,0x14,0x17,0x1c,0xfc,0xc2,0x2a,0x1,0xda,0x50,0x6e,0x61,0x94,0x51,0x2,0x8c,0x2a,0xfe,0x25,0x52,0x6d,0x61,0x94,0x51,0x3,0x98,0x16,0x16,0x18, + 0x69,0x3c,0x91,0x50,0x8b,0xdd,0x7c,0x33,0x2f,0x69,0x17,0x1c,0x1c,0x16,0x15,0x18,0x6a,0x3c,0x91,0x50,0x8b,0xdd,0x7c,0x33,0x2f,0x69,0x17,0x1c,0xfd,0xb7, + 0x4e,0x1,0xca,0x37,0x55,0x99,0x62,0x63,0x4e,0xfe,0x36,0x37,0x55,0x99,0x62,0x0,0x0,0x0,0xff,0xff,0x0,0x86,0xff,0xea,0x4,0x46,0x5,0x2d,0x0,0x22, + 0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x9a,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x46,0xff,0xea,0x4,0x80,0x3,0xb2,0x0,0x26,0x0,0x2d,0x0,0x39,0x0,0x58, + 0x40,0x55,0x23,0x1,0x8,0x5,0x19,0x1,0x3,0x1,0x2,0x4a,0x0,0x2,0x0,0x1,0x0,0x2,0x1,0x70,0x0,0x7,0x0,0x0,0x2,0x7,0x0,0x61,0xd,0xa, + 0xc,0x3,0x8,0x8,0x5,0x5b,0xb,0x6,0x2,0x5,0x5,0x19,0x4b,0x9,0x1,0x1,0x1,0x3,0x5b,0x4,0x1,0x3,0x3,0x17,0x3,0x4c,0x2e,0x2e,0x27,0x27, + 0x0,0x0,0x2e,0x39,0x2e,0x38,0x34,0x32,0x27,0x2d,0x27,0x2c,0x2a,0x29,0x0,0x26,0x0,0x25,0x24,0x23,0x27,0x23,0x21,0x24,0xe,0x7,0x1a,0x2b,0x0,0x16, + 0x17,0x16,0x6,0x23,0x21,0x12,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x6,0x23,0x22,0x26,0x35,0x34, + 0x36,0x33,0x32,0x17,0x36,0x36,0x33,0x6,0x6,0x7,0x21,0x26,0x26,0x23,0x4,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x3,0xed,0x8c,0x6, + 0x1,0x1e,0x22,0xfe,0x71,0x5,0x9f,0x30,0x50,0x2a,0x11,0x16,0x1f,0x19,0x15,0x1b,0x37,0x84,0x48,0x4e,0x7a,0x28,0x4b,0x9c,0x9a,0x9e,0x9e,0x9a,0x9c,0x4b, + 0x28,0x7a,0x4e,0x45,0x4e,0xc,0x1,0x2c,0x7,0x42,0x42,0xfd,0xd8,0x4b,0x4b,0x4f,0x4f,0x4b,0x4b,0x4f,0x3,0xb2,0xe8,0xd4,0x21,0x1d,0xfe,0xc3,0x25,0x29, + 0x11,0x1f,0x19,0x19,0x1c,0x19,0x34,0x36,0x45,0x45,0x8a,0xfb,0xe9,0xe9,0xfb,0x8c,0x46,0x46,0x91,0x68,0x75,0x6c,0x71,0x3,0xa1,0xaf,0xaf,0xa1,0xa1,0xaf, + 0xaf,0xa1,0x0,0x2,0x0,0xc0,0xfe,0x72,0x4,0x41,0x3,0xb2,0x0,0x1d,0x0,0x2d,0x0,0x68,0xb6,0x1a,0x9,0x2,0x4,0x5,0x1,0x4a,0x4b,0xb0,0x28,0x50, + 0x58,0x40,0x1d,0x7,0x1,0x5,0x5,0x2,0x5b,0x6,0x3,0x2,0x2,0x2,0x11,0x4b,0x0,0x4,0x4,0x0,0x5b,0x0,0x0,0x0,0x17,0x4b,0x0,0x1,0x1,0x13, + 0x1,0x4c,0x1b,0x40,0x21,0x0,0x2,0x2,0x11,0x4b,0x7,0x1,0x5,0x5,0x3,0x5b,0x6,0x1,0x3,0x3,0x19,0x4b,0x0,0x4,0x4,0x0,0x5b,0x0,0x0,0x0, + 0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x59,0x40,0x14,0x1e,0x1e,0x0,0x0,0x1e,0x2d,0x1e,0x2c,0x26,0x24,0x0,0x1d,0x0,0x1c,0x35,0x34,0x26,0x8,0x7, + 0x17,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x27,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x36, + 0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0xf,0xc3,0x6f,0x6f,0xc3,0x7c,0xbc,0x81,0x21,0x29,0x2,0x29, + 0x21,0x1e,0x27,0x2,0x27,0x1e,0x3f,0xa6,0x62,0x63,0x8b,0x4f,0x4f,0x8b,0x59,0x59,0x81,0x44,0x44,0x81,0x59,0x3,0xb2,0x75,0xdb,0x94,0x94,0xdb,0x75,0xa5, + 0xfe,0x24,0x23,0x1e,0x1e,0x23,0x4,0xb2,0x23,0x1e,0x1e,0x23,0x5d,0x52,0x58,0x94,0x50,0x98,0x68,0x68,0x98,0x50,0x55,0x99,0x62,0x62,0x99,0x55,0x0,0x2, + 0x0,0xc0,0xfe,0x72,0x4,0x41,0x5,0x2a,0x0,0x1d,0x0,0x2d,0x0,0x3f,0x40,0x3c,0x10,0x3,0x2,0x4,0x5,0x1,0x4a,0x6,0x1,0x3,0x3,0x10,0x4b,0x7, + 0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x0,0x4,0x4,0x1,0x5b,0x0,0x1,0x1,0x17,0x4b,0x0,0x2,0x2,0x13,0x2,0x4c,0x1e,0x1e,0x0,0x0, + 0x1e,0x2d,0x1e,0x2c,0x26,0x24,0x0,0x1d,0x0,0x1b,0x34,0x26,0x25,0x8,0x7,0x17,0x2b,0x0,0x16,0x15,0x11,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6, + 0x6,0x23,0x22,0x27,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x0,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34, + 0x26,0x26,0x23,0x1,0x35,0x21,0x3e,0xa1,0x5e,0x7c,0xc3,0x6f,0x6f,0xc3,0x7c,0xbc,0x81,0x21,0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x1,0x24,0x8b,0x4f,0x4f, + 0x8b,0x59,0x59,0x81,0x44,0x44,0x81,0x59,0x5,0x2a,0x1e,0x23,0xfe,0x2a,0x4c,0x53,0x75,0xdb,0x94,0x94,0xdb,0x75,0xa5,0xfe,0x24,0x23,0x1e,0x1e,0x23,0x6, + 0x36,0x23,0x1e,0xfd,0xf4,0x50,0x98,0x68,0x68,0x98,0x50,0x55,0x99,0x62,0x62,0x99,0x55,0x0,0x0,0x2,0x0,0x8b,0xfe,0x72,0x4,0xc,0x3,0xb2,0x0,0x1d, + 0x0,0x2d,0x0,0x68,0xb6,0x13,0x2,0x2,0x4,0x5,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1d,0x7,0x1,0x5,0x5,0x0,0x5b,0x6,0x3,0x2,0x0,0x0, + 0x11,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x1b,0x40,0x21,0x0,0x0,0x0,0x11,0x4b,0x7,0x1,0x5,0x5, + 0x3,0x5b,0x6,0x1,0x3,0x3,0x19,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x59,0x40,0x14,0x1e,0x1e,0x0, + 0x0,0x1e,0x2d,0x1e,0x2c,0x26,0x24,0x0,0x1d,0x0,0x1c,0x24,0x35,0x35,0x8,0x7,0x17,0x2b,0x0,0x16,0x17,0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11, + 0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34, + 0x26,0x26,0x23,0x2,0x9b,0xa6,0x3f,0x1e,0x27,0x2,0x27,0x1e,0x21,0x29,0x2,0x29,0x21,0x81,0xbc,0x7c,0xc3,0x6f,0x6f,0xc3,0x7c,0x4f,0x81,0x44,0x44,0x81, + 0x59,0x59,0x8b,0x4f,0x4f,0x8b,0x59,0x3,0xb2,0x58,0x52,0x5d,0x23,0x1e,0x1e,0x23,0xfb,0x4e,0x23,0x1e,0x1e,0x23,0x1,0xdc,0xa5,0x75,0xdb,0x94,0x94,0xdb, + 0x75,0x94,0x55,0x99,0x62,0x62,0x99,0x55,0x50,0x98,0x68,0x68,0x98,0x50,0x0,0x1,0x1,0x33,0xff,0xf6,0x4,0x3d,0x3,0xb2,0x0,0x24,0x0,0x8e,0x4b,0xb0, + 0x17,0x50,0x58,0x40,0xa,0x3,0x1,0x0,0x3,0x21,0x1,0x2,0x0,0x2,0x4a,0x1b,0x40,0xa,0x3,0x1,0x1,0x3,0x21,0x1,0x2,0x0,0x2,0x4a,0x59,0x4b, + 0xb0,0x17,0x50,0x58,0x40,0x13,0x1,0x1,0x0,0x0,0x3,0x5b,0x5,0x4,0x2,0x3,0x3,0x11,0x4b,0x0,0x2,0x2,0xf,0x2,0x4c,0x1b,0x4b,0xb0,0x28,0x50, + 0x58,0x40,0x1a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x0,0x1,0x1,0x3,0x5b,0x5,0x4,0x2,0x3,0x3,0x11,0x4b,0x0,0x2,0x2,0xf,0x2,0x4c,0x1b, + 0x40,0x1e,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x0,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0x4,0x5b,0x5,0x1,0x4,0x4,0x19,0x4b,0x0,0x2,0x2,0xf, + 0x2,0x4c,0x59,0x59,0x40,0xd,0x0,0x0,0x0,0x24,0x0,0x23,0x35,0x36,0x22,0x27,0x6,0x7,0x18,0x2b,0x0,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22, + 0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x15,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x15,0x36,0x36,0x33,0x3,0xca,0x42, + 0x31,0x4,0x9,0x19,0x13,0xb,0xb,0x38,0x36,0x73,0xca,0x7a,0x21,0x29,0x2,0x29,0x21,0x1e,0x27,0x2,0x27,0x1e,0x57,0xee,0x85,0x3,0xb2,0x15,0x10,0x30, + 0x10,0xf,0x21,0x21,0x4,0x12,0x8c,0xed,0x8b,0xd7,0x23,0x1e,0x1e,0x23,0x3,0x2e,0x23,0x1e,0x1e,0x23,0xeb,0x93,0xa5,0x0,0x0,0x0,0xff,0xff,0x1,0x33, + 0xff,0xf6,0x4,0x3d,0x5,0x87,0x0,0x22,0x1,0x80,0x50,0x0,0x0,0x2,0x0,0xd4,0x0,0x0,0x0,0x0,0xff,0xff,0x1,0x33,0xff,0xf6,0x4,0x3d,0x5,0x76, + 0x0,0x22,0x0,0xd4,0x0,0x0,0x0,0x2,0x1,0x83,0x46,0x0,0x0,0x0,0xff,0xff,0x1,0x33,0xfd,0xf2,0x4,0x3d,0x3,0xb2,0x0,0x22,0x0,0xd4,0x0,0x0, + 0x0,0x3,0x1,0x7e,0x4,0x64,0x0,0x0,0x0,0x1,0x0,0xb2,0xff,0xea,0x4,0x18,0x3,0xb2,0x0,0x3e,0x0,0x3f,0x40,0x3c,0x3,0x1,0x1,0x0,0x1,0x4a, + 0x0,0x3,0x4,0x0,0x4,0x3,0x0,0x70,0x0,0x0,0x1,0x4,0x0,0x1,0x6e,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x1,0x1,0x5,0x5b, + 0x6,0x1,0x5,0x5,0x17,0x5,0x4c,0x0,0x0,0x0,0x3e,0x0,0x3d,0x2c,0x2a,0x27,0x26,0x20,0x1e,0x24,0x16,0x7,0x7,0x16,0x2b,0x4,0x27,0x26,0x35,0x34, + 0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x16, + 0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x1,0x90, + 0xb7,0x27,0xc,0x18,0x1e,0xf,0x10,0x52,0xbc,0x63,0x7b,0x7f,0x29,0x28,0x22,0x5c,0x48,0x62,0x7c,0x35,0x47,0x4f,0x61,0xa9,0x6c,0xe5,0xad,0x28,0xa,0x17, + 0x1f,0xa,0x14,0xa3,0xb3,0x6a,0x78,0x28,0x25,0x21,0x52,0x4b,0x5d,0x7e,0x36,0x4d,0x57,0x5a,0xb1,0x7f,0x16,0x64,0x16,0x23,0x13,0x19,0x2f,0x9,0x2e,0x30, + 0x53,0x47,0x22,0x2b,0xd,0xb,0xd,0x7,0x9,0x14,0x15,0x1c,0x66,0x52,0x5c,0x81,0x41,0x57,0x14,0x25,0x14,0x17,0x32,0x9,0x53,0x48,0x45,0x1f,0x27,0xc, + 0xb,0xb,0x7,0x8,0x13,0x14,0x1d,0x6b,0x59,0x5a,0x87,0x4a,0xff,0xff,0x0,0xb2,0xff,0xea,0x4,0x18,0x5,0x87,0x0,0x22,0x0,0xd8,0x0,0x0,0x0,0x2, + 0x1,0x80,0xea,0x0,0x0,0x0,0xff,0xff,0x0,0xb2,0xff,0xea,0x4,0x18,0x5,0x76,0x0,0x22,0x0,0xd8,0x0,0x0,0x0,0x2,0x1,0x83,0x0,0x0,0x0,0x0, + 0x0,0x1,0x0,0xb2,0xfe,0x28,0x4,0x18,0x3,0xb2,0x0,0x5e,0x0,0xf8,0x40,0xe,0x27,0x1,0x7,0x6,0x23,0x1,0x0,0x7,0xf,0x1,0x2,0x4,0x3,0x4a, + 0x4b,0xb0,0xa,0x50,0x58,0x40,0x3f,0x0,0x9,0xa,0x6,0xa,0x9,0x6,0x70,0x0,0x6,0x7,0xa,0x6,0x7,0x6e,0x0,0x1,0x0,0x5,0x4,0x1,0x68,0x0, + 0x5,0x3,0x0,0x5,0x66,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0xa,0xa,0x8,0x5b,0x0,0x8,0x8,0x19,0x4b,0x0, + 0x7,0x7,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x4b,0xb0,0xc,0x50,0x58,0x40,0x40,0x0,0x9,0xa,0x6,0xa,0x9,0x6,0x70,0x0,0x6,0x7,0xa, + 0x6,0x7,0x6e,0x0,0x1,0x0,0x5,0x0,0x1,0x5,0x70,0x0,0x5,0x3,0x0,0x5,0x66,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2, + 0x60,0x0,0xa,0xa,0x8,0x5b,0x0,0x8,0x8,0x19,0x4b,0x0,0x7,0x7,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x41,0x0,0x9,0xa,0x6,0xa, + 0x9,0x6,0x70,0x0,0x6,0x7,0xa,0x6,0x7,0x6e,0x0,0x1,0x0,0x5,0x0,0x1,0x5,0x70,0x0,0x5,0x3,0x0,0x5,0x3,0x6e,0x0,0x3,0x4,0x0,0x3, + 0x4,0x6e,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0xa,0xa,0x8,0x5b,0x0,0x8,0x8,0x19,0x4b,0x0,0x7,0x7,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c, + 0x59,0x59,0x40,0x11,0x50,0x4e,0x4b,0x4a,0x44,0x42,0x24,0x1b,0x24,0x24,0x17,0x24,0x11,0x12,0xb,0x7,0x1c,0x2b,0x24,0x6,0x6,0x7,0x15,0x36,0x16,0x15, + 0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x26,0x27, + 0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x33, + 0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x4,0x18,0x53, + 0xa4,0x76,0x65,0x66,0x7c,0x79,0x44,0x80,0x33,0x17,0x8,0x11,0x1d,0x8,0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36,0x3e,0x27,0xf,0x13,0xbf,0x8f,0x27,0xc,0x18, + 0x1e,0xf,0x10,0x52,0xbc,0x63,0x7b,0x7f,0x29,0x28,0x22,0x5c,0x48,0x62,0x7c,0x35,0x47,0x4f,0x61,0xa9,0x6c,0xe5,0xad,0x28,0xa,0x17,0x1f,0xa,0x14,0xa3, + 0xb3,0x6a,0x78,0x28,0x25,0x21,0x52,0x4b,0x5d,0x7e,0x36,0x4d,0x57,0xbe,0x83,0x4c,0x4,0x5c,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19,0xe,0x15,0x2d, + 0x2,0x10,0x16,0x21,0x1f,0x21,0x20,0x1,0x15,0x17,0x9f,0x11,0x4f,0x16,0x23,0x13,0x19,0x2f,0x9,0x2e,0x30,0x53,0x47,0x22,0x2b,0xd,0xb,0xd,0x7,0x9, + 0x14,0x15,0x1c,0x66,0x52,0x5c,0x81,0x41,0x57,0x14,0x25,0x14,0x17,0x32,0x9,0x53,0x48,0x45,0x1f,0x27,0xc,0xb,0xb,0x7,0x8,0x13,0x14,0x1d,0x6b,0x59, + 0x0,0x0,0xff,0xff,0x0,0xb2,0xff,0xea,0x4,0x18,0x5,0x74,0x0,0x22,0x1,0x92,0x0,0x0,0x0,0x2,0x0,0xd8,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xb2, + 0xfd,0xf2,0x4,0x18,0x3,0xb2,0x0,0x22,0x0,0xd8,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xbe,0x0,0x0,0x0,0x1,0x0,0xeb,0xff,0xea,0x4,0xd,0x5,0x25, + 0x0,0x35,0x0,0x65,0xb5,0x6,0x1,0x2,0x3,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1f,0x0,0x2,0x3,0x1,0x3,0x2,0x1,0x70,0x0,0x3,0x3,0x5, + 0x5b,0x6,0x1,0x5,0x5,0x10,0x4b,0x0,0x1,0x1,0x0,0x5b,0x4,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x23,0x0,0x2,0x3,0x1,0x3,0x2,0x1,0x70, + 0x0,0x3,0x3,0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x40,0xe, + 0x0,0x0,0x0,0x35,0x0,0x34,0x35,0x2a,0x24,0x24,0x2c,0x7,0x7,0x19,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22, + 0x26,0x35,0x34,0x36,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x15,0x11,0x14,0x6,0x23, + 0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x36,0x33,0x2,0xd7,0xaa,0x55,0x5a,0x52,0x6b,0x78,0x64,0xb6,0x79,0x32,0x21,0x1e,0x22,0x7e,0x8e,0x8a,0x76,0x22,0x1d, + 0x1d,0x22,0x62,0x67,0x75,0x6d,0x67,0x72,0x21,0x29,0x2,0x29,0x21,0x59,0xa8,0x72,0x5,0x25,0x5b,0x9c,0x63,0x5b,0x87,0x2b,0x29,0xb2,0x7b,0x76,0xad,0x5b, + 0x21,0x2c,0x25,0x22,0x7a,0x72,0x7a,0x87,0x21,0x24,0x24,0x20,0x3,0xa,0x70,0x5a,0x5d,0x69,0x7f,0x6e,0xfc,0x93,0x23,0x1e,0x1e,0x23,0x3,0x78,0x6e,0xa9, + 0x5f,0x0,0x0,0x1,0x0,0x75,0xff,0xea,0x4,0x48,0x4,0xb9,0x0,0x2d,0x0,0x30,0x40,0x2d,0x0,0x7,0x1,0x6,0x1,0x7,0x6,0x70,0x4,0x1,0x2,0x5, + 0x1,0x1,0x7,0x2,0x1,0x61,0x0,0x3,0x3,0x16,0x4b,0x0,0x6,0x6,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x23,0x23,0x24,0x23,0x23,0x24,0x23,0x25, + 0x8,0x7,0x1c,0x2b,0x24,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x11,0x34,0x36,0x33,0x32,0x16,0x15, + 0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x4,0x48,0x21,0x4e,0xc0,0x53,0xaa,0x9d,0xcb,0x22, + 0x1d,0x1d,0x22,0xcb,0x22,0x29,0x29,0x22,0x1,0x9b,0x22,0x1d,0x1d,0x22,0xfe,0x65,0x50,0x61,0x43,0x94,0x45,0xe,0x11,0x22,0x18,0xa1,0x13,0x20,0x14,0x31, + 0x3f,0xb1,0xb0,0x1,0x71,0x21,0x27,0x27,0x21,0x1,0x2c,0x23,0x1e,0x1e,0x23,0xfe,0xd4,0x21,0x27,0x27,0x21,0xfe,0x9c,0x72,0x6a,0x36,0x2d,0xa,0x2e,0x0, + 0x0,0x0,0x0,0x1,0x0,0x75,0xff,0xea,0x4,0x48,0x4,0xb9,0x0,0x3f,0x0,0x41,0x40,0x3e,0x0,0xb,0x1,0xa,0x1,0xb,0xa,0x70,0x6,0x1,0x4,0x7, + 0x1,0x3,0x2,0x4,0x3,0x61,0x8,0x1,0x2,0x9,0x1,0x1,0xb,0x2,0x1,0x63,0x0,0x5,0x5,0x16,0x4b,0x0,0xa,0xa,0x0,0x5b,0x0,0x0,0x0,0x17, + 0x0,0x4c,0x3e,0x3c,0x39,0x37,0x34,0x32,0x21,0x24,0x23,0x23,0x24,0x21,0x24,0x23,0x25,0xc,0x7,0x1d,0x2b,0x24,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26, + 0x35,0x35,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x35,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x11,0x34,0x36,0x33,0x32,0x16,0x15,0x11,0x21,0x32,0x16, + 0x15,0x14,0x6,0x23,0x21,0x15,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x4,0x48,0x21,0x4e,0xc0, + 0x53,0xaa,0x9d,0x78,0x22,0x1d,0x1d,0x22,0x78,0xcb,0x22,0x1d,0x1d,0x22,0xcb,0x22,0x29,0x29,0x22,0x1,0x9b,0x22,0x1d,0x1d,0x22,0xfe,0x65,0xfc,0x22,0x1d, + 0x1d,0x22,0xfc,0x50,0x61,0x43,0x94,0x45,0xe,0x11,0x22,0x18,0xa1,0x13,0x20,0x14,0x31,0x3f,0xb1,0xb0,0x4b,0x21,0x27,0x27,0x21,0x96,0x21,0x27,0x27,0x21, + 0x1,0x2c,0x23,0x1e,0x1e,0x23,0xfe,0xd4,0x21,0x27,0x27,0x21,0x96,0x21,0x27,0x27,0x21,0x3e,0x72,0x6a,0x36,0x2d,0xa,0x2e,0xff,0xff,0x0,0x75,0xff,0xea, + 0x4,0x48,0x5,0x78,0x0,0x22,0x0,0xdf,0x0,0x0,0x1,0x7,0x1,0x7e,0x5,0xe4,0x6,0xa,0x0,0x9,0xb1,0x1,0x1,0xb8,0x6,0xa,0xb0,0x33,0x2b,0x0, + 0x0,0x1,0x0,0x75,0xfe,0x28,0x4,0x48,0x4,0xb9,0x0,0x4e,0x0,0xf1,0x40,0xa,0x27,0x1,0x0,0xb,0x13,0x1,0x2,0x4,0x2,0x4a,0x4b,0xb0,0xa,0x50, + 0x58,0x40,0x3d,0x0,0xc,0x6,0xb,0x6,0xc,0xb,0x70,0x0,0x1,0x0,0x5,0x4,0x1,0x68,0x0,0x5,0x3,0x0,0x5,0x66,0x0,0x3,0x4,0x0,0x3,0x4, + 0x6e,0x9,0x1,0x7,0xa,0x1,0x6,0xc,0x7,0x6,0x61,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0x8,0x8,0x16,0x4b,0x0,0xb,0xb,0x0,0x5b,0x0,0x0, + 0x0,0x17,0x0,0x4c,0x1b,0x4b,0xb0,0xc,0x50,0x58,0x40,0x3e,0x0,0xc,0x6,0xb,0x6,0xc,0xb,0x70,0x0,0x1,0x0,0x5,0x0,0x1,0x5,0x70,0x0,0x5, + 0x3,0x0,0x5,0x66,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x9,0x1,0x7,0xa,0x1,0x6,0xc,0x7,0x6,0x61,0x0,0x4,0x0,0x2,0x4,0x2,0x60,0x0,0x8, + 0x8,0x16,0x4b,0x0,0xb,0xb,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x3f,0x0,0xc,0x6,0xb,0x6,0xc,0xb,0x70,0x0,0x1,0x0,0x5,0x0, + 0x1,0x5,0x70,0x0,0x5,0x3,0x0,0x5,0x3,0x6e,0x0,0x3,0x4,0x0,0x3,0x4,0x6e,0x9,0x1,0x7,0xa,0x1,0x6,0xc,0x7,0x6,0x61,0x0,0x4,0x0, + 0x2,0x4,0x2,0x60,0x0,0x8,0x8,0x16,0x4b,0x0,0xb,0xb,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x59,0x40,0x14,0x4d,0x4b,0x48,0x46,0x43,0x41, + 0x3d,0x3b,0x23,0x24,0x28,0x24,0x24,0x17,0x24,0x12,0x15,0xd,0x7,0x1d,0x2b,0x24,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x15,0x36,0x16,0x15,0x14,0x6,0x23, + 0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x26,0x26,0x35,0x11,0x23, + 0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x11,0x34,0x36,0x33,0x32,0x16,0x15,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x16,0x33,0x32,0x36,0x37, + 0x36,0x33,0x32,0x17,0x4,0x48,0x21,0x4e,0xc0,0x53,0x7,0x65,0x66,0x7c,0x79,0x44,0x80,0x33,0x17,0x8,0x11,0x1d,0x8,0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36, + 0x3e,0x27,0xf,0x13,0x61,0x5b,0xcb,0x22,0x1d,0x1d,0x22,0xcb,0x22,0x29,0x29,0x22,0x1,0x9b,0x22,0x1d,0x1d,0x22,0xfe,0x65,0x50,0x61,0x43,0x94,0x45,0xe, + 0x11,0x22,0x18,0xa1,0x13,0x20,0x14,0x31,0x3f,0x5b,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19,0xe,0x15,0x2d,0x2,0x10,0x16,0x21,0x1f,0x21,0x20,0x1, + 0x15,0x17,0xae,0x20,0xa7,0x87,0x1,0x71,0x21,0x27,0x27,0x21,0x1,0x2c,0x23,0x1e,0x1e,0x23,0xfe,0xd4,0x21,0x27,0x27,0x21,0xfe,0x9c,0x72,0x6a,0x36,0x2d, + 0xa,0x2e,0xff,0xff,0x0,0x75,0xfd,0xf2,0x4,0x48,0x4,0xb9,0x0,0x22,0x0,0xdf,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xfe,0x0,0x0,0x0,0x1,0x0,0xb8, + 0xff,0xea,0x4,0x2,0x3,0xa6,0x0,0x26,0x0,0x4c,0xb5,0xb,0x1,0x3,0x2,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x13,0x5,0x4,0x2,0x2,0x2,0x11, + 0x4b,0x0,0x3,0x3,0x0,0x5b,0x1,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40,0x17,0x5,0x4,0x2,0x2,0x2,0x11,0x4b,0x0,0x0,0x0,0xf,0x4b,0x0,0x3, + 0x3,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0xd,0x0,0x0,0x0,0x26,0x0,0x24,0x25,0x35,0x25,0x35,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x11, + 0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x6,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x36,0x35, + 0x11,0x34,0x36,0x33,0x33,0x3,0xe1,0x21,0x1e,0x27,0x2,0x27,0x1e,0x44,0xd2,0x6b,0x97,0xa6,0x21,0x29,0x2,0x29,0x21,0x59,0x5d,0x56,0xa7,0x6b,0x21,0x29, + 0x2,0x3,0xa6,0x1e,0x23,0xfc,0xd2,0x23,0x1e,0x1e,0x23,0xa3,0x69,0x87,0xae,0x98,0x2,0x35,0x23,0x1e,0x1e,0x23,0xfd,0xda,0x5a,0x67,0x6d,0xbb,0x6e,0x1, + 0x51,0x23,0x1e,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x2,0x5,0x87,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x80,0xfe,0x0,0x0,0x0,0xff,0xff, + 0x0,0xb8,0xff,0xea,0x4,0x2,0x5,0x5c,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x82,0xff,0x0,0x0,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x2, + 0x5,0x74,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x92,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x2,0x5,0x53,0x0,0x22,0x0,0xe4, + 0x0,0x0,0x0,0x2,0x1,0x93,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x2,0x5,0x87,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x95, + 0xf8,0x0,0x0,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x3b,0x5,0x76,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x96,0xec,0x0,0x0,0x0,0xff,0xff, + 0x0,0xbb,0xff,0xea,0x4,0x5,0x4,0xe2,0x0,0x22,0x1,0x97,0x0,0x0,0x0,0x2,0x0,0xe4,0x3,0x0,0x0,0x0,0x0,0x1,0x0,0xb8,0xfe,0x28,0x4,0x39, + 0x3,0xa6,0x0,0x38,0x0,0x35,0x40,0x32,0x1d,0x1,0x4,0x3,0x1c,0x3,0x2,0x2,0x4,0x2,0x4a,0x0,0x0,0x0,0x1,0x0,0x1,0x60,0x6,0x5,0x2,0x3, + 0x3,0x11,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x0,0x0,0x0,0x38,0x0,0x36,0x25,0x35,0x28,0x28,0x2b,0x7,0x7,0x19,0x2b,0x0, + 0x16,0x15,0x11,0x14,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x35,0x6, + 0x6,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x32,0x16,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x11,0x34,0x36,0x33,0x33,0x3,0xe1,0x21,0x7, + 0x9,0x5b,0x50,0x2a,0x23,0x37,0x3a,0x18,0x1c,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x67,0x64,0x44,0xd2,0x6b,0x97,0xa6,0x21,0x29,0x2,0x29,0x21,0x59,0x5d,0x56, + 0xa7,0x6b,0x21,0x29,0x2,0x3,0xa6,0x1e,0x23,0xfc,0xd2,0x13,0x18,0x8,0x54,0x7d,0x38,0x24,0x27,0xa,0x4,0x23,0x27,0x14,0x18,0x6,0x1a,0x68,0x57,0x51, + 0x98,0x50,0xba,0x69,0x87,0xae,0x98,0x2,0x35,0x23,0x1e,0x1e,0x23,0xfd,0xda,0x5a,0x67,0x6d,0xbb,0x6e,0x1,0x51,0x23,0x1e,0xff,0xff,0x0,0xb8,0xff,0xea, + 0x4,0x2,0x6,0x15,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x99,0xfd,0x0,0x0,0x0,0xff,0xff,0x0,0xb8,0xff,0xea,0x4,0x2,0x5,0x2d,0x0,0x22, + 0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x9a,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x7c,0xff,0xea,0x4,0x50,0x3,0xa8,0x0,0x1d,0x0,0x32,0xb5,0x17,0x1,0x0, + 0x1,0x1,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0xc,0x2,0x1,0x1,0x1,0x11,0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0xc,0x2,0x1,0x1,0x1,0x19, + 0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0xb5,0x26,0x29,0x27,0x3,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x1,0x26, + 0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x1,0x1,0x36,0x36,0x33,0x32,0x17,0x4,0x36,0x1a,0x9,0xfe,0x95,0xf,0x36,0x31,0x31,0x36,0xf,0xfe,0x95, + 0x9,0x1a,0x1b,0x1b,0x13,0x11,0x18,0xa,0x1,0x54,0x1,0x54,0xa,0x18,0x11,0x13,0x1b,0x3,0x91,0x1b,0x12,0xf,0x14,0xfc,0xe7,0x21,0x1d,0x1d,0x21,0x3, + 0x19,0x13,0x10,0x12,0x1b,0xb,0xc,0x14,0x16,0xfd,0x11,0x2,0xef,0x16,0x14,0xc,0x0,0x0,0x0,0x1,0x0,0x3a,0xff,0xea,0x4,0x92,0x3,0xa6,0x0,0x2b, + 0x0,0x2d,0x40,0x2a,0x16,0x2,0x2,0x3,0x2,0x25,0x1f,0xc,0x3,0x0,0x3,0x2,0x4a,0x0,0x3,0x2,0x0,0x2,0x3,0x0,0x70,0x4,0x1,0x2,0x2,0x11, + 0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x15,0x25,0x29,0x26,0x27,0x5,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x3, + 0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x13,0x36,0x33,0x32,0x17,0x13,0x13,0x36,0x36,0x33,0x32, + 0x17,0x4,0x76,0x1c,0x4,0xc7,0x9,0x23,0x26,0x2b,0x30,0xb,0xa9,0xa9,0xb,0x30,0x2b,0x26,0x23,0x9,0xc7,0x4,0x1c,0x20,0x11,0x10,0x17,0x19,0x6,0x9f, + 0xaf,0x10,0x3b,0x3b,0x10,0xaf,0x9f,0x6,0x19,0x17,0x10,0x11,0x3,0x9c,0x19,0x15,0xe,0xf,0xfc,0xda,0x24,0x1d,0x1f,0x22,0x2,0x0,0xfe,0x0,0x22,0x1f, + 0x1d,0x24,0x3,0x26,0xf,0xe,0x15,0x19,0x6,0x4,0x18,0x1b,0xfd,0x5f,0x2,0x15,0x2f,0x2f,0xfd,0xeb,0x2,0xa1,0x1b,0x18,0x4,0x0,0xff,0xff,0x0,0x3a, + 0xff,0xea,0x4,0x92,0x5,0x87,0x0,0x22,0x0,0xf0,0x0,0x0,0x0,0x2,0x1,0x80,0x14,0x0,0x0,0x0,0xff,0xff,0x0,0x3a,0xff,0xea,0x4,0x92,0x5,0x74, + 0x0,0x22,0x0,0xf0,0x0,0x0,0x0,0x2,0x1,0x92,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x3a,0xff,0xea,0x4,0x92,0x5,0x53,0x0,0x22,0x0,0xf0,0x0,0x0, + 0x0,0x2,0x1,0x93,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x3a,0xff,0xea,0x4,0x92,0x5,0x87,0x0,0x22,0x0,0xf0,0x0,0x0,0x0,0x2,0x1,0x95,0xec,0x0, + 0x0,0x0,0x0,0x1,0x0,0xa7,0xff,0xf1,0x4,0x31,0x3,0xab,0x0,0x27,0x0,0x22,0x40,0x1f,0x26,0x23,0x1c,0x12,0xf,0x8,0x6,0x0,0x2,0x1,0x4a,0x3, + 0x1,0x2,0x2,0x19,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x24,0x2c,0x24,0x24,0x4,0x7,0x18,0x2b,0x24,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x1, + 0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x1,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x1,0x1,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x1, + 0x4,0x31,0x2c,0x21,0x16,0x1d,0x1a,0xfe,0xd5,0xfe,0xd5,0x1a,0x1d,0x16,0x21,0x2c,0x11,0x1,0x48,0xfe,0xc5,0x12,0x2d,0x21,0x16,0x1d,0x1a,0x1,0x1e,0x1, + 0x1e,0x1a,0x1d,0x16,0x21,0x2d,0x12,0xfe,0xc5,0x1,0x48,0x45,0x13,0x1e,0x14,0xf,0x1e,0x1,0x60,0xfe,0xa0,0x1e,0xf,0x14,0x1e,0x13,0x14,0x1,0x7e,0x1, + 0x6c,0x15,0x12,0x1e,0x14,0xf,0x1e,0xfe,0xb4,0x1,0x4c,0x1e,0xf,0x14,0x1e,0x12,0x15,0xfe,0x94,0xfe,0x82,0x0,0x0,0x0,0x0,0x1,0x0,0x7b,0xfe,0x70, + 0x4,0x50,0x3,0xa8,0x0,0x21,0x0,0x33,0xb6,0x1b,0x10,0x2,0x0,0x1,0x1,0x4a,0x4b,0xb0,0xa,0x50,0x58,0x40,0xc,0x2,0x1,0x1,0x1,0x11,0x4b,0x0, + 0x0,0x0,0x13,0x0,0x4c,0x1b,0x40,0xc,0x2,0x1,0x1,0x1,0x19,0x4b,0x0,0x0,0x0,0x13,0x0,0x4c,0x59,0xb5,0x26,0x2d,0x27,0x3,0x7,0x17,0x2b,0x0, + 0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x13,0x1,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x16,0x17,0x1,0x1,0x36,0x36, + 0x33,0x32,0x17,0x4,0x36,0x1a,0xa,0xfd,0xab,0xb,0x18,0x10,0x12,0x1b,0x1b,0x19,0xa,0xab,0xfe,0x73,0xa,0x36,0x1b,0x12,0x11,0x18,0xb,0x1,0x55,0x1, + 0x53,0xb,0x18,0x11,0x12,0x1b,0x3,0x91,0x1b,0x12,0x10,0x13,0xfb,0x59,0x16,0x14,0xc,0xb,0x1b,0x11,0x10,0x14,0x1,0x54,0x3,0x16,0x13,0x10,0x22,0x16, + 0xc,0x14,0x16,0xfd,0x55,0x2,0xab,0x16,0x14,0xc,0x0,0x0,0xff,0xff,0x0,0x7b,0xfe,0x70,0x4,0x50,0x5,0x87,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2, + 0x1,0x80,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x7b,0xfe,0x70,0x4,0x50,0x5,0x74,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2,0x1,0x92,0x10,0x0,0x0,0x0, + 0xff,0xff,0x0,0x7b,0xfe,0x70,0x4,0x50,0x5,0x53,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2,0x1,0x93,0x2,0x0,0x0,0x0,0xff,0xff,0x0,0x7b,0xfe,0x70, + 0x4,0x50,0x5,0x87,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2,0x1,0x95,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0xb2,0x0,0x0,0x4,0x1a,0x3,0x9c,0x0,0x1d, + 0x0,0x25,0x40,0x22,0x0,0x1,0x1,0x2,0x59,0x0,0x2,0x2,0x11,0x4b,0x4,0x1,0x3,0x3,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x1d, + 0x0,0x1c,0x44,0x25,0x44,0x5,0x7,0x17,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x21,0x22,0x26,0x35,0x34,0x36,0x33, + 0x21,0x33,0x32,0x16,0x15,0x14,0x7,0x1,0x21,0x3,0xfd,0x1d,0x1d,0x22,0xfd,0x70,0x5a,0x22,0x1d,0xe,0x2,0x5c,0xfd,0xe9,0x22,0x1d,0x1d,0x22,0x2,0x74, + 0x58,0x22,0x1d,0xf,0xfd,0xa5,0x2,0x35,0x90,0x21,0x27,0x27,0x21,0x1f,0x25,0x1e,0xf,0x2,0x9b,0x21,0x27,0x27,0x21,0x1f,0x25,0x1d,0x11,0xfd,0x66,0x0, + 0xff,0xff,0x0,0xb2,0x0,0x0,0x4,0x1a,0x5,0x87,0x0,0x22,0x0,0xfb,0x0,0x0,0x0,0x2,0x1,0x80,0xf4,0x0,0x0,0x0,0xff,0xff,0x0,0xb2,0x0,0x0, + 0x4,0x1a,0x5,0x76,0x0,0x22,0x0,0xfb,0x0,0x0,0x0,0x2,0x1,0x83,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0xb2,0x0,0x0,0x4,0x1a,0x5,0x53,0x0,0x22, + 0x0,0xfb,0x0,0x0,0x0,0x2,0x1,0x94,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0xbb,0xff,0xf6,0x9,0x15,0x5,0x53,0x0,0x22,0x0,0x9f,0x0,0x0,0x0,0x23, + 0x0,0xa9,0x4,0xcc,0x0,0x0,0x0,0x3,0x1,0x94,0x4,0xd0,0x0,0x0,0xff,0xff,0x0,0xbb,0xff,0xf6,0x9,0xb,0x5,0x25,0x0,0x22,0x0,0x9f,0x0,0x0, + 0x0,0x3,0x0,0xb9,0x4,0xcc,0x0,0x0,0x0,0x2,0x0,0xfc,0x1,0xd1,0x3,0x9f,0x4,0xb9,0x0,0x26,0x0,0x30,0x0,0x8,0xb5,0x2a,0x27,0xc,0x0,0x2, + 0x30,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x33,0x32,0x17,0x35,0x34,0x23,0x22,0x7, + 0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x2,0x15,0x14,0x16,0x33,0x32,0x37,0x35,0x26,0x23,0x3,0xf,0x90,0x1c,0x1f,0x2,0x1f,0x1c,0x85, + 0x98,0x4e,0x7a,0x46,0xaa,0x88,0x84,0x66,0x94,0x78,0x70,0xe,0xc,0x1c,0x14,0x10,0x17,0x3d,0x9f,0x4f,0xfb,0x47,0x3e,0x93,0x77,0x6d,0x72,0x4,0xb9,0x85, + 0x7a,0xfe,0x52,0x1a,0x18,0x18,0x1a,0x36,0x71,0x33,0x64,0x47,0x7a,0x76,0x1c,0x33,0x82,0x41,0x8,0x23,0x1c,0x13,0x18,0xf,0x26,0x2b,0xfe,0x68,0x6f,0x30, + 0x34,0x75,0x45,0x19,0x0,0x0,0x0,0x2,0x0,0xeb,0x1,0xd1,0x3,0xe1,0x4,0xb9,0x0,0xf,0x0,0x1f,0x0,0x8,0xb5,0x16,0x10,0x6,0x0,0x2,0x30,0x2b, + 0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26, + 0x23,0x2,0xd1,0xad,0x63,0x63,0xad,0x6b,0x6b,0xad,0x63,0x63,0xad,0x6b,0x46,0x6d,0x3c,0x3c,0x6d,0x46,0x47,0x6c,0x3c,0x3c,0x6c,0x47,0x4,0xb9,0x60,0xaa, + 0x6a,0x6b,0xa9,0x60,0x60,0xa9,0x6b,0x6a,0xaa,0x60,0x84,0x3e,0x6d,0x45,0x45,0x6e,0x3d,0x3d,0x6d,0x46,0x45,0x6d,0x3e,0x0,0x0,0x2,0x0,0x93,0x0,0x0, + 0x4,0x38,0x4,0xb9,0x0,0x12,0x0,0x16,0x0,0x8,0xb5,0x14,0x13,0x7,0x0,0x2,0x30,0x2b,0x0,0x16,0x17,0x1,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26, + 0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x7,0x1,0x21,0x1,0x2,0x91,0x31,0xc,0x1,0x65,0x5,0x1d,0x22,0xfc,0xd9,0x22,0x1d,0x6,0x1,0x69,0xc,0x32,0x29, + 0x2,0xfe,0xda,0x2,0x4a,0xfe,0xde,0x4,0xb9,0x1f,0x22,0xfb,0xf2,0xf,0x17,0x25,0x1f,0x1f,0x25,0x14,0x12,0x4,0xe,0x22,0x1f,0xbb,0xfc,0x8a,0x3,0x76, + 0x0,0x1,0x0,0x51,0x0,0x0,0x4,0x7b,0x4,0xb9,0x0,0x35,0x0,0x6,0xb3,0xc,0x0,0x1,0x30,0x2b,0x0,0x16,0x12,0x15,0x14,0x6,0x7,0x33,0x32,0x16, + 0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x16,0x15,0x14,0x6,0x23,0x21, + 0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x26,0x26,0x35,0x34,0x12,0x36,0x33,0x3,0x2,0xef,0x83,0x82,0x67,0xb1,0x22,0x1d,0x1d,0x22,0xfe,0xb2,0x22,0x1d,0x11, + 0x87,0x8f,0x5b,0xa7,0x6e,0x6e,0xa7,0x5b,0x8f,0x87,0x11,0x1d,0x22,0xfe,0xb2,0x22,0x1d,0x1d,0x22,0xb1,0x67,0x82,0x83,0xef,0x9c,0x4,0xb9,0x92,0xfe,0xf6, + 0xae,0x94,0xfb,0x50,0x21,0x27,0x27,0x21,0x24,0x2a,0x34,0xc,0x56,0xf1,0x9a,0x85,0xc6,0x6b,0x6b,0xc6,0x85,0x9a,0xf1,0x56,0xc,0x34,0x2a,0x24,0x21,0x27, + 0x27,0x21,0x50,0xfb,0x94,0xae,0x1,0xa,0x92,0x0,0x0,0x1,0x0,0xda,0xfe,0x72,0x3,0xfc,0x3,0xa6,0x0,0x2d,0x0,0x6,0xb3,0x13,0x0,0x1,0x30,0x2b, + 0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x6,0x6,0x23,0x22,0x27,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33, + 0x32,0x16,0x15,0x11,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x11,0x34,0x36,0x33,0x33,0x3,0xdb,0x21,0x1e,0x27,0x2,0x27,0x1e,0x3f,0xb5,0x65,0x64,0x43,0x21, + 0x29,0x2,0x29,0x21,0x21,0x29,0x2,0x29,0x21,0x59,0x5d,0x4c,0x95,0x5f,0x21,0x29,0x2,0x3,0xa6,0x1e,0x23,0xfc,0xd2,0x23,0x1e,0x1e,0x23,0x8f,0x62,0x7a, + 0x2f,0xfe,0x9a,0x23,0x1e,0x1e,0x23,0x4,0xb2,0x23,0x1e,0x1e,0x23,0xfd,0xda,0x5a,0x67,0x66,0xad,0x65,0x1,0x6f,0x23,0x1e,0x0,0x0,0x0,0x1,0x0,0x62, + 0xff,0xf6,0x4,0x6a,0x3,0x9c,0x0,0x21,0x0,0x6,0xb3,0x9,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x14,0x6,0x23,0x23,0x22,0x26, + 0x35,0x11,0x21,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0x4d,0x1d,0x1d,0x22,0x57,0x21,0x29,0x2,0x29, + 0x21,0xfe,0x50,0x21,0x29,0x2,0x29,0x21,0x57,0x22,0x1d,0x1d,0x22,0x3,0x8a,0x3,0x9c,0x21,0x27,0x27,0x21,0xfd,0x2b,0x23,0x1e,0x1e,0x23,0x2,0xd5,0xfd, + 0x2b,0x23,0x1e,0x1e,0x23,0x2,0xd5,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x3,0x0,0xbe,0xff,0xea,0x4,0xe,0x4,0xb9,0x0,0xf,0x0,0x19,0x0,0x23, + 0x0,0x3a,0x40,0x37,0x20,0x1f,0x16,0x15,0x4,0x3,0x2,0x1,0x4a,0x5,0x1,0x2,0x2,0x1,0x5b,0x4,0x1,0x1,0x1,0x16,0x4b,0x6,0x1,0x3,0x3,0x0, + 0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1a,0x1a,0x10,0x10,0x0,0x0,0x1a,0x23,0x1a,0x22,0x10,0x19,0x10,0x18,0x0,0xf,0x0,0xe,0x26,0x7,0x7,0x15,0x2b, + 0x0,0x16,0x12,0x15,0x14,0x2,0x6,0x23,0x22,0x26,0x2,0x35,0x34,0x12,0x36,0x33,0xe,0x2,0x15,0x14,0x17,0x1,0x26,0x26,0x23,0x12,0x36,0x36,0x35,0x34, + 0x27,0x1,0x16,0x16,0x33,0x2,0xe6,0xc0,0x68,0x68,0xc0,0x80,0x80,0xc0,0x68,0x68,0xc0,0x80,0x4f,0x7a,0x45,0x10,0x1,0xc9,0x25,0x68,0x3e,0x4f,0x7a,0x45, + 0x10,0xfe,0x38,0x24,0x68,0x3e,0x4,0xb9,0x99,0xfe,0xe9,0xb8,0xb8,0xfe,0xea,0x99,0x99,0x1,0x16,0xb8,0xb8,0x1,0x17,0x99,0x94,0x6f,0xd3,0x92,0x5f,0x55, + 0x1,0xff,0x43,0x46,0xfc,0x59,0x6e,0xd3,0x92,0x5f,0x55,0xfe,0x1,0x43,0x45,0x0,0x0,0x0,0x0,0x1,0x0,0xdc,0x0,0x0,0x4,0xd,0x4,0xbc,0x0,0x1f, + 0x0,0x30,0x40,0x2d,0xe,0x1,0x2,0x3,0x1,0x4a,0x0,0x2,0x3,0x1,0x3,0x2,0x1,0x70,0x0,0x3,0x3,0x16,0x4b,0x5,0x4,0x2,0x1,0x1,0x0,0x5a, + 0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x1f,0x0,0x1e,0x27,0x23,0x24,0x34,0x6,0x7,0x18,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35, + 0x34,0x36,0x33,0x21,0x11,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x25,0x36,0x33,0x32,0x16,0x15,0x11,0x21,0x3,0xf0,0x1d,0x1d,0x22,0xfd,0x5e,0x22, + 0x1d,0x1d,0x22,0x1,0xd,0xf9,0x11,0xe,0x20,0x17,0xe,0x1f,0x1,0x79,0x14,0x14,0x16,0x1d,0x0,0xff,0x90,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x3, + 0x52,0x9b,0xa,0x29,0x18,0x16,0x22,0x12,0xe8,0xc,0x1d,0x1a,0xfc,0xb,0x0,0x0,0x0,0x1,0x0,0xc5,0x0,0x0,0x3,0xf9,0x4,0xb9,0x0,0x2a,0x0,0x2e, + 0x40,0x2b,0x0,0x2,0x1,0x4,0x1,0x2,0x4,0x70,0x0,0x1,0x1,0x3,0x5b,0x0,0x3,0x3,0x16,0x4b,0x5,0x1,0x4,0x4,0x0,0x59,0x0,0x0,0x0,0xf, + 0x0,0x4c,0x0,0x0,0x0,0x2a,0x0,0x29,0x27,0x23,0x2a,0x44,0x6,0x7,0x18,0x2b,0x24,0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26,0x35,0x34,0x37,0x1, + 0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x7,0x1,0x21,0x3, + 0xdc,0x1d,0x1d,0x22,0xfd,0xa3,0x59,0x22,0x1d,0xf,0x1,0xb8,0x5c,0x4b,0x77,0x6d,0x42,0x8e,0x3f,0x10,0x12,0x21,0x19,0x11,0x1e,0x4c,0xb8,0x59,0x74,0xad, + 0x5e,0x63,0x69,0xfe,0xb8,0x2,0x1,0x90,0x21,0x27,0x27,0x21,0x1f,0x25,0x26,0x10,0x1,0xbe,0x5d,0x7e,0x48,0x5d,0x6d,0x32,0x2c,0xc,0x29,0x1d,0x14,0x1c, + 0x16,0x36,0x3c,0x53,0x9e,0x6d,0x66,0xad,0x6b,0xfe,0xb3,0x0,0x0,0x1,0x0,0xb5,0xff,0xea,0x3,0xe6,0x4,0xb9,0x0,0x3b,0x0,0x47,0x40,0x44,0x6,0x1, + 0x3,0x4,0x1,0x4a,0x0,0x6,0x5,0x4,0x5,0x6,0x4,0x70,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x5, + 0x5,0x7,0x5b,0x8,0x1,0x7,0x7,0x16,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x3b,0x0,0x3a,0x22,0x24,0x34,0x34, + 0x24,0x17,0x2c,0x9,0x7,0x1b,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33, + 0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22, + 0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x2,0xb7,0xac,0x5e,0x50,0x49,0x5a,0x64,0x61,0xb8,0x81,0x62,0xc8,0x4f,0x1e,0x11,0x1a,0x20,0x10,0x12,0x42,0x9a,0x4e, + 0x7c,0x84,0x85,0x76,0x49,0x22,0x1d,0x1d,0x22,0x37,0x72,0x76,0x76,0x6c,0x84,0x84,0x12,0xe,0x20,0x18,0xe,0x20,0xa3,0xaa,0x4,0xb9,0x51,0x95,0x64,0x56, + 0x7d,0x25,0x25,0x93,0x66,0x6d,0xa6,0x5c,0x44,0x3a,0x16,0x1c,0x14,0x1d,0x2a,0xd,0x31,0x39,0x76,0x65,0x67,0x6b,0x1f,0x25,0x25,0x1f,0x60,0x5c,0x55,0x61, + 0x50,0xa,0x2b,0x1b,0x15,0x20,0x13,0x60,0x0,0x2,0x0,0x91,0xff,0xf6,0x4,0x27,0x4,0xb9,0x0,0x1d,0x0,0x20,0x0,0x2e,0x40,0x2b,0x20,0x1,0x4,0x3, + 0x1,0x4a,0x5,0x6,0x2,0x4,0x2,0x1,0x0,0x1,0x4,0x0,0x61,0x0,0x3,0x3,0x16,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x1f,0x1e,0x0,0x1d, + 0x0,0x1c,0x27,0x23,0x33,0x24,0x7,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x15,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x21,0x22,0x26,0x35, + 0x34,0x37,0x1,0x36,0x36,0x33,0x32,0x15,0x11,0x33,0x21,0x21,0x13,0x4,0xa,0x1d,0x1d,0x22,0xa2,0x21,0x29,0x2,0x29,0x21,0xfe,0x22,0x22,0x1f,0xc,0x1, + 0xe4,0x15,0x33,0x26,0x57,0xa2,0xfd,0x6e,0x1,0x5a,0x8,0x1,0xbe,0x21,0x27,0x27,0x21,0xf7,0x23,0x1e,0x1e,0x23,0xf7,0x24,0x26,0x20,0x11,0x2,0xd3,0x20, + 0x1d,0x4e,0xfd,0x53,0x2,0x22,0x0,0x1,0x0,0xbc,0xff,0xea,0x3,0xf0,0x4,0xa3,0x0,0x35,0x0,0x46,0x40,0x43,0x33,0x1,0x3,0x7,0x1,0x4a,0x0,0x4, + 0x3,0x1,0x3,0x4,0x1,0x70,0x0,0x1,0x2,0x3,0x1,0x2,0x6e,0x8,0x1,0x7,0x0,0x3,0x4,0x7,0x3,0x63,0x0,0x6,0x6,0x5,0x59,0x0,0x5,0x5, + 0xe,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x35,0x0,0x34,0x24,0x45,0x23,0x26,0x24,0x17,0x26,0x9,0x7,0x1b,0x2b, + 0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23, + 0x22,0x6,0x7,0x6,0x23,0x22,0x26,0x37,0x13,0x36,0x36,0x33,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x3,0x36,0x33,0x2,0xe5,0xaf,0x5c,0x67,0xbf, + 0x7e,0x60,0xc2,0x4f,0x1f,0x10,0x1a,0x20,0x10,0x12,0x41,0x98,0x4b,0x51,0x79,0x40,0x3c,0x70,0x4a,0x44,0x6c,0x33,0x10,0x22,0x2a,0x23,0x2,0x14,0x2,0x20, + 0x29,0x86,0x1,0x90,0x22,0x1d,0x1d,0x22,0xfe,0x2e,0xd,0x64,0x73,0x3,0x12,0x66,0xb5,0x75,0x75,0xba,0x69,0x40,0x37,0x17,0x1d,0x16,0x1a,0x2a,0xd,0x2e, + 0x36,0x41,0x75,0x4e,0x4a,0x72,0x40,0x23,0x24,0xa,0x1e,0x23,0x1,0xf4,0x23,0x1e,0x21,0x27,0x27,0x21,0xfe,0xc7,0x38,0x0,0x0,0x2,0x0,0xcb,0xff,0xea, + 0x4,0xa,0x4,0xba,0x0,0x1c,0x0,0x2c,0x0,0x3c,0x40,0x39,0x8,0x1,0x5,0x1,0x1,0x4a,0x0,0x1,0x7,0x1,0x5,0x4,0x1,0x5,0x63,0x0,0x0,0x0, + 0x3,0x5b,0x6,0x1,0x3,0x3,0x16,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x1d,0x1d,0x0,0x0,0x1d,0x2c,0x1d,0x2b,0x25,0x23,0x0, + 0x1c,0x0,0x1b,0x26,0x24,0x24,0x8,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x6,0x7,0x4,0x4,0x7,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23, + 0x22,0x26,0x27,0x26,0x35,0x34,0x12,0x24,0x37,0x0,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0xb0,0x1f,0x13,0x12, + 0xfe,0xf6,0xfe,0xe2,0x1c,0x34,0x98,0x56,0x6e,0xb0,0x64,0x65,0xba,0x79,0x6d,0xb6,0x38,0x4c,0x92,0x1,0x40,0xf8,0xfe,0x94,0x74,0x41,0x3f,0x73,0x4c,0x4c, + 0x73,0x3f,0x3e,0x72,0x4e,0x4,0xba,0x26,0x33,0x1f,0x1b,0x1,0xe,0xf7,0xd4,0x44,0x4a,0x5e,0xac,0x70,0x6c,0xab,0x60,0x64,0x5f,0x83,0xd0,0xad,0x1,0x34, + 0xcd,0xb,0xfd,0x8e,0x37,0x61,0x3f,0x46,0x6e,0x3e,0x38,0x67,0x44,0x45,0x68,0x39,0x0,0x0,0x0,0x1,0x0,0xc7,0xff,0xea,0x4,0x5,0x4,0xa3,0x0,0x17, + 0x0,0x25,0x40,0x22,0xb,0x1,0x0,0x1,0x1,0x4a,0x0,0x1,0x1,0x2,0x59,0x3,0x1,0x2,0x2,0xe,0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0, + 0x17,0x0,0x14,0x25,0x27,0x4,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x21,0x22,0x26,0x35,0x34,0x36, + 0x33,0x21,0x33,0x3,0xe8,0x1d,0x6,0xfe,0x56,0x9,0x27,0x1b,0x25,0x2c,0x5,0x1,0x94,0xfd,0xb4,0x22,0x1d,0x1d,0x22,0x2,0x88,0x38,0x4,0xa3,0x1f,0x25, + 0x18,0x10,0xfb,0xe1,0x17,0x17,0x1d,0x19,0x9,0xf,0x3,0xdb,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x3,0x0,0xd2,0xff,0xea,0x3,0xfa,0x4,0xb9,0x0,0x1b, + 0x0,0x2b,0x0,0x3b,0x0,0x44,0x40,0x41,0x14,0x6,0x2,0x5,0x2,0x1,0x4a,0x0,0x2,0x8,0x1,0x5,0x4,0x2,0x5,0x63,0x7,0x1,0x3,0x3,0x1,0x5b, + 0x6,0x1,0x1,0x1,0x16,0x4b,0x0,0x4,0x4,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x2c,0x2c,0x1c,0x1c,0x0,0x0,0x2c,0x3b,0x2c,0x3a,0x34,0x32,0x1c, + 0x2b,0x1c,0x2a,0x24,0x22,0x0,0x1b,0x0,0x1a,0x2c,0x9,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26, + 0x26,0x35,0x34,0x36,0x37,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x2,0x6,0x6, + 0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x2,0xce,0xa8,0x5f,0x5a,0x4a,0x5c,0x6d,0x68,0xb9,0x73,0x73,0xb9,0x68,0x6d,0x5b,0x4a, + 0x59,0x5f,0xa8,0x68,0x3e,0x61,0x38,0x38,0x63,0x3c,0x3c,0x63,0x38,0x38,0x61,0x3e,0x49,0x71,0x40,0x40,0x71,0x49,0x49,0x71,0x40,0x40,0x71,0x49,0x4,0xb9, + 0x57,0x97,0x5c,0x51,0x80,0x28,0x29,0x96,0x63,0x67,0xa5,0x5e,0x5e,0xa5,0x67,0x63,0x96,0x29,0x28,0x80,0x51,0x5c,0x97,0x57,0x94,0x2d,0x54,0x38,0x33,0x54, + 0x30,0x30,0x54,0x33,0x38,0x54,0x2d,0xfe,0x5,0x36,0x61,0x3e,0x3e,0x62,0x37,0x37,0x62,0x3e,0x3e,0x61,0x36,0x0,0x0,0x2,0x0,0xc2,0xff,0xe9,0x4,0x1, + 0x4,0xb9,0x0,0x1c,0x0,0x2c,0x0,0x3c,0x40,0x39,0x11,0x1,0x2,0x4,0x1,0x4a,0x0,0x4,0x0,0x2,0x1,0x4,0x2,0x63,0x7,0x1,0x5,0x5,0x3,0x5b, + 0x6,0x1,0x3,0x3,0x16,0x4b,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1d,0x1d,0x0,0x0,0x1d,0x2c,0x1d,0x2b,0x25,0x23,0x0,0x1c,0x0, + 0x1b,0x24,0x24,0x27,0x8,0x7,0x17,0x2b,0x0,0x16,0x17,0x16,0x15,0x14,0x2,0x4,0x7,0x6,0x26,0x35,0x34,0x36,0x37,0x24,0x24,0x37,0x6,0x6,0x23,0x22, + 0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x2,0xc7,0xb6,0x38,0x4c,0x92,0xfe,0xc0, + 0xf8,0x1b,0x1f,0x13,0x12,0x1,0xa,0x1,0x1e,0x1c,0x34,0x98,0x56,0x6e,0xb0,0x64,0x65,0xba,0x79,0x4c,0x73,0x3f,0x3e,0x72,0x4e,0x49,0x74,0x41,0x3f,0x73, + 0x4c,0x4,0xb9,0x64,0x5f,0x83,0xd0,0xad,0xfe,0xcc,0xcd,0xb,0x1,0x26,0x33,0x1f,0x1b,0x1,0xe,0xf7,0xd4,0x44,0x4a,0x5e,0xac,0x70,0x6c,0xab,0x60,0x94, + 0x38,0x67,0x44,0x45,0x68,0x39,0x37,0x61,0x3f,0x46,0x6e,0x3e,0x0,0x1,0x0,0x6f,0x0,0xc4,0x4,0x5d,0x3,0x56,0x0,0x11,0x0,0x17,0x40,0x14,0x5,0x1, + 0x1,0x0,0x1,0x4a,0x0,0x0,0x1,0x0,0x72,0x0,0x1,0x1,0x69,0x18,0x11,0x2,0x7,0x16,0x2b,0x0,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23, + 0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x4,0x1a,0x9,0x17,0x15,0xe,0xe,0xfc,0x6a,0x7,0x9,0x17,0x15,0xe,0xe,0x3,0x96,0x3,0x56,0x1c,0x12,0x14,0x13, + 0x8,0xfd,0xcf,0x4,0x1c,0x14,0x12,0x12,0x9,0x2,0x31,0x0,0x0,0x0,0x0,0x3,0x0,0x1,0xff,0x28,0x4,0xba,0x5,0x71,0x0,0x1e,0x0,0x30,0x0,0x58, + 0x0,0x5c,0xb1,0x6,0x64,0x44,0x40,0x51,0x24,0x1,0x1,0x4,0x1,0x4a,0x1e,0xb,0x2,0x0,0x48,0x0,0x0,0x4,0x0,0x72,0x0,0x4,0x1,0x4,0x72,0x0, + 0x5,0x8,0x6,0x8,0x5,0x6,0x70,0x3,0x1,0x1,0x0,0x2,0x9,0x1,0x2,0x61,0xa,0x1,0x9,0x0,0x8,0x5,0x9,0x8,0x63,0x0,0x6,0x7,0x7,0x6, + 0x55,0x0,0x6,0x6,0x7,0x5a,0x0,0x7,0x6,0x7,0x4e,0x31,0x31,0x31,0x58,0x31,0x57,0x29,0x34,0x2d,0x18,0x13,0x23,0x34,0x2c,0x12,0xb,0x7,0x1d,0x2b, + 0xb1,0x6,0x0,0x44,0x13,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x36,0x33,0x32,0x16,0x15,0x11,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x35, + 0x34,0x36,0x33,0x33,0x11,0x0,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x12,0x16,0x15,0x14,0x6,0x7,0x7, + 0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x35,0x34,0x37,0x25,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37, + 0x36,0x36,0x33,0x44,0xe,0x5,0x1a,0xe,0x5,0x1e,0xed,0xa,0xa,0x10,0x13,0xa2,0x15,0x14,0x14,0x15,0xfe,0x43,0x2a,0x15,0x15,0xaa,0x3,0x45,0x9,0x17, + 0x15,0xe,0xe,0xfc,0x6a,0x7,0x9,0x17,0x15,0xe,0xe,0x3,0x96,0xb,0x7f,0x42,0x46,0xc7,0x1,0x43,0x15,0x14,0x14,0x15,0xfe,0x34,0x28,0x1a,0x1,0x16, + 0x2f,0x2c,0x42,0x3e,0x2b,0x62,0x2c,0x7,0x8,0x19,0x10,0x7,0x12,0x34,0x7e,0x3b,0x4,0xc1,0x4,0x26,0x11,0xa,0x1a,0xa,0x4c,0x3,0x11,0x11,0xfd,0xc5, + 0x18,0x1c,0x1b,0x19,0x34,0x1c,0x18,0x1,0xdc,0xfe,0x8e,0x1c,0x12,0x14,0x13,0x8,0xfd,0xcf,0x4,0x1c,0x14,0x12,0x12,0x9,0x2,0x31,0xfe,0x74,0x74,0x62, + 0x40,0x69,0x3a,0xa5,0x18,0x1c,0x1b,0x19,0x3c,0x21,0x15,0xea,0x28,0x43,0x29,0x30,0x3a,0x1c,0x17,0x4,0x25,0x13,0xe,0x18,0xa,0x1c,0x1f,0x0,0x0,0x4, + 0x0,0x1,0xff,0x22,0x4,0xd1,0x5,0x71,0x0,0x1e,0x0,0x30,0x0,0x4f,0x0,0x52,0x0,0x6f,0xb1,0x6,0x64,0x44,0x40,0x64,0x20,0x1,0x0,0x1,0x51,0x1, + 0x4,0x9,0x43,0x1,0x6,0xa,0x3,0x4a,0x16,0xa,0x2,0x2,0x48,0x0,0x2,0x5,0x2,0x72,0x0,0x5,0x1,0x5,0x72,0x0,0x4,0x9,0xa,0x9,0x4,0xa, + 0x70,0x3,0x1,0x1,0x0,0x0,0x9,0x1,0x0,0x61,0x0,0x9,0x4,0x7,0x9,0x57,0xd,0xb,0xc,0x3,0xa,0x8,0x1,0x6,0x7,0xa,0x6,0x63,0x0,0x9, + 0x9,0x7,0x5c,0x0,0x7,0x9,0x7,0x50,0x50,0x50,0x31,0x31,0x50,0x52,0x50,0x52,0x31,0x4f,0x31,0x4e,0x4b,0x49,0x23,0x23,0x26,0x18,0x19,0x2c,0x14,0x23, + 0x31,0xe,0x7,0x1d,0x2b,0xb1,0x6,0x0,0x44,0x0,0x6,0x23,0x21,0x22,0x35,0x34,0x36,0x33,0x33,0x11,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37, + 0x36,0x33,0x32,0x16,0x15,0x11,0x33,0x32,0x16,0x15,0x24,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x32,0x17,0x12,0x16, + 0x15,0x14,0x6,0x23,0x23,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x21,0x22,0x26,0x35,0x34,0x36,0x37,0x1,0x36,0x36,0x33,0x32,0x16,0x15,0x11,0x33,0x23, + 0x13,0x3,0x2,0x11,0x14,0x15,0xfe,0x43,0x2a,0x15,0x15,0xaa,0x91,0xe,0x5,0x1a,0xe,0x5,0x1e,0xed,0xa,0xa,0x10,0x13,0xa2,0x15,0x14,0x2,0x4c,0xe, + 0xfc,0x6a,0x7,0x9,0x17,0x15,0xe,0xe,0x3,0x96,0x7,0x9,0x17,0x15,0x6e,0x14,0x14,0x14,0x5b,0x1a,0x1e,0x1e,0x1b,0xfe,0xc6,0x14,0x19,0x6,0x8,0x1, + 0x3d,0xf,0x1f,0x15,0x1d,0x2d,0x5b,0xcc,0x5,0xdd,0x2,0xc5,0x19,0x34,0x1c,0x18,0x1,0xdc,0x2f,0x4,0x26,0x11,0xa,0x1a,0xa,0x4c,0x3,0x11,0x11,0xfd, + 0xc5,0x18,0x1c,0x3e,0x14,0x13,0x8,0xfd,0xcf,0x4,0x1c,0x14,0x12,0x12,0x9,0x2,0x31,0x4,0x1c,0xfd,0x1c,0x18,0x1c,0x1c,0x19,0x99,0x14,0x14,0x14,0x14, + 0x99,0x21,0x20,0xf,0x13,0xb,0x1,0x79,0x13,0x12,0x1b,0x14,0xfe,0x8c,0x1,0xa,0xfe,0xf6,0x0,0x0,0x0,0x4,0x0,0x15,0xff,0x22,0x4,0xd1,0x5,0x72, + 0x0,0x39,0x0,0x4b,0x0,0x6a,0x0,0x6d,0x0,0xf0,0xb1,0x6,0x64,0x44,0x40,0x16,0x36,0x1,0x3,0x4,0x3b,0x1,0x2,0x1,0x7,0x1,0x0,0x2,0x6c,0x1, + 0x8,0xd,0x5e,0x1,0xa,0xe,0x5,0x4a,0x4b,0xb0,0x13,0x50,0x58,0x40,0x4d,0x0,0x6,0x5,0x4,0x5,0x6,0x4,0x70,0x9,0x1,0x1,0x3,0x2,0x3,0x1, + 0x2,0x70,0x0,0x8,0xd,0xe,0xd,0x8,0xe,0x70,0x0,0x7,0x0,0x5,0x6,0x7,0x5,0x63,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x2,0x0,0x0, + 0xd,0x2,0x0,0x63,0x0,0xd,0x8,0xb,0xd,0x57,0x11,0xf,0x10,0x3,0xe,0xc,0x1,0xa,0xb,0xe,0xa,0x63,0x0,0xd,0xd,0xb,0x5c,0x0,0xb,0xd, + 0xb,0x50,0x1b,0x40,0x53,0x0,0x6,0x5,0x4,0x5,0x6,0x4,0x70,0x0,0x9,0x3,0x1,0x3,0x9,0x1,0x70,0x0,0x1,0x2,0x3,0x1,0x2,0x6e,0x0,0x8, + 0xd,0xe,0xd,0x8,0xe,0x70,0x0,0x7,0x0,0x5,0x6,0x7,0x5,0x63,0x0,0x4,0x0,0x3,0x9,0x4,0x3,0x63,0x0,0x2,0x0,0x0,0xd,0x2,0x0,0x63, + 0x0,0xd,0x8,0xb,0xd,0x57,0x11,0xf,0x10,0x3,0xe,0xc,0x1,0xa,0xb,0xe,0xa,0x63,0x0,0xd,0xd,0xb,0x5c,0x0,0xb,0xd,0xb,0x50,0x59,0x40, + 0x22,0x6b,0x6b,0x4c,0x4c,0x6b,0x6d,0x6b,0x6d,0x4c,0x6a,0x4c,0x69,0x66,0x64,0x5c,0x5a,0x57,0x55,0x52,0x50,0x4a,0x49,0x1f,0x27,0x13,0x24,0x33,0x34,0x24, + 0x17,0x21,0x12,0x7,0x1d,0x2b,0xb1,0x6,0x0,0x44,0x0,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35, + 0x34,0x26,0x23,0x23,0x22,0x35,0x34,0x36,0x33,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32, + 0x16,0x16,0x15,0x14,0x7,0x16,0x16,0x15,0x4,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x32,0x17,0x12,0x16,0x15,0x14, + 0x6,0x23,0x23,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x21,0x22,0x26,0x35,0x34,0x36,0x37,0x1,0x36,0x36,0x33,0x32,0x16,0x15,0x11,0x33,0x23,0x13,0x3, + 0x2,0x1e,0x88,0x84,0x3e,0x7b,0x31,0x13,0x7,0xf,0x1a,0x8,0x8,0x2b,0x5f,0x2d,0x4b,0x52,0x4f,0x4a,0x2c,0x24,0x12,0x12,0x21,0x46,0x48,0x4a,0x41,0x53, + 0x59,0x7,0x9,0x19,0x10,0x6,0x12,0x30,0x77,0x3b,0x4c,0x6f,0x3c,0x5e,0x37,0x3d,0x2,0x3f,0xe,0xfc,0x6a,0x7,0x9,0x17,0x15,0xe,0xe,0x3,0x96,0x7, + 0x9,0x17,0x15,0x6e,0x14,0x14,0x14,0x5b,0x1a,0x1e,0x1e,0x1b,0xfe,0xc6,0x14,0x19,0x6,0x8,0x1,0x3d,0xf,0x1f,0x15,0x1d,0x2d,0x5b,0xcc,0x5,0xdd,0x3, + 0xe,0x71,0x1b,0x1b,0xa,0x17,0xd,0x13,0x27,0x4,0x15,0x1a,0x37,0x32,0x37,0x2e,0x33,0x18,0x1d,0x30,0x35,0x31,0x32,0x2e,0x4,0x27,0x11,0xf,0x17,0xa, + 0x1a,0x1c,0x32,0x5b,0x3a,0x64,0x33,0x12,0x53,0x3e,0x49,0x14,0x13,0x8,0xfd,0xcf,0x4,0x1c,0x14,0x12,0x12,0x9,0x2,0x31,0x4,0x1c,0xfd,0x12,0x18,0x1c, + 0x1c,0x19,0x99,0x14,0x14,0x14,0x14,0x99,0x21,0x20,0xf,0x13,0xb,0x1,0x79,0x13,0x12,0x1b,0x14,0xfe,0x8c,0x1,0xa,0xfe,0xf6,0x0,0x0,0x0,0x0,0x1, + 0x1,0x3b,0x1,0xe3,0x3,0xb3,0x5,0x36,0x0,0x1f,0x0,0x6,0xb3,0x16,0xb,0x1,0x30,0x2b,0x1,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x25,0x36, + 0x33,0x32,0x16,0x15,0x11,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x35,0x34,0x36,0x33,0x33,0x11,0x1,0x8b,0xb,0xc,0x10,0x17,0x8,0x6,0x23,0x1, + 0x1c,0xb,0xd,0x13,0x17,0xc2,0x19,0x18,0x18,0x19,0xfd,0xeb,0x32,0x19,0x19,0xcc,0x4,0x62,0x4,0x16,0x17,0x12,0xf,0x20,0xb,0x5b,0x4,0x15,0x15,0xfd, + 0x54,0x1d,0x21,0x21,0x1e,0x3f,0x21,0x1d,0x2,0x3b,0x0,0x0,0x0,0x1,0x1,0x20,0x1,0xe3,0x3,0xa7,0x5,0x36,0x0,0x29,0x0,0x6,0xb3,0xd,0x0,0x1, + 0x30,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x7,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x35,0x34,0x37,0x1,0x36,0x36,0x35,0x34,0x26,0x23,0x22, + 0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x2,0xc0,0x81,0x44,0x4f,0x54,0xef,0x1,0x83,0x19,0x18,0x18,0x19,0xfd,0xd9,0x2f, + 0x1f,0x1,0x4c,0x39,0x35,0x50,0x4a,0x33,0x75,0x35,0xc,0x7,0xf,0x19,0x8,0x9,0x16,0x3d,0x97,0x48,0x5,0x36,0x3f,0x74,0x4d,0x4d,0x7d,0x46,0xc6,0x1d, + 0x21,0x21,0x1e,0x48,0x27,0x1a,0x1,0x18,0x31,0x50,0x31,0x3a,0x45,0x22,0x1b,0x5,0x19,0x14,0x19,0xf,0x1c,0xc,0x21,0x25,0x0,0x1,0x1,0x2e,0x1,0xd1, + 0x3,0x9e,0x5,0x36,0x0,0x3a,0x0,0x6,0xb3,0xa,0x0,0x1,0x30,0x2b,0x0,0x16,0x16,0x15,0x14,0x7,0x16,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27,0x26, + 0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x23,0x22,0x35,0x34,0x36,0x33,0x33,0x32,0x36,0x35,0x34,0x26,0x23, + 0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x2,0xb6,0x86,0x47,0x70,0x42,0x49,0xa3,0x9e,0x4a,0x94,0x3b,0x16,0x8,0x9,0x19,0xf, + 0x9,0xa,0x33,0x73,0x36,0x5a,0x62,0x5f,0x59,0x34,0x2c,0x15,0x17,0x27,0x54,0x56,0x58,0x4e,0x62,0x6c,0xa,0x9,0x1e,0x13,0x8,0x16,0x3a,0x8d,0x48,0x5, + 0x36,0x3c,0x6c,0x46,0x79,0x3c,0x16,0x64,0x4a,0x77,0x87,0x21,0x20,0xc,0x1b,0x11,0x16,0x16,0x19,0x5,0x1a,0x1e,0x41,0x3d,0x42,0x36,0x3e,0x1c,0x23,0x3a, + 0x3f,0x3a,0x3d,0x37,0x5,0x2f,0x15,0x10,0x1e,0xb,0x1f,0x21,0x0,0x2,0x0,0xf2,0x1,0xdb,0x3,0xc4,0x5,0x36,0x0,0x1e,0x0,0x21,0x0,0x8,0xb5,0x20, + 0x1f,0x18,0x9,0x2,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x21,0x22,0x26,0x35,0x34,0x36,0x37,0x1,0x36, + 0x36,0x33,0x32,0x16,0x15,0x11,0x33,0x23,0x13,0x1,0x3,0xac,0x18,0x18,0x18,0x6d,0x1f,0x24,0x24,0x20,0xfe,0x88,0x19,0x1d,0x8,0x9,0x1,0x7b,0x13,0x24, + 0x1a,0x22,0x36,0x6d,0xf4,0x6,0xfe,0xf7,0x3,0x40,0x1d,0x21,0x21,0x1e,0xb8,0x18,0x18,0x18,0x18,0xb8,0x27,0x27,0x11,0x18,0xc,0x1,0xc4,0x17,0x15,0x20, + 0x18,0xfe,0x42,0x1,0x3f,0xfe,0xc1,0x0,0x0,0x2,0x3,0xb,0xff,0xf6,0x4,0x19,0x3,0xa6,0x0,0xd,0x0,0x1b,0x0,0x8,0xb5,0x13,0xe,0x5,0x0,0x2, + 0x30,0x2b,0x0,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x12,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33, + 0x3,0xda,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x3,0xa6,0x1d,0x22,0xb8,0x22,0x1d,0x1d,0x22,0xb8,0x22,0x1d,0xfd, + 0x86,0x1d,0x22,0xb8,0x22,0x1d,0x1d,0x22,0xb8,0x22,0x1d,0x0,0x0,0x0,0xff,0xff,0x2,0xa0,0xfe,0xda,0x4,0x19,0x1,0x26,0x0,0x3,0x1,0x27,0x1,0x2c, + 0x0,0x0,0x0,0x0,0xff,0xff,0x3,0xb,0xff,0xf6,0x4,0x19,0x1,0x2c,0x0,0x3,0x1,0x2c,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x2,0x2,0xb4,0xfe,0xda, + 0x4,0x2d,0x3,0xa6,0x0,0xd,0x0,0x1e,0x0,0x8,0xb5,0x14,0xe,0x5,0x0,0x2,0x30,0x2b,0x0,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34, + 0x36,0x33,0x12,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x3,0xda,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x89,0x12, + 0x7,0xd4,0x12,0x44,0x48,0x2,0x5e,0x4,0x1b,0x15,0xc2,0x3,0xa6,0x1d,0x22,0xb8,0x22,0x1d,0x1d,0x22,0xb8,0x22,0x1d,0xfd,0x80,0x13,0xf,0xe,0xf,0xfe, + 0x1c,0x29,0x32,0x4,0xc,0x1,0xe2,0x13,0x15,0x0,0x0,0x0,0x0,0x3,0xfe,0x39,0xff,0xea,0x6,0x93,0x1,0x3c,0x0,0xf,0x0,0x1f,0x0,0x2f,0x0,0xa, + 0xb7,0x2a,0x22,0x1a,0x12,0xa,0x2,0x3,0x30,0x2b,0x24,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x24,0x36,0x36,0x33, + 0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x24,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0xfe,0x39, + 0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x3,0x84,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x3,0x84,0x2e,0x4d, + 0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0xc1,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d, + 0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x0,0x0,0x0,0x3,0x3,0x5,0xff,0xea,0xb,0x5f,0x1,0x3c,0x0,0xf, + 0x0,0x1f,0x0,0x2f,0x0,0xa,0xb7,0x2a,0x22,0x1a,0x12,0xa,0x2,0x3,0x30,0x2b,0x24,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26, + 0x26,0x35,0x24,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x24,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23, + 0x22,0x26,0x26,0x35,0x3,0x5,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x3,0x84,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e, + 0x4d,0x2e,0x3,0x84,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0xc1,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d, + 0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x0,0x0,0x0,0x3,0x1,0x18,0xff,0xea, + 0x6,0x5c,0x0,0xf4,0x0,0xf,0x0,0x1f,0x0,0x2f,0x0,0xa,0xb7,0x26,0x20,0x16,0x10,0x6,0x0,0x3,0x30,0x2b,0x24,0x16,0x16,0x15,0x14,0x6,0x6,0x23, + 0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x20,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x20,0x16,0x16,0x15,0x14,0x6, + 0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x1,0xc1,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x2,0x41,0x3d,0x24,0x24,0x3d,0x24, + 0x24,0x3d,0x24,0x24,0x3d,0x24,0x2,0x41,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0xf4,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24, + 0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x0,0x3,0xfe,0x20, + 0xff,0xea,0x4,0x7c,0x0,0xf4,0x0,0xf,0x0,0x1f,0x0,0x2f,0x0,0xa,0xb7,0x26,0x20,0x16,0x10,0x6,0x0,0x3,0x30,0x2b,0x24,0x16,0x16,0x15,0x14,0x6, + 0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x20,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x20,0x16,0x16,0x15, + 0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xfe,0xc9,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x2,0xcd,0x3d,0x24,0x24, + 0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x2,0xcd,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0xf4,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d, + 0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x24,0x3d,0x24,0x0,0x3, + 0x3,0x5,0xff,0xea,0xc,0x8b,0x1,0x3c,0x0,0xf,0x0,0x1f,0x0,0x2f,0x0,0xa,0xb7,0x2a,0x22,0x1a,0x12,0xa,0x2,0x3,0x30,0x2b,0x24,0x36,0x36,0x33, + 0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x24,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x24,0x36, + 0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x3,0x5,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x4,0x1a, + 0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x4,0x1a,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0xc1,0x4d,0x2e,0x2e, + 0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e,0x4d,0x2e,0x2e, + 0x4d,0x2e,0x0,0x0,0x0,0x1,0x0,0x6a,0x0,0x91,0x4,0x62,0x4,0x67,0x0,0x37,0x0,0x2b,0x40,0x28,0x2f,0x27,0x2,0x2,0x3,0x31,0x26,0x1e,0x1a,0x10, + 0x5,0x6,0x0,0x2,0x2,0x4a,0x0,0x3,0x2,0x3,0x72,0x4,0x1,0x2,0x0,0x2,0x72,0x1,0x1,0x0,0x0,0x69,0x26,0x27,0x2e,0x25,0x2b,0x5,0x7,0x19, + 0x2b,0x0,0x15,0x14,0x6,0x7,0x5,0x13,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x3,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x13,0x25,0x26, + 0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x5,0x3,0x26,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x7,0x3,0x25,0x36,0x33,0x32,0x16,0x17,0x4,0x62,0x26, + 0x22,0xfe,0x9f,0xfb,0x1b,0x2d,0x1f,0x1d,0x16,0x25,0xe,0xb7,0xb7,0x1e,0x2b,0x1d,0x1f,0x2e,0x1b,0xfb,0xfe,0x9f,0x22,0x25,0x7,0xa,0x28,0x1b,0x16,0x15, + 0x1,0x49,0x29,0x1,0x31,0x2d,0x2e,0x30,0x1,0x2a,0x1,0x4a,0x15,0x16,0x1a,0x28,0xb,0x2,0xe5,0xf,0x1f,0x28,0x8,0x48,0xfe,0xeb,0x1c,0x1f,0x27,0x21, + 0x16,0x1a,0x17,0x1,0x40,0xfe,0xc0,0x31,0x16,0x21,0x27,0x1f,0x1c,0x1,0x15,0x48,0x8,0x28,0x1e,0x13,0x15,0x22,0x23,0xa,0x96,0x1,0x64,0x5,0xa,0x26, + 0x2c,0x2c,0x27,0xe,0xfe,0x9c,0x96,0xa,0x23,0x22,0x0,0x1,0x0,0xc6,0xfe,0x9d,0x4,0x6,0x5,0x72,0x0,0x11,0x0,0x36,0xb6,0xe,0x5,0x2,0x0,0x1, + 0x1,0x4a,0x4b,0xb0,0x17,0x50,0x58,0x40,0xc,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x13,0x0,0x4c,0x1b,0x40,0xa,0x2,0x1,0x1,0x0,0x1,0x72, + 0x0,0x0,0x0,0x69,0x59,0x40,0xa,0x0,0x0,0x0,0x11,0x0,0x10,0x27,0x3,0x7,0x15,0x2b,0x0,0x16,0x17,0x1,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27, + 0x1,0x26,0x35,0x34,0x36,0x33,0x1,0x39,0x23,0x7,0x2,0xa0,0x3,0x34,0x28,0x17,0x23,0x7,0xfd,0x60,0x3,0x34,0x28,0x5,0x72,0x14,0x10,0xf9,0x95,0x9, + 0x8,0x17,0x1e,0x14,0x10,0x6,0x6b,0x9,0x8,0x17,0x1e,0x0,0x0,0x0,0xff,0xff,0x1,0xdf,0x1,0xa9,0x2,0xed,0x2,0xdf,0x1,0x7,0x1,0x2c,0x0,0x0, + 0x1,0xb3,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xb3,0xb0,0x33,0x2b,0x0,0x0,0x0,0x0,0x1,0x1,0x7e,0x1,0x63,0x3,0x4e,0x3,0x55,0x0,0xd,0x0,0x1f, + 0x40,0x1c,0x2,0x1,0x1,0x0,0x0,0x1,0x57,0x2,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x0,0x0,0x0,0xd,0x0,0xc,0x25,0x3,0x7,0x15, + 0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x2,0xe1,0x6d,0x6d,0x7b,0x7b,0x6d,0x6d,0x7b,0x3,0x55,0x2e,0x34,0xfe,0xd2, + 0x34,0x2e,0x2e,0x34,0x1,0x2e,0x34,0x2e,0x0,0x0,0x0,0x2,0x1,0xdf,0xff,0xf6,0x2,0xed,0x3,0xa6,0x0,0xd,0x0,0x1b,0x0,0x2c,0x40,0x29,0x0,0x0, + 0x0,0x1,0x5b,0x4,0x1,0x1,0x1,0x11,0x4b,0x5,0x1,0x3,0x3,0x2,0x5b,0x0,0x2,0x2,0xf,0x2,0x4c,0xe,0xe,0x0,0x0,0xe,0x1b,0xe,0x1a,0x15, + 0x13,0x0,0xd,0x0,0xc,0x25,0x6,0x7,0x15,0x2b,0x0,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x12,0x16,0x15,0x15,0x14,0x6, + 0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x2,0xae,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x3,0xa6,0x1d,0x22,0xb8, + 0x22,0x1d,0x1d,0x22,0xb8,0x22,0x1d,0xfd,0x86,0x1d,0x22,0xb8,0x22,0x1d,0x1d,0x22,0xb8,0x22,0x1d,0x0,0x0,0x0,0x0,0x1,0x1,0x74,0xfe,0xda,0x2,0xed, + 0x1,0x26,0x0,0x10,0x0,0x1e,0x40,0x1b,0x9,0x1,0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f, + 0x26,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x2,0xdb,0x12,0x7,0xd4,0x12,0x44, + 0x48,0x2,0x5e,0x4,0x1b,0x15,0xc2,0x1,0x26,0x13,0xf,0xe,0xf,0xfe,0x1c,0x29,0x32,0x4,0xc,0x1,0xe2,0x13,0x15,0x0,0x0,0x3,0x0,0x6d,0xff,0xf6, + 0x4,0x5f,0x0,0xe6,0x0,0xd,0x0,0x1b,0x0,0x29,0x0,0x2f,0x40,0x2c,0x8,0x5,0x7,0x3,0x6,0x5,0x1,0x1,0x0,0x5b,0x4,0x2,0x2,0x0,0x0,0xf, + 0x0,0x4c,0x1c,0x1c,0xe,0xe,0x0,0x0,0x1c,0x29,0x1c,0x28,0x23,0x21,0xe,0x1b,0xe,0x1a,0x15,0x13,0x0,0xd,0x0,0xc,0x25,0x9,0x7,0x15,0x2b,0x24, + 0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x20,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x20,0x16,0x15, + 0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x1,0xe,0x31,0x31,0x38,0x38,0x31,0x31,0x38,0x1,0xc8,0x31,0x31,0x38,0x38,0x31,0x31,0x38,0x1, + 0xc8,0x31,0x31,0x38,0x38,0x31,0x31,0x38,0xe6,0x19,0x1c,0x86,0x1c,0x19,0x19,0x1c,0x86,0x1c,0x19,0x19,0x1c,0x86,0x1c,0x19,0x19,0x1c,0x86,0x1c,0x19,0x19, + 0x1c,0x86,0x1c,0x19,0x19,0x1c,0x86,0x1c,0x19,0x0,0x0,0x0,0x0,0x2,0x1,0xe9,0xff,0xf6,0x2,0xe3,0x4,0xf5,0x0,0xe,0x0,0x1c,0x0,0x32,0x40,0x2f, + 0xa,0x3,0x2,0x3,0x0,0x1,0x1,0x4a,0x4,0x1,0x1,0x0,0x0,0x3,0x1,0x0,0x63,0x5,0x1,0x3,0x3,0x2,0x5b,0x0,0x2,0x2,0xf,0x2,0x4c,0xf, + 0xf,0x0,0x0,0xf,0x1c,0xf,0x1b,0x16,0x14,0x0,0xe,0x0,0xc,0x25,0x6,0x7,0x15,0x2b,0x0,0x16,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x26, + 0x36,0x33,0x33,0x12,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x2,0xbe,0x14,0x2,0x31,0x2,0x1d,0x1a,0x1a,0x1f,0x1,0x30,0x2, + 0x14,0x17,0x82,0x1,0x3b,0x3b,0x42,0x42,0x3b,0x3b,0x42,0x4,0xf5,0x18,0x1a,0xfd,0x3d,0x17,0x19,0x19,0x17,0x2,0xc3,0x1a,0x18,0xfc,0x19,0x1d,0x22,0x9a, + 0x22,0x1d,0x1d,0x22,0x9a,0x22,0x1d,0x0,0x0,0x0,0x0,0x2,0x1,0xe9,0xfe,0xa7,0x2,0xe3,0x3,0xa6,0x0,0xd,0x0,0x1c,0x0,0x31,0x40,0x2e,0x18,0x11, + 0x10,0x3,0x3,0x2,0x1,0x4a,0x0,0x2,0x5,0x1,0x3,0x2,0x3,0x5f,0x4,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x11,0x1,0x4c,0xe,0xe,0x0,0x0, + 0xe,0x1c,0xe,0x1a,0x15,0x13,0x0,0xd,0x0,0xc,0x25,0x6,0x7,0x15,0x2b,0x0,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x14,0x6,0x23,0x2, + 0x26,0x37,0x13,0x36,0x36,0x33,0x32,0x16,0x17,0x13,0x16,0x6,0x23,0x23,0x2,0x24,0x3b,0x3b,0x42,0x42,0x3b,0x3b,0x42,0x58,0x14,0x2,0x31,0x2,0x1d,0x1a, + 0x1a,0x1f,0x1,0x30,0x2,0x14,0x17,0x82,0x2,0x8e,0x1d,0x22,0x9a,0x22,0x1d,0x1d,0x22,0x9a,0x22,0x1d,0xfc,0x19,0x18,0x1a,0x2,0xc3,0x17,0x19,0x19,0x17, + 0xfd,0x3d,0x1a,0x18,0x0,0x2,0x0,0x3c,0xff,0xea,0x4,0x90,0x4,0xb9,0x0,0x4b,0x0,0x4f,0x0,0x53,0x40,0x50,0x47,0x3c,0x2,0x9,0xa,0x21,0x16,0x2, + 0x3,0x2,0x2,0x4a,0x10,0xd,0xb,0x3,0x9,0xe,0x8,0x2,0x0,0x1,0x9,0x0,0x62,0xf,0x7,0x2,0x1,0x6,0x4,0x2,0x2,0x3,0x1,0x2,0x61,0xc, + 0x1,0xa,0xa,0x16,0x4b,0x5,0x1,0x3,0x3,0x17,0x3,0x4c,0x0,0x0,0x4f,0x4e,0x4d,0x4c,0x0,0x4b,0x0,0x4a,0x45,0x43,0x40,0x3f,0x3a,0x38,0x35,0x33, + 0x21,0x24,0x25,0x23,0x15,0x23,0x24,0x21,0x24,0x11,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x7,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x3, + 0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x37,0x23, + 0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x13,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x21,0x13,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x33,0x5, + 0x21,0x7,0x21,0x4,0x73,0x1d,0x1d,0x22,0xc2,0x40,0xbc,0x22,0x1d,0x1d,0x22,0xe2,0x53,0x4,0x1f,0x13,0x1c,0x2c,0x2,0x4b,0xfe,0xfa,0x53,0x4,0x1f,0x13, + 0x1c,0x2c,0x2,0x4b,0xa0,0x22,0x1d,0x1d,0x22,0xc5,0x40,0xbf,0x22,0x1d,0x1d,0x22,0xe4,0x51,0x4,0x1f,0x13,0x1c,0x2c,0x2,0x48,0x1,0x5,0x51,0x4,0x1f, + 0x13,0x1c,0x2c,0x2,0x48,0x9d,0xfe,0xb9,0xfe,0xfb,0x40,0x1,0x5,0x3,0x61,0x21,0x27,0x27,0x21,0xf5,0x21,0x27,0x27,0x21,0xfe,0xbf,0x10,0x11,0x1e,0x18, + 0x3,0xa,0x1,0x1f,0xfe,0xbf,0x10,0x11,0x1e,0x18,0x3,0xa,0x1,0x1f,0x21,0x27,0x27,0x21,0xf5,0x21,0x27,0x27,0x21,0x1,0x37,0x10,0x11,0x1e,0x18,0x3, + 0xa,0xfe,0xeb,0x1,0x37,0x10,0x11,0x1e,0x18,0x3,0xa,0xfe,0xeb,0x90,0xf5,0x0,0x0,0x1,0x1,0xdf,0xff,0xf6,0x2,0xed,0x1,0x2c,0x0,0xd,0x0,0x19, + 0x40,0x16,0x2,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0xd,0x0,0xc,0x25,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x15,0x14, + 0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x2,0xae,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x1,0x2c,0x1d,0x22,0xb8,0x22,0x1d,0x1d,0x22,0xb8,0x22,0x1d, + 0x0,0x0,0x0,0x2,0x1,0x6,0xff,0xf6,0x3,0xc6,0x4,0xf5,0x0,0x26,0x0,0x34,0x0,0x43,0x40,0x40,0xe,0x8,0x7,0x3,0x0,0x2,0x1,0x4a,0x0,0x2, + 0x1,0x0,0x1,0x2,0x0,0x70,0x0,0x0,0x5,0x1,0x0,0x5,0x6e,0x6,0x1,0x3,0x0,0x1,0x2,0x3,0x1,0x63,0x7,0x1,0x5,0x5,0x4,0x5b,0x0,0x4, + 0x4,0xf,0x4,0x4c,0x27,0x27,0x0,0x0,0x27,0x34,0x27,0x33,0x2e,0x2c,0x0,0x26,0x0,0x25,0x22,0x2d,0x2a,0x8,0x7,0x17,0x2b,0x0,0x16,0x16,0x15,0x14, + 0x6,0x6,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x27,0x26,0x36,0x37,0x37,0x3e,0x2,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34, + 0x37,0x36,0x33,0x12,0x16,0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x2,0xd6,0x9d,0x53,0x45,0x87,0x6d,0xa,0x2,0x24,0x1f,0x1f,0x24, + 0x2,0xa,0x1,0xe,0x11,0x45,0x50,0x5d,0x2d,0x65,0x5c,0x85,0x80,0xf,0x10,0x21,0x14,0xc,0x26,0x90,0xae,0x11,0x36,0x36,0x3d,0x3d,0x36,0x36,0x3d,0x4, + 0xf5,0x4f,0x8d,0x5d,0x56,0x7b,0x5b,0x2d,0xab,0x18,0x1b,0x1b,0x18,0xe1,0x14,0x18,0x7,0x1c,0x21,0x3a,0x48,0x31,0x4b,0x5a,0x43,0x9,0x2e,0x1b,0x13,0x21, + 0x15,0x4e,0xfb,0xf1,0x1d,0x22,0x72,0x22,0x1d,0x1d,0x22,0x72,0x22,0x1d,0x0,0x0,0x0,0x2,0x1,0x6,0xfe,0xa7,0x3,0xc6,0x3,0xa6,0x0,0xd,0x0,0x34, + 0x0,0x44,0x40,0x41,0x1c,0x16,0x15,0x3,0x4,0x2,0x1,0x4a,0x0,0x2,0x1,0x4,0x1,0x2,0x4,0x70,0x0,0x4,0x3,0x1,0x4,0x3,0x6e,0x0,0x3,0x7, + 0x1,0x5,0x3,0x5,0x60,0x6,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x11,0x1,0x4c,0xe,0xe,0x0,0x0,0xe,0x34,0xe,0x33,0x2d,0x2b,0x29,0x27,0x1a, + 0x18,0x0,0xd,0x0,0xc,0x25,0x8,0x7,0x15,0x2b,0x0,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x14,0x6,0x23,0x2,0x26,0x26,0x35,0x34,0x36, + 0x36,0x37,0x37,0x36,0x36,0x33,0x32,0x16,0x17,0x17,0x16,0x6,0x7,0x7,0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7, + 0x6,0x23,0x2,0x51,0x36,0x36,0x3d,0x3d,0x36,0x36,0x3d,0x98,0x9d,0x53,0x45,0x87,0x6d,0xa,0x2,0x24,0x1f,0x1f,0x24,0x2,0xa,0x1,0xe,0x11,0x45,0x50, + 0x5d,0x2d,0x65,0x5c,0x85,0x80,0xf,0x10,0x21,0x14,0xc,0x26,0x90,0xae,0x2,0xb6,0x1d,0x22,0x72,0x22,0x1d,0x1d,0x22,0x72,0x22,0x1d,0xfb,0xf1,0x4f,0x8d, + 0x5d,0x56,0x7b,0x5b,0x2d,0xab,0x18,0x1b,0x1b,0x18,0xe1,0x14,0x18,0x7,0x1c,0x21,0x3a,0x48,0x31,0x4b,0x5a,0x43,0x9,0x2e,0x1b,0x13,0x21,0x15,0x4e,0x0, + 0xff,0xff,0x0,0xff,0x2,0xcb,0x3,0xc8,0x4,0xf5,0x0,0x23,0x1,0x30,0xff,0x1a,0x0,0x0,0x0,0x3,0x1,0x30,0x0,0xe6,0x0,0x0,0x0,0x0,0x0,0x1, + 0x1,0xe5,0x2,0xcb,0x2,0xe2,0x4,0xf5,0x0,0xd,0x0,0x25,0x40,0x22,0x1,0x1,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1, + 0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x0,0x0,0x0,0xd,0x0,0xb,0x25,0x3,0x7,0x15,0x2b,0x0,0x15,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x3, + 0x26,0x33,0x33,0x2,0xe2,0x1,0x37,0x3,0x23,0x1e,0x1d,0x24,0x3,0x37,0x6,0x2f,0xa4,0x4,0xf5,0x27,0xb,0xfe,0x3e,0x1a,0x1c,0x1c,0x1a,0x1,0xc2,0x32, + 0x0,0x2,0x1,0x88,0xfe,0xda,0x3,0x1,0x3,0xa6,0x0,0xd,0x0,0x1e,0x0,0x2a,0x40,0x27,0x17,0x1,0x2,0x3,0x1,0x4a,0x0,0x3,0x0,0x2,0x3,0x2, + 0x5f,0x0,0x0,0x0,0x1,0x5b,0x4,0x1,0x1,0x1,0x11,0x0,0x4c,0x0,0x0,0x1e,0x1c,0x16,0x14,0x0,0xd,0x0,0xc,0x25,0x5,0x7,0x15,0x2b,0x0,0x16, + 0x15,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x12,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x2, + 0xae,0x3f,0x3f,0x48,0x48,0x3f,0x3f,0x48,0x89,0x12,0x7,0xd4,0x12,0x44,0x48,0x2,0x5e,0x4,0x1b,0x15,0xc2,0x3,0xa6,0x1d,0x22,0xb8,0x22,0x1d,0x1d,0x22, + 0xb8,0x22,0x1d,0xfd,0x80,0x13,0xf,0xe,0xf,0xfe,0x1c,0x29,0x32,0x4,0xc,0x1,0xe2,0x13,0x15,0x0,0x0,0x1,0x0,0xc6,0xfe,0x9d,0x4,0x6,0x5,0x72, + 0x0,0x11,0x0,0x36,0xb6,0xb,0x2,0x2,0x0,0x1,0x1,0x4a,0x4b,0xb0,0x17,0x50,0x58,0x40,0xc,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x13,0x0, + 0x4c,0x1b,0x40,0xa,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x59,0x40,0xa,0x0,0x0,0x0,0x11,0x0,0x10,0x27,0x3,0x7,0x15,0x2b,0x0,0x16, + 0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x3,0xd2,0x34,0x3,0xfd,0x60,0x7,0x23,0x17,0x28,0x34,0x3,0x2,0xa0, + 0x7,0x23,0x17,0x5,0x72,0x1e,0x17,0x8,0x9,0xf9,0x95,0x10,0x14,0x1e,0x17,0x8,0x9,0x6,0x6b,0x10,0x14,0x0,0x0,0x0,0x0,0x1,0x0,0x46,0xfe,0x77, + 0x4,0x86,0xff,0x7,0x0,0xd,0x0,0x27,0xb1,0x6,0x64,0x44,0x40,0x1c,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1, + 0x0,0x4d,0x0,0x0,0x0,0xd,0x0,0xb,0x34,0x3,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x4,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33, + 0x21,0x4,0x69,0x1d,0x1d,0x22,0xfc,0x3e,0x22,0x1d,0x1d,0x22,0x3,0xc2,0xf9,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xb1, + 0xfe,0xb3,0x3,0xde,0x5,0x5c,0x0,0x3c,0x0,0xe0,0x40,0xa,0x37,0x1,0x4,0x0,0xe,0x1,0x3,0x4,0x2,0x4a,0x4b,0xb0,0xc,0x50,0x58,0x40,0x21,0x6, + 0x1,0x5,0x0,0x0,0x4,0x5,0x0,0x63,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x2,0x2,0x1,0x57,0x0,0x1,0x1,0x2,0x5b,0x0,0x2,0x1, + 0x2,0x4f,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x1b,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x0,0x2,0x1,0x2,0x5f,0x0,0x0,0x0,0x5,0x5b, + 0x6,0x1,0x5,0x5,0x10,0x0,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x21,0x6,0x1,0x5,0x0,0x0,0x4,0x5,0x0,0x63,0x0,0x4,0x0,0x3,0x1,0x4, + 0x3,0x63,0x0,0x1,0x2,0x2,0x1,0x57,0x0,0x1,0x1,0x2,0x5b,0x0,0x2,0x1,0x2,0x4f,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x1b,0x0,0x4,0x0,0x3, + 0x1,0x4,0x3,0x63,0x0,0x1,0x0,0x2,0x1,0x2,0x5f,0x0,0x0,0x0,0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x0,0x4c,0x1b,0x40,0x21,0x6,0x1,0x5,0x0, + 0x0,0x4,0x5,0x0,0x63,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x2,0x2,0x1,0x57,0x0,0x1,0x1,0x2,0x5b,0x0,0x2,0x1,0x2,0x4f,0x59, + 0x59,0x59,0x59,0x40,0x12,0x0,0x0,0x0,0x3c,0x0,0x3b,0x32,0x30,0x2c,0x2a,0x21,0x1f,0x1b,0x19,0x24,0x7,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x6,0x23, + 0x22,0x6,0x6,0x15,0x17,0x17,0x16,0x6,0x7,0x15,0x16,0x16,0x15,0x14,0x7,0x7,0x6,0x15,0x14,0x16,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x35, + 0x34,0x37,0x37,0x36,0x35,0x34,0x26,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x32,0x36,0x35,0x34,0x27,0x27,0x26,0x35,0x34,0x36,0x33,0x3,0xc1,0x1d,0x1d,0x22, + 0x64,0x78,0x35,0x1,0x3,0x5,0x6f,0x7f,0x7e,0x71,0x1,0x8,0x1,0x83,0x8e,0x22,0x1d,0x1d,0x22,0xc9,0xdf,0x2,0xb,0x2,0x86,0x90,0x22,0x1d,0x1d,0x22, + 0x8b,0x84,0x1,0x5,0x2,0xdd,0xcb,0x5,0x5c,0x21,0x27,0x27,0x21,0x34,0x6e,0x5a,0x1d,0x48,0x78,0x9d,0x34,0xa,0x25,0x8f,0x6e,0x16,0xb,0x79,0xd,0x19, + 0x7f,0x74,0x21,0x27,0x27,0x21,0xb4,0xb4,0x23,0x12,0x7b,0x1c,0xc,0x71,0x71,0x21,0x27,0x27,0x21,0x7e,0x74,0x14,0xa,0x4a,0x1e,0xd,0xb9,0xb9,0x0,0x1, + 0x0,0xee,0xfe,0xb3,0x4,0x1b,0x5,0x5c,0x0,0x3b,0x0,0xdd,0x40,0xa,0x2c,0x1,0x1,0x0,0x15,0x1,0x3,0x1,0x2,0x4a,0x4b,0xb0,0xc,0x50,0x58,0x40, + 0x21,0x6,0x1,0x5,0x0,0x4,0x0,0x5,0x4,0x63,0x0,0x0,0x0,0x1,0x3,0x0,0x1,0x63,0x0,0x3,0x2,0x2,0x3,0x57,0x0,0x3,0x3,0x2,0x5b,0x0, + 0x2,0x3,0x2,0x4f,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x1b,0x0,0x0,0x0,0x1,0x3,0x0,0x1,0x63,0x0,0x3,0x0,0x2,0x3,0x2,0x5f,0x0,0x4,0x4, + 0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x4,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x21,0x6,0x1,0x5,0x0,0x4,0x0,0x5,0x4,0x63,0x0,0x0,0x0,0x1, + 0x3,0x0,0x1,0x63,0x0,0x3,0x2,0x2,0x3,0x57,0x0,0x3,0x3,0x2,0x5b,0x0,0x2,0x3,0x2,0x4f,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x1b,0x0,0x0, + 0x0,0x1,0x3,0x0,0x1,0x63,0x0,0x3,0x0,0x2,0x3,0x2,0x5f,0x0,0x4,0x4,0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x4,0x4c,0x1b,0x40,0x21,0x6,0x1, + 0x5,0x0,0x4,0x0,0x5,0x4,0x63,0x0,0x0,0x0,0x1,0x3,0x0,0x1,0x63,0x0,0x3,0x2,0x2,0x3,0x57,0x0,0x3,0x3,0x2,0x5b,0x0,0x2,0x3,0x2, + 0x4f,0x59,0x59,0x59,0x59,0x40,0xf,0x0,0x0,0x0,0x3b,0x0,0x3a,0x36,0x34,0x24,0x29,0x24,0x29,0x7,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6, + 0x15,0x14,0x16,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x22,0x6,0x15,0x14,0x17,0x17,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x32,0x36,0x35, + 0x34,0x27,0x27,0x26,0x35,0x34,0x36,0x37,0x35,0x26,0x26,0x37,0x37,0x36,0x26,0x26,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x1,0xf8,0xdd,0x2,0x5,0x1,0x84, + 0x8b,0x22,0x1d,0x1d,0x22,0x90,0x86,0x2,0xb,0x2,0xdf,0xc9,0x22,0x1d,0x1d,0x22,0x8e,0x83,0x1,0x8,0x1,0x71,0x7e,0x7f,0x6f,0x5,0x3,0x4,0x31,0x79, + 0x6a,0x22,0x1d,0x1d,0x22,0x5,0x5c,0xb9,0xb9,0xd,0x1e,0x4a,0xa,0x14,0x74,0x7e,0x21,0x27,0x27,0x21,0x71,0x71,0xc,0x1c,0x7b,0x12,0x23,0xb4,0xb4,0x21, + 0x27,0x27,0x21,0x74,0x7f,0x19,0xd,0x79,0xb,0x16,0x6e,0x8f,0x25,0xa,0x34,0x9d,0x78,0x48,0x64,0x7b,0x3a,0x21,0x27,0x27,0x21,0x0,0x0,0x1,0x1,0x4a, + 0xfe,0xb3,0x3,0x66,0x5,0x5c,0x0,0x19,0x0,0xa9,0x4b,0xb0,0xc,0x50,0x58,0x40,0x1a,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x4,0x1,0x3,0x0,0x0, + 0x3,0x55,0x4,0x1,0x3,0x3,0x0,0x59,0x0,0x0,0x3,0x0,0x4d,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x13,0x4,0x1,0x3,0x0,0x0,0x3,0x0,0x5d,0x0, + 0x2,0x2,0x1,0x59,0x0,0x1,0x1,0x10,0x2,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x1a,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x4,0x1,0x3,0x0, + 0x0,0x3,0x55,0x4,0x1,0x3,0x3,0x0,0x59,0x0,0x0,0x3,0x0,0x4d,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x13,0x4,0x1,0x3,0x0,0x0,0x3,0x0,0x5d, + 0x0,0x2,0x2,0x1,0x59,0x0,0x1,0x1,0x10,0x2,0x4c,0x1b,0x40,0x1a,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x4,0x1,0x3,0x0,0x0,0x3,0x55,0x4, + 0x1,0x3,0x3,0x0,0x59,0x0,0x0,0x3,0x0,0x4d,0x59,0x59,0x59,0x59,0x40,0xc,0x0,0x0,0x0,0x19,0x0,0x18,0x24,0x45,0x44,0x5,0x7,0x17,0x2b,0x4, + 0x16,0x15,0x14,0x6,0x23,0x21,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x3,0x49,0x1d,0x1d,0x22, + 0xfe,0xa0,0x3e,0x22,0x1d,0x1d,0x22,0x57,0x1,0x47,0x22,0x1d,0x1d,0x22,0xfe,0xb9,0x1,0x47,0xbd,0x21,0x27,0x27,0x21,0x1f,0x25,0x6,0x21,0x25,0x1f,0x21, + 0x27,0x27,0x21,0xfa,0x77,0x0,0x0,0x0,0x0,0x1,0x1,0x66,0xfe,0xb3,0x3,0x82,0x5,0x5c,0x0,0x19,0x0,0xa6,0x4b,0xb0,0xc,0x50,0x58,0x40,0x19,0x4, + 0x1,0x3,0x0,0x2,0x1,0x3,0x2,0x61,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x1b,0x4b,0xb0,0xe,0x50,0x58, + 0x40,0x13,0x0,0x1,0x0,0x0,0x1,0x0,0x5d,0x0,0x2,0x2,0x3,0x59,0x4,0x1,0x3,0x3,0x10,0x2,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x19,0x4, + 0x1,0x3,0x0,0x2,0x1,0x3,0x2,0x61,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x1b,0x4b,0xb0,0x15,0x50,0x58, + 0x40,0x13,0x0,0x1,0x0,0x0,0x1,0x0,0x5d,0x0,0x2,0x2,0x3,0x59,0x4,0x1,0x3,0x3,0x10,0x2,0x4c,0x1b,0x40,0x19,0x4,0x1,0x3,0x0,0x2,0x1, + 0x3,0x2,0x61,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x59,0x59,0x59,0x59,0x40,0xc,0x0,0x0,0x0,0x19,0x0, + 0x16,0x21,0x24,0x45,0x5,0x7,0x17,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x11,0x21,0x22,0x26,0x35,0x34, + 0x36,0x33,0x21,0x33,0x3,0x65,0x1d,0x1d,0x22,0x57,0xfe,0xb9,0x22,0x1d,0x1d,0x22,0x1,0x47,0xfe,0xb9,0x22,0x1d,0x1d,0x22,0x1,0x60,0x3e,0x5,0x5c,0x1f, + 0x25,0xf9,0xdf,0x25,0x1f,0x21,0x27,0x27,0x21,0x5,0x89,0x21,0x27,0x27,0x21,0x0,0x0,0x1,0x1,0x29,0xfe,0xa9,0x3,0x61,0x5,0x65,0x0,0x1f,0x0,0x10, + 0x40,0xd,0x1,0x1,0x0,0x48,0x0,0x0,0x0,0x69,0x16,0x14,0x1,0x7,0x14,0x2b,0x0,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x2,0x15,0x14,0x12, + 0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x27,0x26,0x26,0x2,0x35,0x34,0x12,0x36,0x37,0x3,0xe,0xa,0x10,0x1d,0xb,0x11,0xd,0xad,0xea,0xe9,0xae, + 0xd,0x11,0xb,0x1d,0x10,0xa,0xb,0x7a,0xd7,0x89,0x89,0xd8,0x79,0x5,0x65,0x16,0x12,0x1d,0x19,0x14,0x9,0x72,0xfe,0x8c,0xff,0xff,0xfe,0x90,0x72,0x9, + 0x14,0x19,0x1d,0x12,0x16,0x6,0x49,0xf3,0x1,0x52,0xc8,0xc8,0x1,0x54,0xf5,0x49,0x0,0x1,0x1,0x6b,0xfe,0xa9,0x3,0xa3,0x5,0x65,0x0,0x1f,0x0,0x10, + 0x40,0xd,0x9,0x1,0x0,0x47,0x0,0x0,0x0,0x69,0x1e,0x1c,0x1,0x7,0x14,0x2b,0x0,0x16,0x12,0x15,0x14,0x2,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26, + 0x35,0x34,0x37,0x36,0x12,0x35,0x34,0x2,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x2,0x42,0xd8,0x89,0x89,0xd7,0x7a,0xb,0xa,0x10,0x1d,0xb, + 0x11,0xd,0xae,0xe9,0xea,0xad,0xd,0x11,0xb,0x1d,0x10,0xa,0xb,0x5,0x16,0xf5,0xfe,0xac,0xc8,0xc8,0xfe,0xae,0xf3,0x49,0x6,0x16,0x12,0x1d,0x19,0x14, + 0x9,0x72,0x1,0x70,0xff,0xff,0x1,0x74,0x72,0x9,0x14,0x19,0x1d,0x12,0x16,0x6,0x0,0x1,0x1,0xe,0x1,0xf8,0x3,0xbe,0x2,0x94,0x0,0xd,0x0,0x6, + 0xb3,0x4,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x3,0xa1,0x1d,0x1d,0x22,0xfd,0xce,0x22,0x1d,0x1d, + 0x22,0x2,0x32,0x2,0x94,0x22,0x2c,0x2c,0x22,0x22,0x2c,0x2c,0x22,0x0,0x0,0x0,0x0,0x1,0xfe,0x52,0x1,0xfe,0x6,0x7a,0x2,0x8e,0x0,0xd,0x0,0x6, + 0xb3,0x4,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x6,0x5d,0x1d,0x1d,0x22,0xf8,0x56,0x22,0x1d,0x1d, + 0x22,0x7,0xaa,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0xff,0xf0,0x1,0xfe,0x9,0xa8,0x2,0x8e,0x0,0xd,0x0,0x6, + 0xb3,0x4,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x9,0x8b,0x1d,0x1d,0x22,0xf6,0xc6,0x22,0x1d,0x1d, + 0x22,0x9,0x3a,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x1,0x1c,0x1,0xfe,0x8,0x7c,0x2,0x8e,0x0,0xd,0x0,0x6, + 0xb3,0x4,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x8,0x5f,0x1d,0x1d,0x22,0xf9,0x1e,0x22,0x1d,0x1d, + 0x22,0x6,0xe2,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0xff,0x1a,0x1,0xfe,0x5,0xb2,0x2,0x8e,0x0,0xd,0x0,0x6, + 0xb3,0x4,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x5,0x95,0x1d,0x1d,0x22,0xf9,0xe6,0x22,0x1d,0x1d, + 0x22,0x6,0x1a,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0xff,0xe2,0x1,0xfe,0x4,0xea,0x2,0x8e,0x0,0xd,0x0,0x1f, + 0x40,0x1c,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0xd,0x0,0xb,0x34,0x3,0x7,0x15, + 0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0xcd,0x1d,0x1d,0x22,0xfb,0x76,0x22,0x1d,0x1d,0x22,0x4,0x8a,0x2,0x8e, + 0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x1,0x0,0xaa,0x1,0xfe,0x4,0x22,0x2,0x8e,0x0,0xd,0x0,0x1f,0x40,0x1c,0x2,0x1,0x1,0x0, + 0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0xd,0x0,0xb,0x34,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x6, + 0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0x5,0x1d,0x1d,0x22,0xfd,0x6,0x22,0x1d,0x1d,0x22,0x2,0xfa,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27, + 0x27,0x21,0x0,0x0,0x0,0x1,0x0,0xaa,0x1,0xfe,0x4,0x22,0x2,0x8e,0x0,0xd,0x0,0x1f,0x40,0x1c,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1, + 0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0xd,0x0,0xb,0x34,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34, + 0x36,0x33,0x21,0x4,0x5,0x1d,0x1d,0x22,0xfd,0x6,0x22,0x1d,0x1d,0x22,0x2,0xfa,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0xff,0xff, + 0x0,0xaa,0x1,0xfe,0x4,0x22,0x2,0x8e,0x0,0x2,0x1,0x41,0x0,0x0,0xff,0xff,0x0,0x99,0x0,0xb6,0x4,0x2f,0x3,0xb2,0x0,0x23,0x1,0x46,0xff,0x10, + 0x0,0x0,0x0,0x3,0x1,0x46,0x0,0xf0,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x9d,0x0,0xb6,0x4,0x33,0x3,0xb2,0x0,0x23,0x1,0x47,0xff,0x10,0x0,0x0, + 0x0,0x3,0x1,0x47,0x0,0xf0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x89,0x0,0xb6,0x3,0x3f,0x3,0xb2,0x0,0x17,0x0,0x1a,0x40,0x17,0x4,0x1,0x2,0x0, + 0x1,0x1,0x4a,0x0,0x0,0x0,0x1,0x5b,0x0,0x1,0x1,0x19,0x0,0x4c,0x28,0x2a,0x2,0x7,0x16,0x2b,0x0,0x15,0x14,0x7,0x3,0x13,0x16,0x15,0x14,0x7, + 0x6,0x23,0x22,0x27,0x1,0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x32,0x17,0x3,0x3f,0xe,0xf6,0xf6,0xe,0x1f,0x20,0x1c,0x14,0xc,0xfe,0xce,0x9,0x9,0x1, + 0x32,0xc,0x14,0x1c,0x20,0x3,0x7b,0x18,0x10,0x10,0xfe,0xf1,0xfe,0xf1,0x10,0x10,0x18,0x1b,0x1c,0xf,0x1,0x57,0xb,0xd,0xf,0x9,0x1,0x57,0xf,0x1c, + 0x0,0x0,0x0,0x1,0x1,0x8d,0x0,0xb6,0x3,0x43,0x3,0xb2,0x0,0x17,0x0,0x1b,0x40,0x18,0x12,0xf,0x6,0x3,0x1,0x0,0x1,0x4a,0x0,0x1,0x1,0x0, + 0x5b,0x0,0x0,0x0,0x19,0x1,0x4c,0x28,0x20,0x2,0x7,0x16,0x2b,0x0,0x33,0x32,0x17,0x1,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34, + 0x37,0x13,0x3,0x26,0x35,0x34,0x37,0x1,0xcc,0x1c,0x14,0xc,0x1,0x32,0x9,0x9,0xfe,0xce,0xc,0x14,0x1c,0x20,0x1f,0xe,0xf6,0xf6,0xe,0x1f,0x3,0xb2, + 0xf,0xfe,0xa9,0x9,0xf,0xd,0xb,0xfe,0xa9,0xf,0x1c,0x1b,0x18,0x10,0x10,0x1,0xf,0x1,0xf,0x10,0x10,0x18,0x1b,0x0,0xff,0xff,0x0,0xc0,0xfe,0xfb, + 0x4,0x18,0x1,0x26,0x0,0x23,0x1,0x4d,0x0,0xf5,0x0,0x0,0x0,0x3,0x1,0x4d,0xff,0xb,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xb1,0x2,0xf0,0x4,0x9, + 0x5,0x1b,0x0,0x23,0x1,0x4b,0xff,0xb,0x0,0x0,0x0,0x3,0x1,0x4b,0x0,0xf5,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xc0,0x2,0xca,0x4,0x18,0x4,0xf5, + 0x0,0x23,0x1,0x4c,0xff,0xb,0x0,0x0,0x0,0x3,0x1,0x4c,0x0,0xf5,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0xa6,0x2,0xf0,0x3,0x14,0x5,0x1b,0x0,0x10, + 0x0,0x19,0x40,0x16,0xa,0x1,0x1,0x0,0x1,0x4a,0x0,0x1,0x0,0x1,0x73,0x0,0x0,0x0,0x10,0x0,0x4c,0x26,0x26,0x2,0x7,0x16,0x2b,0x0,0x26,0x35, + 0x34,0x37,0x13,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x23,0x1,0xb9,0x13,0x8,0xdc,0x16,0x34,0x1d,0x23,0x2,0x65,0x9,0x2b,0xaf,0x2,0xf0, + 0x12,0xf,0xc,0x12,0x1,0xc1,0x2b,0x1c,0x18,0x5,0xc,0xfe,0x42,0x28,0x0,0x0,0x0,0x1,0x1,0xb5,0x2,0xca,0x3,0x23,0x4,0xf5,0x0,0x10,0x0,0x17, + 0x40,0x14,0xa,0x1,0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x26,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6, + 0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x33,0x33,0x3,0x10,0x13,0x8,0xdc,0x15,0x35,0x1d,0x23,0x2,0x65,0x9,0x2b,0xaf,0x4,0xf5,0x12,0xf,0xc,0x12, + 0xfe,0x3f,0x2b,0x1c,0x18,0x5,0xc,0x1,0xbe,0x28,0x0,0x1,0x1,0xb5,0xfe,0xfb,0x3,0x23,0x1,0x26,0x0,0x10,0x0,0x17,0x40,0x14,0xa,0x1,0x0,0x1, + 0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x26,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37, + 0x13,0x36,0x33,0x33,0x3,0x10,0x13,0x8,0xdc,0x15,0x35,0x1d,0x23,0x2,0x65,0x9,0x2b,0xaf,0x1,0x26,0x12,0xf,0xc,0x12,0xfe,0x3f,0x2b,0x1c,0x18,0x5, + 0xc,0x1,0xbe,0x28,0x0,0x2,0x0,0x93,0xff,0x83,0x4,0x31,0x5,0x20,0x0,0x31,0x0,0x3a,0x0,0x34,0x40,0x31,0x36,0x2a,0x1e,0x16,0x4,0x2,0x1,0x35, + 0x2b,0xe,0x6,0x4,0x0,0x3,0x2,0x4a,0x0,0x2,0x1,0x3,0x1,0x2,0x3,0x70,0x0,0x3,0x0,0x1,0x3,0x0,0x6e,0x0,0x0,0x0,0x1,0x5b,0x0,0x1, + 0x1,0x10,0x0,0x4c,0x28,0x1a,0x2e,0x29,0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x6,0x6,0x7,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x2e,0x2,0x35, + 0x34,0x36,0x36,0x37,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x27,0x11,0x36,0x37,0x36,0x33,0x32, + 0x17,0x24,0x16,0x16,0x17,0x11,0xe,0x2,0x15,0x4,0x31,0x20,0x43,0xa9,0x5b,0x21,0x25,0x25,0x21,0x80,0xc2,0x69,0x69,0xc2,0x80,0x21,0x25,0x25,0x21,0xa8, + 0x87,0x23,0xf,0x14,0x20,0x13,0x12,0x6b,0x7f,0x8f,0x6c,0x14,0x12,0x1f,0x16,0xfd,0x11,0x42,0x7a,0x51,0x51,0x7a,0x42,0x1,0x45,0x17,0x21,0x17,0x30,0x41, + 0xa,0xb7,0x22,0x1f,0x1f,0x22,0xb5,0xc,0x82,0xd2,0x81,0x81,0xd2,0x82,0xc,0xa4,0x22,0x1f,0x1f,0x22,0xa6,0x11,0x58,0x16,0x23,0x17,0x1b,0x29,0xd,0x4a, + 0x11,0xfd,0x6c,0x16,0x53,0xf,0x26,0xa1,0x8f,0x5a,0xc,0x2,0x98,0xc,0x5a,0x8f,0x57,0x0,0x0,0x2,0x0,0x6f,0x0,0x63,0x4,0x5d,0x4,0x51,0x0,0x37, + 0x0,0x47,0x0,0x49,0x40,0x46,0x29,0x25,0x2,0x7,0x4,0x37,0x33,0x1b,0x17,0x4,0x6,0x7,0xd,0x9,0x2,0x1,0x6,0x3,0x4a,0x5,0x1,0x3,0x4,0x0, + 0x3,0x57,0x0,0x4,0x0,0x7,0x6,0x4,0x7,0x63,0x0,0x6,0x0,0x1,0x0,0x6,0x1,0x63,0x5,0x1,0x3,0x3,0x0,0x5b,0x2,0x1,0x0,0x3,0x0,0x4f, + 0x44,0x42,0x3c,0x3a,0x2d,0x2b,0x28,0x26,0x23,0x21,0x23,0x23,0x25,0x8,0x7,0x17,0x2b,0x25,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x27,0x6,0x23,0x22, + 0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x35,0x34,0x37,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x17,0x36,0x33,0x32,0x17,0x37, + 0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x7,0x16,0x15,0x14,0x7,0x24,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x4, + 0x46,0x17,0x1d,0x1d,0x17,0x15,0x17,0x8f,0x67,0x84,0x84,0x67,0x8f,0x17,0x15,0x17,0x1d,0x1d,0x17,0x8e,0x48,0x48,0x8e,0x17,0x1d,0x1d,0x17,0x15,0x17,0x8f, + 0x67,0x84,0x84,0x67,0x8f,0x17,0x15,0x17,0x1d,0x1d,0x17,0x8e,0x48,0x48,0xfd,0xa8,0x42,0x77,0x4d,0x4d,0x77,0x42,0x42,0x77,0x4d,0x4d,0x77,0x42,0xe0,0x17, + 0x15,0x17,0x1d,0x1d,0x17,0x8f,0x43,0x43,0x8f,0x17,0x1d,0x1d,0x17,0x15,0x17,0x8e,0x66,0x86,0x86,0x66,0x8e,0x17,0x15,0x17,0x1d,0x1d,0x17,0x8f,0x43,0x43, + 0x8f,0x17,0x1d,0x1d,0x17,0x15,0x17,0x8e,0x66,0x86,0x86,0x66,0xa1,0x78,0x43,0x43,0x78,0x4b,0x4b,0x78,0x43,0x43,0x78,0x4b,0x0,0x1,0x0,0xae,0xff,0x1f, + 0x4,0x1c,0x5,0x84,0x0,0x4e,0x0,0x90,0x40,0xe,0x33,0x1,0x7,0x4,0x37,0x1,0x6,0x7,0xb,0x1,0x0,0x3,0x3,0x4a,0x4b,0xb0,0x9,0x50,0x58,0x40, + 0x32,0x0,0x5,0x4,0x4,0x5,0x66,0x0,0x6,0x7,0x2,0x7,0x6,0x2,0x70,0x0,0x2,0x3,0x7,0x2,0x3,0x6e,0x0,0x1,0x0,0x1,0x73,0x0,0x4,0x0, + 0x7,0x6,0x4,0x7,0x64,0x0,0x3,0x0,0x0,0x3,0x57,0x0,0x3,0x3,0x0,0x5b,0x0,0x0,0x3,0x0,0x4f,0x1b,0x40,0x31,0x0,0x5,0x4,0x5,0x72,0x0, + 0x6,0x7,0x2,0x7,0x6,0x2,0x70,0x0,0x2,0x3,0x7,0x2,0x3,0x6e,0x0,0x1,0x0,0x1,0x73,0x0,0x4,0x0,0x7,0x6,0x4,0x7,0x64,0x0,0x3,0x0, + 0x0,0x3,0x57,0x0,0x3,0x3,0x0,0x5b,0x0,0x0,0x3,0x0,0x4f,0x59,0x40,0xf,0x40,0x3e,0x3b,0x3a,0x30,0x2e,0x2b,0x2a,0x24,0x1a,0x23,0x12,0x8,0x7, + 0x18,0x2b,0x0,0x6,0x6,0x7,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35, + 0x34,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x37,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x16,0x17,0x16,0x15,0x14,0x7, + 0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x4,0x1c,0x55,0xa7,0x7a,0x21,0x25,0x25,0x21, + 0xb6,0x90,0x26,0xd,0x18,0x1f,0xe,0x11,0x50,0xbb,0x61,0x81,0x84,0x30,0x2d,0x23,0x57,0x4e,0x5b,0x7b,0x34,0x49,0x51,0x5a,0x9f,0x68,0x21,0x25,0x25,0x21, + 0xa5,0x82,0x27,0xc,0x15,0x21,0xf,0x10,0xa1,0xb6,0x6e,0x7b,0x27,0x26,0x21,0x57,0x4c,0x5a,0x79,0x35,0x53,0x5d,0x1,0x2a,0x8a,0x50,0x5,0xeb,0x22,0x1f, + 0x1f,0x22,0xef,0x12,0x52,0x15,0x23,0x14,0x1a,0x2e,0xa,0x2e,0x33,0x5b,0x4d,0x2a,0x35,0x11,0xd,0xf,0x9,0xb,0x17,0x15,0x1e,0x6c,0x57,0x5c,0x85,0x49, + 0x5,0xe3,0x22,0x1f,0x1f,0x22,0xe8,0x11,0x44,0x14,0x25,0x13,0x1a,0x30,0x9,0x56,0x52,0x4c,0x22,0x2c,0xe,0xd,0xe,0x9,0xa,0x15,0x14,0x20,0x77,0x63, + 0x0,0x0,0x0,0x1,0x0,0x5a,0xff,0xea,0x4,0x5a,0x4,0xb9,0x0,0x4f,0x0,0x58,0x40,0x55,0x29,0x1,0x7,0x8,0x1,0x4a,0x0,0x7,0x8,0x5,0x8,0x7, + 0x5,0x70,0x0,0x0,0x2,0xd,0x2,0x0,0xd,0x70,0x9,0x1,0x5,0xa,0x1,0x4,0x3,0x5,0x4,0x63,0xb,0x1,0x3,0xc,0x1,0x2,0x0,0x3,0x2,0x63, + 0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0x16,0x4b,0x0,0xd,0xd,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x4d,0x4b,0x49,0x47,0x43,0x41,0x3d,0x3b,0x37, + 0x35,0x24,0x17,0x22,0x24,0x24,0x24,0x22,0x27,0x20,0xe,0x7,0x1d,0x2b,0x24,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x23,0x22, + 0x26,0x35,0x34,0x36,0x33,0x33,0x26,0x35,0x34,0x37,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x36,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23, + 0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x7,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x6,0x15,0x14,0x17,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x16,0x16, + 0x33,0x32,0x36,0x37,0x4,0xa,0xe,0x20,0x15,0xd,0x25,0x5a,0xac,0x65,0xb2,0xed,0x2c,0x66,0x22,0x1d,0x1d,0x22,0x50,0x3,0x3,0x50,0x22,0x1d,0x1d,0x22, + 0x67,0x2e,0xec,0xb0,0x65,0xac,0x5a,0x25,0xd,0x15,0x20,0xe,0x14,0x49,0x90,0x53,0x70,0x97,0x24,0x1,0x5e,0x22,0x1d,0x1d,0x22,0xfe,0x87,0x4,0x3,0x1, + 0x7a,0x22,0x1d,0x1d,0x22,0xfe,0xa0,0x23,0x99,0x71,0x53,0x90,0x49,0xde,0x2c,0x1d,0x13,0x22,0x16,0x33,0x2d,0xcf,0xb9,0x21,0x27,0x27,0x21,0x27,0x29,0x2c, + 0x2a,0x21,0x27,0x27,0x21,0xb6,0xcb,0x2d,0x33,0x16,0x22,0x13,0x1d,0x2c,0xb,0x2c,0x29,0x7b,0x72,0x21,0x27,0x27,0x21,0x24,0x32,0x29,0x27,0x21,0x27,0x27, + 0x21,0x75,0x7f,0x29,0x2c,0x0,0x0,0x1,0x0,0x21,0xfe,0xe9,0x4,0x80,0x5,0x25,0x0,0x37,0x0,0x47,0x40,0x44,0x1,0x1,0x1,0x9,0x1d,0x1,0x4,0x6, + 0x2,0x4a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x0,0x5,0x3,0x6,0x3,0x5,0x6,0x70,0x8,0x1,0x2,0x7,0x1,0x3,0x5,0x2,0x3,0x61,0x0,0x6, + 0x0,0x4,0x6,0x4,0x5f,0x0,0x1,0x1,0x9,0x5b,0x0,0x9,0x9,0x10,0x1,0x4c,0x36,0x34,0x24,0x23,0x23,0x16,0x23,0x24,0x23,0x23,0x14,0xa,0x7,0x1d, + 0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x7,0x7,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x22,0x27,0x26, + 0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x33,0x32,0x36,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x37,0x36,0x36,0x33,0x32,0x17,0x4,0x80,0x6, + 0x10,0x29,0xb,0xb,0x5b,0x51,0x4d,0x5e,0xa,0xe,0xea,0x22,0x1d,0x1d,0x22,0xf8,0x43,0x10,0xb0,0x8e,0x72,0x61,0x29,0x6,0x10,0x29,0xb,0xb,0x5b,0x51, + 0x4d,0x5e,0xa,0x41,0xc4,0x22,0x1d,0x1d,0x22,0xd3,0xf,0x10,0xb0,0x8e,0x72,0x61,0x4,0xf9,0x26,0x11,0x15,0x3b,0x4,0x1d,0x5d,0x5e,0x88,0x21,0x27,0x27, + 0x21,0xfd,0x69,0x99,0xa7,0x1f,0xd,0x26,0x11,0x15,0x3b,0x4,0x1d,0x5d,0x5e,0x2,0x8a,0x21,0x27,0x27,0x21,0x95,0x99,0xa7,0x1f,0x0,0x0,0x0,0x0,0x1, + 0x0,0x32,0xff,0xf6,0x4,0x10,0x4,0xa3,0x0,0x2f,0x0,0x37,0x40,0x34,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x7,0x1,0x3,0x6,0x1,0x4,0x5,0x3, + 0x4,0x63,0x0,0x0,0x0,0x8,0x59,0x9,0x1,0x8,0x8,0xe,0x4b,0x0,0x5,0x5,0xf,0x5,0x4c,0x0,0x0,0x0,0x2f,0x0,0x2c,0x24,0x23,0x33,0x24,0x21, + 0x24,0x21,0x24,0xa,0x7,0x1c,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x15,0x21,0x32,0x16,0x15,0x14,0x6, + 0x23,0x21,0x15,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x11,0x34,0x36,0x33,0x33,0x21,0x3,0xf3,0x1d,0x1d,0x22, + 0xfd,0xba,0x1,0xd3,0x22,0x1d,0x1d,0x22,0xfe,0x2d,0x1,0x22,0x22,0x1d,0x1d,0x22,0xfe,0xde,0x21,0x29,0x2,0x29,0x21,0x84,0x22,0x1d,0x1d,0x22,0x84,0x1f, + 0x20,0x57,0x2,0x46,0x4,0xa3,0x21,0x27,0x27,0x21,0xfe,0xad,0x21,0x27,0x27,0x21,0xba,0x21,0x27,0x27,0x21,0xaf,0x23,0x1e,0x1e,0x23,0xaf,0x21,0x27,0x27, + 0x21,0x2,0xe9,0x25,0x1f,0x0,0x0,0x1,0x0,0xdc,0x0,0x0,0x3,0xd2,0x4,0xb9,0x0,0x41,0x0,0x42,0x40,0x3f,0x9,0x1,0x0,0x8,0x1,0x4a,0x0,0x4, + 0x5,0x2,0x5,0x4,0x2,0x70,0x6,0x1,0x2,0x7,0x1,0x1,0x8,0x2,0x1,0x63,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x16,0x4b,0x9,0x1,0x8,0x8, + 0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x41,0x0,0x40,0x24,0x27,0x23,0x16,0x26,0x24,0x2a,0x34,0xa,0x7,0x1c,0x2b,0x24,0x16,0x15,0x14, + 0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x37,0x36,0x36,0x35,0x34,0x27,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32, + 0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x17,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x16,0x15,0x14, + 0x7,0x21,0x3,0xb5,0x1d,0x1d,0x22,0xfd,0xa1,0x16,0x20,0x9,0xa,0x56,0x46,0x6,0x8c,0x22,0x1d,0x1d,0x22,0x52,0x27,0x24,0x54,0x9a,0x64,0x9e,0x8b,0x22, + 0x10,0x18,0x1d,0xf,0x13,0x6b,0x7a,0x37,0x54,0x2c,0x1e,0x1e,0x1d,0x1,0x1a,0x22,0x1d,0x1d,0x22,0xee,0x4,0x7d,0x1,0xcb,0x90,0x21,0x27,0x27,0x21,0x3d, + 0x22,0xd,0x14,0xa,0x55,0x8e,0x50,0x1f,0x1c,0x21,0x27,0x27,0x21,0x4d,0x63,0x3c,0x5c,0x94,0x55,0x57,0x15,0x1e,0x15,0x1d,0x2b,0xc,0x47,0x2f,0x51,0x31, + 0x2a,0x4f,0x39,0x3a,0x21,0x27,0x27,0x21,0x18,0x22,0xa0,0x8e,0x0,0x0,0x0,0x3,0xff,0xe2,0xff,0xea,0x4,0xea,0x4,0xad,0x0,0x3f,0x0,0x42,0x0,0x45, + 0x0,0x7d,0x40,0x10,0x3b,0x1d,0x2,0x7,0x5,0xd,0x1,0x0,0x4,0x45,0x42,0x2,0x1,0x0,0x3,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x21,0xd,0xa,0x8, + 0x6,0x4,0x4,0xc,0xb,0x3,0x3,0x0,0x1,0x4,0x0,0x63,0x9,0x1,0x5,0x5,0xe,0x4b,0x0,0x7,0x7,0x11,0x4b,0x2,0x1,0x1,0x1,0x17,0x1,0x4c, + 0x1b,0x40,0x24,0x0,0x7,0x5,0x4,0x5,0x7,0x4,0x70,0xd,0xa,0x8,0x6,0x4,0x4,0xc,0xb,0x3,0x3,0x0,0x1,0x4,0x0,0x63,0x9,0x1,0x5,0x5, + 0xe,0x4b,0x2,0x1,0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x18,0x0,0x0,0x44,0x43,0x41,0x40,0x0,0x3f,0x0,0x3e,0x38,0x35,0x13,0x23,0x13,0x36,0x24,0x23, + 0x24,0x23,0x24,0xe,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x22,0x27,0x3,0x3,0x6,0x23,0x22,0x26,0x27,0x3,0x23,0x22, + 0x26,0x35,0x34,0x36,0x33,0x33,0x3,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x33,0x37,0x36,0x36,0x33,0x32,0x16,0x17,0x17,0x33,0x13,0x36, + 0x36,0x33,0x32,0x17,0x16,0x16,0x15,0x14,0x7,0x3,0x33,0x5,0x23,0x13,0x1,0x23,0x13,0x4,0xcd,0x1d,0x1d,0x22,0x72,0x4e,0x5,0x29,0x28,0x4d,0x17,0xcf, + 0xcf,0x17,0x4d,0x28,0x29,0x5,0x4e,0x6a,0x22,0x1d,0x1d,0x22,0x56,0x33,0x1,0x20,0x24,0x7,0xd,0x1e,0x1c,0x4,0x31,0xee,0x20,0x7,0x23,0x20,0x20,0x23, + 0x7,0x20,0xee,0x31,0x4,0x1c,0x1e,0xd,0x7,0x24,0x20,0x1,0x33,0x5e,0xfd,0x1a,0xa9,0x2d,0x2,0x5f,0xa9,0x7c,0x2,0xf2,0x21,0x27,0x27,0x21,0xfd,0xc9, + 0x24,0x1d,0x41,0x2,0x4a,0xfd,0xb6,0x41,0x1d,0x24,0x2,0x37,0x21,0x27,0x27,0x21,0x1,0x70,0x6,0xc,0x19,0x1a,0x5,0x1,0x1b,0x1f,0xfe,0x7f,0x5b,0x14, + 0x14,0x14,0x14,0x5b,0x1,0x81,0x1f,0x1b,0x1,0x5,0x1a,0x19,0xc,0x6,0xfe,0x90,0x90,0xfe,0xa0,0x1,0x60,0xfe,0xa0,0x0,0x0,0x1,0x0,0x7d,0xff,0xf6, + 0x4,0x4f,0x4,0xb1,0x0,0x42,0x0,0x3e,0x40,0x3b,0x3d,0x1,0x1,0x0,0x29,0xe,0x2,0x2,0x1,0x2,0x4a,0x8,0x1,0x0,0x7,0x1,0x1,0x2,0x0,0x1, + 0x62,0x6,0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9,0x16,0x4b,0x0,0x4,0x4,0xf,0x4,0x4c,0x40,0x3f,0x3b,0x39,0x24,0x22,0x24, + 0x23,0x33,0x24,0x22,0x24,0x25,0xb,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x7,0x15,0x21,0x32,0x16,0x15, + 0x14,0x6,0x23,0x21,0x15,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x35,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x35,0x27,0x23,0x22,0x26,0x35,0x34,0x36,0x33, + 0x33,0x3,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x17,0x1,0x1,0x36,0x33,0x32,0x17,0x4,0x38,0x17,0xf,0xe7,0x9e,0x22,0x1d,0x1d,0x22,0xfc,0x4a,0x1, + 0x32,0x22,0x1d,0x1d,0x22,0xfe,0xce,0x21,0x29,0x2,0x29,0x21,0xfe,0xce,0x22,0x1d,0x1d,0x22,0x1,0x32,0x4a,0xfc,0x22,0x1d,0x1d,0x22,0x9e,0xe7,0xf,0x17, + 0x19,0x21,0x13,0x1e,0x12,0x1,0x55,0x1,0x55,0x14,0x1c,0x13,0x21,0x4,0x98,0x19,0x10,0x10,0x17,0xfe,0xa0,0x21,0x27,0x27,0x21,0x71,0x35,0x21,0x27,0x27, + 0x21,0xeb,0x23,0x1e,0x1e,0x23,0xeb,0x21,0x27,0x27,0x21,0x35,0x71,0x21,0x27,0x27,0x21,0x1,0x60,0x17,0x10,0x10,0x19,0xb,0xe,0x1d,0xfd,0xf2,0x2,0xe, + 0x1d,0xe,0xff,0xff,0x0,0x96,0x0,0xe5,0x4,0x36,0x3,0xa7,0x0,0x27,0x1,0x59,0x0,0x0,0x0,0xc8,0x1,0x7,0x1,0x59,0x0,0x0,0xff,0x38,0x0,0x11, + 0xb1,0x0,0x1,0xb0,0xc8,0xb0,0x33,0x2b,0xb1,0x1,0x1,0xb8,0xff,0x38,0xb0,0x33,0x2b,0x0,0x0,0x0,0x0,0x1,0x0,0x96,0x1,0xad,0x4,0x36,0x2,0xdf, + 0x0,0x25,0x0,0x4c,0xb1,0x6,0x64,0x44,0x40,0x41,0xd,0x1,0x0,0x1,0x20,0x1,0x4,0x3,0x2,0x4a,0x0,0x1,0x5,0x0,0x5,0x1,0x0,0x70,0x0,0x4, + 0x3,0x2,0x3,0x4,0x2,0x70,0x0,0x0,0x3,0x2,0x0,0x57,0x6,0x1,0x5,0x0,0x3,0x4,0x5,0x3,0x63,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x0,0x2, + 0x4f,0x0,0x0,0x0,0x25,0x0,0x24,0x22,0x24,0x27,0x22,0x24,0x7,0x7,0x19,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x17,0x16,0x16,0x33,0x32,0x37,0x36,0x33, + 0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x1,0xdc, + 0x65,0x40,0x3a,0x48,0x27,0x55,0x46,0x10,0x16,0x16,0x15,0x20,0x7,0x2f,0x88,0x4e,0x3a,0x64,0x42,0x38,0x4a,0x26,0x55,0x46,0x10,0x16,0x16,0x15,0x20,0x7, + 0x2f,0x88,0x4e,0x2,0xdf,0x2a,0x28,0x22,0x20,0x54,0x13,0x11,0x18,0x1c,0xe,0xb,0x4c,0x5b,0x2a,0x28,0x21,0x21,0x54,0x13,0x11,0x18,0x1c,0xe,0xb,0x4c, + 0x5b,0x0,0x0,0x3,0x0,0xaa,0x0,0x6e,0x4,0x22,0x4,0x1f,0x0,0xd,0x0,0x1b,0x0,0x29,0x0,0x41,0x40,0x3e,0x6,0x1,0x1,0x0,0x0,0x3,0x1,0x0, + 0x63,0x7,0x1,0x3,0x0,0x2,0x5,0x3,0x2,0x61,0x8,0x1,0x5,0x4,0x4,0x5,0x57,0x8,0x1,0x5,0x5,0x4,0x5b,0x0,0x4,0x5,0x4,0x4f,0x1c,0x1c, + 0xe,0xe,0x0,0x0,0x1c,0x29,0x1c,0x28,0x23,0x21,0xe,0x1b,0xe,0x19,0x15,0x12,0x0,0xd,0x0,0xc,0x25,0x9,0x7,0x15,0x2b,0x0,0x16,0x15,0x15,0x14, + 0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x0,0x16,0x15,0x15,0x14,0x6,0x23, + 0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x2,0x9e,0x31,0x31,0x38,0x38,0x31,0x31,0x38,0x1,0x9f,0x1d,0x1d,0x22,0xfd,0x6,0x22,0x1d,0x1d,0x22,0x2,0xfa,0xfe, + 0xbb,0x31,0x31,0x38,0x38,0x31,0x31,0x38,0x4,0x1f,0x1d,0x22,0x68,0x22,0x1d,0x1d,0x22,0x68,0x22,0x1d,0xfe,0x6f,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21, + 0xfe,0xc6,0x1d,0x22,0x68,0x22,0x1d,0x1d,0x22,0x68,0x22,0x1d,0x0,0x0,0xff,0xff,0x0,0xaa,0x1,0x36,0x4,0x22,0x3,0x56,0x0,0x27,0x1,0x63,0x0,0x0, + 0x0,0xc8,0x1,0x7,0x1,0x63,0x0,0x0,0xff,0x38,0x0,0x11,0xb1,0x0,0x1,0xb0,0xc8,0xb0,0x33,0x2b,0xb1,0x1,0x1,0xb8,0xff,0x38,0xb0,0x33,0x2b,0x0, + 0x0,0x0,0x0,0x1,0x0,0xaf,0x0,0x77,0x4,0x4f,0x4,0x17,0x0,0x19,0x0,0x1f,0x40,0x1c,0x18,0x1,0x2,0x1,0x0,0x1,0x4a,0x0,0x0,0x1,0x1,0x0, + 0x57,0x0,0x0,0x0,0x1,0x5b,0x0,0x1,0x0,0x1,0x4f,0x2b,0x14,0x2,0x7,0x16,0x2b,0x12,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x1,0x16,0x16,0x15,0x14, + 0x6,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x1,0xaf,0xc,0x17,0x23,0x10,0x12,0x3,0x9,0x19,0x16,0x16,0x19,0xfc,0xf7,0x12,0x10,0x23, + 0x17,0xc,0x29,0x2,0xa0,0xfd,0x60,0x3,0x9d,0x21,0x12,0x18,0x2f,0x9,0xfe,0x83,0xd,0x20,0x1d,0x1d,0x20,0xd,0xfe,0x83,0x9,0x2f,0x18,0x12,0x21,0x14, + 0x1,0x42,0x1,0x42,0x0,0x0,0x0,0x2,0x0,0xaa,0x0,0x6e,0x4,0x22,0x4,0x6b,0x0,0x17,0x0,0x25,0x0,0x8,0xb5,0x1c,0x18,0x14,0x6,0x2,0x30,0x2b, + 0x1,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x25,0x25,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x0,0x16,0x15,0x14,0x6,0x23, + 0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x3,0xee,0x34,0x34,0xfd,0x1e,0x11,0xe,0x26,0x14,0x8,0x30,0x2,0x65,0xfd,0x9b,0x30,0x8,0x14,0x26,0xf,0x10, + 0x2,0xf9,0x1d,0x1d,0x22,0xfd,0x6,0x22,0x1d,0x1d,0x22,0x2,0xfa,0x3,0x43,0x14,0x3c,0x3c,0x14,0xfe,0xde,0x6,0x34,0x13,0x12,0x26,0x11,0xe8,0xe8,0x11, + 0x26,0x12,0x13,0x34,0x6,0xfc,0x99,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x3,0x0,0x1c,0x1,0x25,0x4,0xb0,0x3,0x67,0x0,0x1b, + 0x0,0x27,0x0,0x33,0x0,0xa,0xb7,0x2c,0x28,0x20,0x1c,0x6,0x0,0x3,0x30,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x6,0x6,0x23, + 0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x36,0x36,0x33,0x4,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x26,0x26,0x23,0x20,0x6,0x7,0x16, + 0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x3,0xe7,0x80,0x49,0x49,0x80,0x4f,0x67,0x8a,0x41,0x41,0x8a,0x67,0x4f,0x80,0x49,0x49,0x80,0x4f,0x67,0x8b,0x40, + 0x40,0x8b,0x67,0xfd,0x5d,0x4f,0x4f,0x42,0x49,0x6a,0x36,0x37,0x69,0x49,0x2,0x15,0x6b,0x35,0x35,0x6b,0x49,0x42,0x4f,0x4f,0x42,0x3,0x67,0x4c,0x84,0x51, + 0x51,0x84,0x4c,0x63,0x59,0x59,0x63,0x4c,0x84,0x51,0x51,0x84,0x4c,0x63,0x5a,0x5a,0x63,0x86,0x58,0x43,0x43,0x58,0x50,0x4b,0x4b,0x50,0x51,0x4a,0x4b,0x50, + 0x58,0x43,0x43,0x58,0x0,0x0,0x0,0x1,0x0,0x5,0xfe,0x66,0x4,0xc7,0x5,0xed,0x0,0x2b,0x0,0x6,0xb3,0x14,0x0,0x1,0x30,0x2b,0x0,0x16,0x17,0x16, + 0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x15,0x11,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17, + 0x16,0x33,0x32,0x36,0x35,0x11,0x34,0x36,0x36,0x33,0x3,0xd3,0x8f,0x3f,0x14,0x12,0x6,0x12,0x22,0x4,0xe,0x84,0x6b,0x69,0x72,0x59,0xa5,0x71,0x49,0x8f, + 0x3f,0x14,0x12,0x6,0x12,0x22,0x4,0xe,0x84,0x6b,0x69,0x72,0x59,0xa5,0x71,0x5,0xed,0x1f,0x1b,0x8,0x18,0x12,0xf,0x14,0x3a,0x4,0x33,0x8f,0x83,0xfb, + 0xb5,0x7c,0xb8,0x64,0x1f,0x1b,0x8,0x18,0x12,0xf,0x14,0x3a,0x4,0x33,0x8f,0x83,0x4,0x4b,0x7c,0xb8,0x64,0x0,0x0,0x1,0x0,0x7d,0x0,0x77,0x4,0x1d, + 0x4,0x17,0x0,0x19,0x0,0x1f,0x40,0x1c,0x18,0x1,0x2,0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x0,0x1,0x57,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0, + 0x4f,0x2b,0x14,0x2,0x7,0x16,0x2b,0x24,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x26,0x26,0x35,0x34,0x36,0x37,0x1,0x36,0x33,0x32,0x17,0x16,0x15,0x14, + 0x7,0x1,0x1,0x4,0x1d,0xc,0x17,0x23,0x10,0x12,0xfc,0xf7,0x19,0x16,0x16,0x19,0x3,0x9,0x12,0x10,0x23,0x17,0xc,0x29,0xfd,0x60,0x2,0xa0,0xf1,0x21, + 0x12,0x18,0x2f,0x9,0x1,0x7d,0xd,0x20,0x1d,0x1d,0x20,0xd,0x1,0x7d,0x9,0x2f,0x18,0x12,0x21,0x14,0xfe,0xbe,0xfe,0xbe,0x0,0x0,0x0,0x2,0x0,0xaa, + 0x0,0x6e,0x4,0x22,0x4,0x6b,0x0,0x17,0x0,0x25,0x0,0x8,0xb5,0x1c,0x18,0xe,0x0,0x2,0x30,0x2b,0x0,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x5,0x5, + 0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x26,0x35,0x34,0x37,0x1,0x12,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x3,0xd1, + 0xe,0x26,0x14,0x8,0x30,0xfd,0x9b,0x2,0x65,0x30,0x8,0x14,0x26,0xe,0x11,0xfd,0x1e,0x34,0x34,0x2,0xe2,0x45,0x1d,0x1d,0x22,0xfd,0x6,0x22,0x1d,0x1d, + 0x22,0x2,0xfa,0x4,0x6b,0x34,0x13,0x12,0x26,0x11,0xe8,0xe8,0x11,0x26,0x12,0x13,0x34,0x6,0x1,0x22,0x14,0x3c,0x3c,0x14,0x1,0x22,0xfc,0x99,0x21,0x27, + 0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x1,0x0,0x8c,0x1,0x3e,0x4,0x36,0x3,0x51,0x0,0x12,0x0,0x25,0x40,0x22,0x0,0x0,0x1,0x0,0x73,0x3, + 0x1,0x2,0x1,0x1,0x2,0x55,0x3,0x1,0x2,0x2,0x1,0x59,0x0,0x1,0x2,0x1,0x4d,0x0,0x0,0x0,0x12,0x0,0x10,0x23,0x25,0x4,0x7,0x16,0x2b,0x0, + 0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0x19,0x1d,0x22,0x29,0x29,0x22,0xfd,0x2b,0x22,0x1d,0x1d, + 0x22,0x3,0x2c,0x3,0x51,0x1f,0x25,0xfe,0x72,0x23,0x1e,0x1e,0x23,0x1,0x42,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xaa,0x1,0xfe,0x4,0x22, + 0x2,0x8e,0x0,0xd,0x0,0x6,0xb3,0x4,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0x5,0x1d,0x1d, + 0x22,0xfd,0x6,0x22,0x1d,0x1d,0x22,0x2,0xfa,0x2,0x8e,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xe7,0x0,0xc7,0x3,0xe5, + 0x3,0xc5,0x0,0x27,0x0,0x20,0x40,0x1d,0x27,0x1d,0x13,0x9,0x4,0x0,0x2,0x1,0x4a,0x1,0x1,0x0,0x0,0x2,0x5b,0x3,0x1,0x2,0x2,0x19,0x0,0x4c, + 0x24,0x2c,0x24,0x25,0x4,0x7,0x18,0x2b,0x1,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x1,0x26, + 0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x1,0x1,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x3,0xce,0x17,0x1d,0x1d,0x17,0x15,0x17,0xfe,0xfe,0xfe,0xfe, + 0x17,0x15,0x17,0x1d,0x1d,0x17,0x1,0x2,0xfe,0xfe,0x17,0x1d,0x1d,0x17,0x15,0x17,0x1,0x2,0x1,0x2,0x17,0x15,0x17,0x1d,0x1d,0x17,0xfe,0xfe,0x1,0x44, + 0x17,0x15,0x17,0x1d,0x1d,0x17,0x1,0x2,0xfe,0xfe,0x17,0x1d,0x1d,0x17,0x15,0x17,0x1,0x2,0x1,0x2,0x17,0x15,0x17,0x1d,0x1d,0x17,0xfe,0xfe,0x1,0x2, + 0x17,0x1d,0x1d,0x17,0x15,0x17,0xfe,0xfe,0x0,0x0,0x0,0x1,0x0,0xaa,0x0,0x44,0x4,0x22,0x4,0x48,0x0,0x37,0x0,0x6,0xb3,0x25,0x9,0x1,0x30,0x2b, + 0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x7,0x6,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x13,0x21,0x22,0x26, + 0x35,0x34,0x36,0x33,0x21,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x7,0x33,0x32,0x16,0x15,0x14,0x6,0x23,0x23,0x3,0x21,0x4,0x5,0x1d,0x1d, + 0x22,0xfe,0x3b,0x7a,0xb,0x16,0xe,0x13,0x19,0x27,0xe,0x51,0x98,0x22,0x1d,0x1d,0x22,0xe2,0x98,0xfe,0x86,0x22,0x1d,0x1d,0x22,0x1,0xc4,0x7b,0xb,0x16, + 0xe,0x13,0x19,0x27,0xe,0x51,0x98,0x22,0x1d,0x1d,0x22,0xe3,0x97,0x1,0x7a,0x1,0xc6,0x21,0x27,0x27,0x21,0xcf,0x12,0x11,0xf,0x16,0x1c,0x11,0x17,0x89, + 0x21,0x27,0x27,0x21,0x1,0x0,0x21,0x27,0x27,0x21,0xcf,0x12,0x11,0xf,0x16,0x1c,0x11,0x17,0x89,0x21,0x27,0x27,0x21,0xff,0x0,0x0,0x0,0x0,0x0,0x2, + 0x0,0xa7,0xff,0xe9,0x4,0x19,0x4,0xb9,0x0,0x26,0x0,0x33,0x0,0x8,0xb5,0x2c,0x27,0x8,0x0,0x2,0x30,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x7,0x6, + 0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x36,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36, + 0x33,0x2,0x6,0x6,0x15,0x14,0x16,0x33,0x36,0x36,0x37,0x26,0x26,0x23,0x2,0xf3,0xb7,0x6f,0x3c,0x36,0x43,0xc9,0x8d,0x6b,0xa3,0x59,0x67,0xb4,0x70,0x71, + 0xa8,0x2a,0x17,0x88,0x83,0x40,0x53,0x5,0xa,0x10,0x1a,0xc,0x9,0x1f,0x5b,0x6a,0x93,0x72,0x3e,0x70,0x5c,0x6d,0x97,0x31,0x13,0x89,0x67,0x4,0xb9,0x65, + 0xd2,0x9c,0x70,0xfe,0xf2,0x6f,0x8a,0x86,0x5c,0xa3,0x66,0x75,0xb5,0x63,0x6b,0x62,0x6e,0x58,0x9c,0xae,0x17,0x2,0x19,0x1e,0x17,0x10,0x21,0xe,0x27,0xfd, + 0x8e,0x3e,0x71,0x4b,0x5e,0x71,0x1,0x6f,0x73,0x65,0x81,0x0,0x0,0x5,0x0,0x32,0xff,0xea,0x4,0x9a,0x4,0xb9,0x0,0xf,0x0,0x21,0x0,0x31,0x0,0x41, + 0x0,0x51,0x0,0x62,0x40,0x5f,0x0,0x2,0x1,0x5,0x1,0x2,0x5,0x70,0x0,0x3,0x8,0x6,0x8,0x3,0x6,0x70,0x0,0x4,0x0,0x0,0x7,0x4,0x0,0x63, + 0xc,0x1,0x7,0xd,0x1,0x9,0x8,0x7,0x9,0x63,0xb,0x1,0x5,0x5,0x1,0x5b,0xa,0x1,0x1,0x1,0x16,0x4b,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6, + 0x17,0x6,0x4c,0x42,0x42,0x32,0x32,0x22,0x22,0x0,0x0,0x42,0x51,0x42,0x50,0x4a,0x48,0x32,0x41,0x32,0x40,0x3a,0x38,0x22,0x31,0x22,0x30,0x2a,0x28,0x1b, + 0x19,0x12,0x10,0x0,0xf,0x0,0xe,0x26,0xe,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x4,0x33, + 0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x24,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26, + 0x26,0x23,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34, + 0x26,0x26,0x23,0x1,0x8e,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x2,0xbd,0x17,0x1a,0x18,0x19,0x18,0xfc,0x96,0x16,0x17,0x1a,0x18,0x19, + 0x18,0x3,0x6a,0xfd,0x32,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x2,0x8e,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x27, + 0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x4,0xb9,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x80,0x1b,0x1b,0x16,0x17, + 0x17,0xfc,0xc2,0x16,0x1b,0x1b,0x16,0x18,0x16,0x3,0x3e,0x14,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0xfd,0xd7,0x4a,0x7e,0x4a,0x4a, + 0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x82,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x0,0x0,0x6,0x0,0x32,0xff,0xea,0x6,0x3c, + 0x4,0xb9,0x0,0xf,0x0,0x21,0x0,0x31,0x0,0x4d,0x0,0x5d,0x0,0x6d,0x0,0x7d,0x40,0x7a,0x4a,0x1,0xb,0x8,0x3c,0x1,0x6,0x3,0x2,0x4a,0x0,0x2, + 0x1,0x5,0x1,0x2,0x5,0x70,0x0,0x3,0xa,0x6,0xa,0x3,0x6,0x70,0x0,0x4,0x0,0x0,0x8,0x4,0x0,0x63,0x10,0x9,0x2,0x8,0x12,0xd,0x11,0x3, + 0xb,0xa,0x8,0xb,0x63,0xf,0x1,0x5,0x5,0x1,0x5b,0xe,0x1,0x1,0x1,0x16,0x4b,0xc,0x1,0xa,0xa,0x6,0x5b,0x7,0x1,0x6,0x6,0x17,0x6,0x4c, + 0x5e,0x5e,0x4e,0x4e,0x32,0x32,0x22,0x22,0x0,0x0,0x5e,0x6d,0x5e,0x6c,0x66,0x64,0x4e,0x5d,0x4e,0x5c,0x56,0x54,0x32,0x4d,0x32,0x4c,0x48,0x46,0x40,0x3e, + 0x3a,0x38,0x22,0x31,0x22,0x30,0x2a,0x28,0x1b,0x19,0x12,0x10,0x0,0xf,0x0,0xe,0x26,0x13,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22, + 0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x4,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x24,0x6,0x6,0x15,0x14, + 0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34, + 0x36,0x36,0x33,0x32,0x16,0x17,0x36,0x36,0x33,0x4,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x20,0x6,0x6,0x15,0x14, + 0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x1,0x8e,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x2,0xbd,0x17,0x1a,0x18,0x19, + 0x18,0xfc,0x96,0x16,0x17,0x1a,0x18,0x19,0x18,0x3,0x6a,0xfd,0x32,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x4,0x30,0x7e,0x4a,0x4a,0x7e, + 0x4a,0x40,0x6d,0x24,0x25,0x6c,0x40,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x40,0x6c,0x25,0x24,0x6d,0x40,0xfe,0x37,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27, + 0x42,0x27,0x1,0x7b,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x4,0xb9,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x80, + 0x1b,0x1b,0x16,0x17,0x17,0xfc,0xc2,0x16,0x1b,0x1b,0x16,0x18,0x16,0x3,0x3e,0x14,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0xfd,0xd7, + 0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x38,0x30,0x31,0x37,0x4a,0x7e,0x4a,0x4a,0x7e,0x4a,0x38,0x31,0x31,0x38,0x82,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27, + 0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x27,0x42,0x27,0x0,0x0,0x1,0x0,0xaa,0x0,0x8a,0x4,0x22,0x4,0x2,0x0,0x1f,0x0,0x2c, + 0x40,0x29,0x0,0x4,0x3,0x1,0x4,0x57,0x6,0x5,0x2,0x3,0x2,0x1,0x0,0x1,0x3,0x0,0x61,0x0,0x4,0x4,0x1,0x5b,0x0,0x1,0x4,0x1,0x4f,0x0, + 0x0,0x0,0x1f,0x0,0x1e,0x23,0x24,0x23,0x23,0x24,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x21, + 0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x11,0x34,0x36,0x33,0x32,0x16,0x15,0x11,0x21,0x4,0x5,0x1d,0x1d,0x22,0xfe,0xcb,0x21,0x27,0x27,0x21,0xfe,0xcb,0x22, + 0x1d,0x1d,0x22,0x1,0x35,0x21,0x27,0x27,0x21,0x1,0x35,0x2,0x8e,0x21,0x27,0x27,0x21,0xfe,0xcb,0x22,0x1d,0x1d,0x22,0x1,0x35,0x21,0x27,0x27,0x21,0x1, + 0x35,0x22,0x1d,0x1d,0x22,0xfe,0xcb,0x0,0x0,0x0,0x0,0x2,0x0,0xaa,0x0,0x6e,0x4,0x22,0x4,0x66,0x0,0x1f,0x0,0x2d,0x0,0x3e,0x40,0x3b,0x2,0x1, + 0x0,0x8,0x5,0x2,0x3,0x4,0x0,0x3,0x61,0x0,0x1,0x0,0x4,0x7,0x1,0x4,0x63,0x9,0x1,0x7,0x6,0x6,0x7,0x55,0x9,0x1,0x7,0x7,0x6,0x59, + 0x0,0x6,0x7,0x6,0x4d,0x20,0x20,0x0,0x0,0x20,0x2d,0x20,0x2b,0x27,0x24,0x0,0x1f,0x0,0x1e,0x23,0x24,0x23,0x23,0x24,0xa,0x7,0x19,0x2b,0x12,0x26, + 0x35,0x34,0x36,0x33,0x21,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35,0x21, + 0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0xc7,0x1d,0x1d,0x22,0x1,0x35,0x21,0x27,0x27,0x21,0x1,0x35,0x22,0x1d,0x1d,0x22, + 0xfe,0xcb,0x21,0x27,0x27,0x21,0xfe,0xcb,0x3,0x1c,0x1d,0x1d,0x22,0xfd,0x6,0x22,0x1d,0x1d,0x22,0x2,0xfa,0x2,0x9e,0x21,0x27,0x27,0x21,0xf9,0x22,0x1d, + 0x1d,0x22,0xf9,0x21,0x27,0x27,0x21,0xf9,0x22,0x1d,0x1d,0x22,0xf9,0xfe,0x60,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xc3, + 0xff,0xf6,0x4,0x9,0x4,0xa3,0x0,0x19,0x0,0x6,0xb3,0x5,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x21,0x11, + 0x14,0x6,0x23,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x21,0x3,0xec,0x1d,0x21,0x29,0x2,0x29,0x21,0xfd,0xe6,0x21,0x29,0x2,0x29,0x21,0x1d,0x22,0x2, + 0xc8,0x4,0xa3,0x1f,0x25,0xfb,0xd8,0x23,0x1e,0x1e,0x23,0x3,0xdc,0xfc,0x24,0x23,0x1e,0x1e,0x23,0x4,0x28,0x25,0x1f,0x0,0x0,0x1,0x0,0x74,0xff,0xea, + 0x4,0x50,0x4,0xad,0x0,0x1e,0x0,0x6,0xb3,0x1b,0x7,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x23,0x22,0x26, + 0x35,0x34,0x36,0x33,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x36,0x33,0x32,0x17,0x4,0x35,0x1b,0x6,0xfe,0x85,0xd,0x32,0x2b,0x2b,0x33,0xe,0xc1,0x85,0x22, + 0x1d,0x1d,0x22,0xc0,0x17,0x1b,0x7,0xb5,0x1,0x58,0x8,0x1a,0x14,0xe,0x1a,0x4,0x9b,0x1a,0x13,0xd,0x12,0xfb,0xdc,0x23,0x1e,0x1f,0x22,0x1,0xd3,0x21, + 0x27,0x27,0x21,0xf,0x11,0xfe,0x48,0x3,0xc9,0x18,0x16,0x8,0x0,0x3,0x0,0xa5,0xfc,0xba,0x4,0x10,0x7,0x5,0x0,0x3,0x0,0x25,0x0,0x29,0x0,0xa, + 0xb7,0x28,0x26,0x16,0x4,0x2,0x0,0x3,0x30,0x2b,0x1,0x23,0x35,0x33,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x1,0x16,0x15,0x14,0x7,0x1,0x21,0x32,0x16, + 0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x1,0x1,0x26,0x35,0x34,0x36,0x33,0x21,0x1,0x23,0x35,0x33,0x2,0x66,0x1,0x1,0x1,0x79,0x1d,0x1d, + 0x22,0xfd,0xd5,0x1,0x48,0xb,0xb,0xfe,0xa4,0x2,0x53,0x22,0x1d,0x1d,0x22,0xfd,0x15,0x22,0x1f,0x10,0x1,0x85,0xfe,0x8b,0xc,0x1f,0x22,0x2,0xc3,0xfe, + 0xa9,0x1,0x1,0x7,0x4,0x1,0xfd,0x9e,0x21,0x27,0x27,0x21,0xfe,0x6b,0xe,0x10,0x11,0xe,0xfe,0x4f,0x21,0x27,0x27,0x21,0x1f,0x25,0x20,0x15,0x1,0xe6, + 0x1,0xcf,0xe,0x23,0x25,0x1f,0xf8,0x17,0x1,0x0,0x0,0x2,0x0,0xcd,0xff,0xea,0x3,0xfe,0x4,0xb9,0x0,0x17,0x0,0x1b,0x0,0x8,0xb5,0x1b,0x19,0xa, + 0x0,0x2,0x30,0x2b,0x0,0x16,0x17,0x1,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x1,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x3,0x13, + 0x13,0x3,0x2,0x8f,0x2d,0x14,0x1,0x26,0x8,0x8,0xfe,0xda,0x14,0x2d,0x29,0x29,0x2d,0x14,0xfe,0xd9,0x8,0x8,0x1,0x27,0x14,0x2d,0x29,0xf6,0xf6,0xf6, + 0xf6,0x4,0xb9,0x1e,0x23,0xfd,0xf7,0xd,0x11,0x11,0xd,0xfd,0xf8,0x23,0x1e,0x1e,0x23,0x2,0x8,0x10,0xe,0xe,0x10,0x2,0x9,0x23,0x1e,0xfd,0x98,0xfe, + 0x4d,0x1,0xb3,0x1,0xb4,0x0,0x0,0x1,0x2,0x1b,0xfe,0x9d,0x2,0xb1,0x5,0x72,0x0,0xd,0x0,0x2e,0x4b,0xb0,0x17,0x50,0x58,0x40,0xc,0x2,0x1,0x1, + 0x0,0x1,0x72,0x0,0x0,0x0,0x13,0x0,0x4c,0x1b,0x40,0xa,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x59,0x40,0xa,0x0,0x0,0x0,0xd,0x0, + 0xc,0x25,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x2,0x8f,0x22,0x22,0x29,0x29,0x22,0x22,0x29,0x5, + 0x72,0x1e,0x23,0xf9,0xad,0x23,0x1e,0x1e,0x23,0x6,0x53,0x23,0x1e,0x0,0x0,0x0,0x0,0x2,0x2,0x1b,0xfe,0x9d,0x2,0xb1,0x5,0x72,0x0,0xd,0x0,0x1b, + 0x0,0x50,0x4b,0xb0,0x17,0x50,0x58,0x40,0x15,0x4,0x1,0x1,0x0,0x0,0x3,0x1,0x0,0x63,0x5,0x1,0x3,0x3,0x2,0x5b,0x0,0x2,0x2,0x13,0x2,0x4c, + 0x1b,0x40,0x1b,0x4,0x1,0x1,0x0,0x0,0x3,0x1,0x0,0x63,0x5,0x1,0x3,0x2,0x2,0x3,0x57,0x5,0x1,0x3,0x3,0x2,0x5b,0x0,0x2,0x3,0x2,0x4f, + 0x59,0x40,0x12,0xe,0xe,0x0,0x0,0xe,0x1b,0xe,0x1a,0x15,0x13,0x0,0xd,0x0,0xc,0x25,0x6,0x7,0x15,0x2b,0x0,0x16,0x15,0x11,0x14,0x6,0x23,0x22, + 0x26,0x35,0x11,0x34,0x36,0x33,0x12,0x16,0x15,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x2,0x8f,0x22,0x22,0x29,0x29,0x22,0x22,0x29,0x29, + 0x22,0x22,0x29,0x29,0x22,0x22,0x29,0x5,0x72,0x1e,0x23,0xfd,0xa9,0x23,0x1e,0x1e,0x23,0x2,0x57,0x23,0x1e,0xfc,0x4,0x1e,0x23,0xfd,0xa9,0x23,0x1e,0x1e, + 0x23,0x2,0x57,0x23,0x1e,0x0,0x0,0x0,0x0,0x2,0x0,0x32,0xff,0x67,0x4,0x92,0x4,0x36,0x0,0x4a,0x0,0x58,0x0,0x5b,0x40,0x58,0x1a,0x17,0x2,0xa, + 0x2,0xa,0x1,0x3,0xa,0x2,0x4a,0x0,0x6,0x0,0x5,0x0,0x6,0x5,0x70,0xb,0x1,0x8,0x0,0x4,0x2,0x8,0x4,0x63,0x0,0x2,0xc,0x1,0xa,0x3, + 0x2,0xa,0x63,0x9,0x1,0x3,0x1,0x1,0x0,0x6,0x3,0x0,0x63,0x0,0x5,0x7,0x7,0x5,0x57,0x0,0x5,0x5,0x7,0x5b,0x0,0x7,0x5,0x7,0x4f,0x4b, + 0x4b,0x0,0x0,0x4b,0x58,0x4b,0x57,0x52,0x50,0x0,0x4a,0x0,0x49,0x27,0x32,0x26,0x25,0x2e,0x26,0x24,0x26,0xd,0x7,0x1c,0x2b,0x0,0x16,0x16,0x15,0x14, + 0x6,0x6,0x23,0x22,0x26,0x27,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x7,0x3,0x6,0x15, + 0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6, + 0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0x2,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x2d,0xe7,0x7e,0x46,0x80, + 0x53,0x41,0x5d,0x17,0x34,0x5e,0x3f,0x31,0x51,0x2e,0x56,0x92,0x55,0x56,0x2a,0x1f,0x6,0x13,0xf,0x13,0x14,0x17,0x4,0x4d,0x7,0x28,0x23,0x4b,0x56,0x60, + 0xb1,0x79,0x88,0xdd,0x7d,0x5a,0xae,0x7b,0x45,0x85,0x35,0x8,0x3,0x1c,0xd,0x5,0x18,0x36,0x97,0x51,0x9f,0xe6,0x7b,0x9f,0x1,0x16,0xad,0x3c,0x55,0x39, + 0x24,0x1e,0x31,0x57,0x34,0x28,0x24,0x4,0x36,0x8b,0xf8,0xa0,0x74,0xb3,0x63,0x42,0x3f,0x43,0x43,0x36,0x65,0x46,0x5b,0xca,0x87,0x64,0x3f,0xb,0x7,0x7, + 0x19,0xe,0xfe,0xd2,0x1b,0x19,0x2a,0x2f,0x93,0x79,0x82,0xbf,0x67,0x95,0xfe,0xfe,0x9f,0x80,0xbd,0x66,0x14,0x11,0x2,0x2d,0x12,0xa,0x1b,0xa,0x18,0x1c, + 0x83,0xf4,0xa7,0xc2,0x1,0x3b,0xb4,0xfe,0x5c,0x59,0x8b,0x47,0x2f,0x2e,0x5b,0x8a,0x42,0x2e,0x33,0x0,0x0,0x0,0x0,0x2,0x0,0x9d,0xff,0xea,0x4,0x44, + 0x4,0xf5,0x0,0x3b,0x0,0x45,0x0,0x42,0x40,0x3f,0x3e,0x3d,0x3a,0x36,0x2c,0x11,0x8,0x7,0x6,0x5,0x1,0x4a,0x0,0x3,0x4,0x5,0x4,0x3,0x5,0x70, + 0x0,0x5,0x6,0x4,0x5,0x6,0x6e,0x0,0x2,0x0,0x4,0x3,0x2,0x4,0x63,0x7,0x1,0x6,0x6,0x0,0x5b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x3c,0x3c, + 0x3c,0x45,0x3c,0x44,0x1b,0x23,0x16,0x2c,0x23,0x24,0x8,0x7,0x1a,0x2b,0x24,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x27,0x6,0x23,0x22,0x26,0x26,0x35,0x34, + 0x36,0x37,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x1,0x36, + 0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x15,0x14,0x7,0x6,0x7,0x17,0x24,0x37,0x1,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x4,0x44,0x2b,0x1f,0x15,0x16, + 0x15,0x78,0x89,0xb5,0x6e,0xa3,0x56,0x68,0x5f,0x2e,0x2e,0x57,0xa1,0x6a,0x9e,0x8b,0x22,0x10,0x18,0x1d,0xf,0x13,0x6b,0x7a,0x3d,0x5a,0x30,0x31,0x32,0x1, + 0x2a,0x36,0x27,0x7,0x1b,0x19,0xd,0x12,0x20,0x1c,0x5,0x38,0x4e,0x9a,0xfe,0x4f,0x5f,0xfe,0xe4,0x48,0x44,0x34,0x5d,0x3c,0x44,0x11,0x1b,0x18,0x12,0x16, + 0x84,0x9e,0x5d,0x9c,0x5d,0x6c,0xa5,0x44,0x3b,0x7c,0x4c,0x62,0x9f,0x5c,0x57,0x14,0x1e,0x16,0x1d,0x2b,0xc,0x47,0x36,0x5c,0x37,0x3f,0x66,0x38,0xfe,0xb9, + 0x6d,0x93,0x1a,0x16,0x3,0x5,0x18,0x15,0xc,0x14,0xc5,0x87,0xa9,0x24,0x76,0x1,0x37,0x35,0x6f,0x47,0x39,0x58,0x31,0x0,0x0,0x1,0x0,0x83,0xfe,0x66, + 0x4,0x5d,0x4,0xa3,0x0,0x20,0x0,0x2c,0x40,0x29,0x0,0x4,0x0,0x1,0x0,0x4,0x1,0x70,0x2,0x1,0x0,0x0,0x5,0x59,0x6,0x1,0x5,0x5,0xe,0x4b, + 0x3,0x1,0x1,0x1,0x13,0x1,0x4c,0x0,0x0,0x0,0x20,0x0,0x1e,0x13,0x23,0x13,0x23,0x24,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x11, + 0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x23,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x2e,0x2,0x35,0x34,0x36,0x36,0x33,0x21,0x4,0x40,0x1d,0x1d,0x22,0x44, + 0x22,0x29,0x29,0x22,0xa0,0x22,0x29,0x29,0x22,0x75,0xb3,0x63,0x69,0xbd,0x7b,0x1,0xfa,0x4,0xa3,0x21,0x27,0x27,0x21,0xfa,0x94,0x23,0x1e,0x1e,0x23,0x5, + 0x6c,0xfa,0x94,0x23,0x1e,0x1e,0x23,0x3,0x4f,0x4,0x53,0x98,0x67,0x6a,0x9b,0x52,0x0,0x0,0x0,0x3,0x0,0x24,0xff,0xea,0x4,0xa8,0x4,0xb9,0x0,0xf, + 0x0,0x1f,0x0,0x4b,0x0,0x67,0xb1,0x6,0x64,0x44,0x40,0x5c,0x0,0x4,0x5,0x7,0x5,0x4,0x7,0x70,0x0,0x7,0x6,0x5,0x7,0x6,0x6e,0xa,0x1,0x1, + 0xb,0x1,0x3,0x9,0x1,0x3,0x63,0xc,0x1,0x9,0x0,0x5,0x4,0x9,0x5,0x63,0x0,0x6,0x0,0x8,0x2,0x6,0x8,0x63,0x0,0x2,0x0,0x0,0x2,0x57, + 0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x20,0x20,0x10,0x10,0x0,0x0,0x20,0x4b,0x20,0x4a,0x44,0x42,0x3a,0x38,0x35,0x33,0x2f,0x2d,0x29,0x28, + 0x10,0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0xd,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0,0x4,0x12,0x15,0x14,0x2,0x4,0x23,0x22,0x24,0x2, + 0x35,0x34,0x12,0x24,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x16,0x16,0x17,0x16,0x16,0x15,0x14,0x7,0x6,0x23, + 0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35, + 0x34,0x36,0x36,0x33,0x3,0xd,0x1,0x7,0x94,0x94,0xfe,0xf8,0xa6,0xa6,0xfe,0xf8,0x94,0x94,0x1,0x7,0xa7,0x85,0xd0,0x73,0x73,0xd0,0x85,0x85,0xd0,0x73, + 0x73,0xd0,0x85,0x3c,0x5d,0x2a,0x15,0x14,0x7,0x10,0x1c,0xc,0x12,0x25,0x41,0x26,0x4f,0x66,0x66,0x4f,0x26,0x41,0x25,0x12,0xc,0x1c,0x10,0x7,0x14,0x15, + 0x2a,0x5d,0x2d,0x5b,0x8f,0x50,0x50,0x8f,0x5b,0x4,0xb9,0xa3,0xfe,0xe6,0xaa,0xaa,0xfe,0xe6,0xa4,0xa4,0x1,0x1a,0xaa,0xaa,0x1,0x1a,0xa3,0x78,0x80,0xe1, + 0x8e,0x8e,0xe2,0x80,0x80,0xe2,0x8e,0x8e,0xe1,0x80,0x98,0x15,0x13,0xa,0x19,0x12,0x10,0x11,0x28,0x8,0x11,0xf,0x71,0x69,0x69,0x71,0xf,0x11,0x8,0x28, + 0x11,0x10,0x12,0x19,0xa,0x13,0x15,0x53,0x9b,0x6a,0x6a,0x9b,0x53,0x0,0x0,0x0,0x0,0x4,0x0,0x24,0xff,0xea,0x4,0xa8,0x4,0xb9,0x0,0xf,0x0,0x1f, + 0x0,0x3d,0x0,0x46,0x0,0x6c,0xb1,0x6,0x64,0x44,0x40,0x61,0x26,0x1,0x5,0x8,0x1,0x4a,0x6,0x1,0x4,0x5,0x2,0x5,0x4,0x2,0x70,0xa,0x1,0x1, + 0xb,0x1,0x3,0x7,0x1,0x3,0x63,0xc,0x1,0x7,0xd,0x1,0x9,0x8,0x7,0x9,0x63,0x0,0x8,0x0,0x5,0x4,0x8,0x5,0x61,0x0,0x2,0x0,0x0,0x2, + 0x57,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x3e,0x3e,0x20,0x20,0x10,0x10,0x0,0x0,0x3e,0x46,0x3e,0x45,0x41,0x3f,0x20,0x3d,0x20,0x3b,0x36, + 0x34,0x31,0x30,0x2e,0x2c,0x10,0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0xe,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0,0x4,0x12,0x15,0x14,0x2, + 0x4,0x23,0x22,0x24,0x2,0x35,0x34,0x12,0x24,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x1e,0x2,0x15,0x14,0x6, + 0x7,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x27,0x23,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x34,0x36,0x33,0x33,0x7,0x15,0x33,0x32,0x36,0x35, + 0x34,0x26,0x23,0x3,0xd,0x1,0x7,0x94,0x94,0xfe,0xf8,0xa6,0xa6,0xfe,0xf8,0x94,0x94,0x1,0x7,0xa7,0x85,0xd0,0x73,0x73,0xd0,0x85,0x85,0xd0,0x73,0x73, + 0xd0,0x85,0x60,0x6e,0x3b,0x4c,0x45,0x6b,0x1a,0x16,0x16,0x16,0x19,0x14,0x9e,0x59,0x1d,0x22,0x22,0x1b,0x1f,0x22,0xbb,0x80,0x6a,0x42,0x44,0x40,0x3d,0x4, + 0xb9,0xa3,0xfe,0xe6,0xaa,0xaa,0xfe,0xe6,0xa4,0xa4,0x1,0x1a,0xaa,0xaa,0x1,0x1a,0xa3,0x78,0x80,0xe1,0x8e,0x8e,0xe2,0x80,0x80,0xe2,0x8e,0x8e,0xe1,0x80, + 0xac,0x38,0x65,0x41,0x4a,0x68,0x17,0x74,0x1d,0x17,0x15,0x15,0x13,0x17,0xb6,0x87,0x23,0x1e,0x1e,0x23,0x2,0x7,0x21,0x1e,0x75,0xd5,0x38,0x34,0x32,0x37, + 0x0,0x0,0x0,0x2,0x0,0xc1,0xff,0x1a,0x4,0xb,0x4,0xa3,0x0,0x35,0x0,0x47,0x0,0x27,0x40,0x24,0x41,0x38,0x1d,0x2,0x4,0x1,0x3,0x1,0x4a,0x0, + 0x1,0x0,0x0,0x1,0x0,0x5d,0x0,0x3,0x3,0x2,0x59,0x0,0x2,0x2,0xe,0x3,0x4c,0x2c,0x29,0x25,0x22,0x34,0x37,0x4,0x7,0x16,0x2b,0x0,0x6,0x7, + 0x16,0x15,0x14,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x32,0x36,0x35,0x34,0x26,0x27,0x25,0x26,0x26,0x35,0x34,0x36,0x37,0x26,0x35,0x34, + 0x36,0x36,0x33,0x21,0x32,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x6,0x15,0x14,0x16,0x17,0x5,0x16,0x16,0x15,0x5,0x16,0x17,0x36,0x36,0x35,0x34,0x26,0x27, + 0x25,0x26,0x27,0x6,0x6,0x15,0x14,0x16,0x17,0x4,0xb,0x3d,0x3c,0x14,0x3f,0x7c,0x58,0xfe,0xba,0x22,0x1d,0x1d,0x22,0x1,0x32,0x46,0x47,0x2b,0x30,0xfe, + 0xb3,0x54,0x4f,0x3d,0x3c,0x14,0x3f,0x7c,0x58,0x1,0x46,0x22,0x1d,0x1d,0x22,0xfe,0xce,0x46,0x47,0x2b,0x30,0x1,0x4d,0x54,0x4f,0xff,0x1,0x12,0x20,0x19, + 0x1a,0x31,0x33,0xfe,0xb3,0x12,0x20,0x19,0x1a,0x31,0x33,0x1,0xb,0x64,0x2d,0x31,0x3f,0x47,0x6c,0x3d,0x21,0x27,0x27,0x21,0x33,0x31,0x2b,0x3c,0x1e,0xce, + 0x34,0x82,0x59,0x42,0x64,0x2d,0x31,0x3f,0x47,0x6c,0x3d,0x21,0x27,0x27,0x21,0x33,0x31,0x2b,0x3c,0x1e,0xce,0x34,0x82,0x59,0x40,0xb,0x18,0x13,0x30,0x20, + 0x2d,0x48,0x20,0xce,0xb,0x18,0x13,0x30,0x20,0x2d,0x48,0x20,0x0,0x0,0x0,0x2,0x0,0x3c,0x2,0xec,0x4,0xf9,0x5,0x2a,0x0,0x23,0x0,0x3a,0x0,0x8, + 0xb5,0x2d,0x24,0x5,0x0,0x2,0x30,0x2b,0x0,0x16,0x17,0x13,0x16,0x6,0x23,0x22,0x26,0x27,0x3,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x27,0x3,0x6,0x6, + 0x23,0x22,0x26,0x37,0x13,0x36,0x36,0x33,0x32,0x17,0x13,0x13,0x36,0x33,0x4,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x23, + 0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x4,0xb6,0x21,0x2,0x1e,0x2,0x19,0x22,0x22,0x1b,0x2,0x12,0x5d,0xc,0x26,0x16,0x16,0x27,0xb,0x5e,0x11,0x2,0x1b, + 0x22,0x22,0x19,0x2,0x1e,0x2,0x21,0x22,0x32,0xc,0x8e,0x8e,0xc,0x32,0xfd,0x87,0x1d,0x1d,0x22,0x81,0x1c,0x22,0x22,0x1c,0x81,0x22,0x1d,0x1d,0x22,0x1, + 0x7e,0x5,0x2a,0x1e,0x23,0xfe,0x44,0x23,0x1e,0x1d,0x24,0x1,0x3,0xc0,0x17,0x19,0x19,0x17,0xc0,0xfe,0xfd,0x24,0x1d,0x1e,0x23,0x1,0xbc,0x23,0x1e,0x1a, + 0xfe,0xd5,0x1,0x2b,0x1a,0xa,0x1b,0x21,0x21,0x1a,0xfe,0x84,0x23,0x1e,0x1e,0x23,0x1,0x7c,0x1a,0x21,0x21,0x1b,0x0,0x2,0x0,0xf6,0x2,0x89,0x3,0x26, + 0x4,0xb9,0x0,0xf,0x0,0x1f,0x0,0x2a,0xb1,0x6,0x64,0x44,0x40,0x1f,0x0,0x0,0x0,0x3,0x2,0x0,0x3,0x63,0x0,0x2,0x1,0x1,0x2,0x57,0x0,0x2, + 0x2,0x1,0x5b,0x0,0x1,0x2,0x1,0x4f,0x26,0x26,0x26,0x22,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x12,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6, + 0x6,0x23,0x22,0x26,0x26,0x35,0x1e,0x2,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0xf6,0x4b,0x81,0x4c,0x4c,0x81,0x4b,0x4b,0x81, + 0x4c,0x4c,0x81,0x4b,0x87,0x27,0x43,0x27,0x27,0x43,0x27,0x27,0x43,0x27,0x27,0x43,0x27,0x3,0xed,0x81,0x4b,0x4b,0x81,0x4c,0x4c,0x81,0x4b,0x4b,0x81,0x4c, + 0x27,0x43,0x27,0x27,0x43,0x27,0x27,0x43,0x27,0x27,0x43,0x27,0x0,0x1,0x0,0xe8,0x1,0xf6,0x3,0xe3,0x4,0xb9,0x0,0x1d,0x0,0x28,0xb1,0x6,0x64,0x44, + 0x40,0x1d,0xe,0x5,0x2,0x0,0x2,0x1,0x4a,0x3,0x1,0x2,0x0,0x2,0x72,0x1,0x1,0x0,0x0,0x69,0x0,0x0,0x0,0x1d,0x0,0x1c,0x27,0x19,0x4,0x7, + 0x16,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x17,0x1,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x3,0x6,0x6,0x23,0x22,0x27,0x26,0x26,0x35, + 0x34,0x37,0x1,0x36,0x36,0x33,0x2,0x82,0x1e,0xa,0x1,0x34,0x5,0x1a,0x14,0x16,0x16,0x13,0x1c,0x7,0xed,0xed,0x7,0x1c,0x13,0x11,0x17,0x16,0x1d,0x6, + 0x1,0x34,0xa,0x1e,0x1c,0x4,0xb9,0x12,0x13,0xfd,0xb1,0x9,0xc,0x11,0x1a,0x7,0x8,0xd,0xc,0x1,0xe0,0xfe,0x20,0xc,0xd,0x7,0x7,0x1b,0x11,0xb, + 0xa,0x2,0x4f,0x13,0x12,0x0,0x0,0x1,0x1,0x22,0x1,0x19,0x3,0xaa,0x4,0xb9,0x0,0x1f,0x0,0x29,0x40,0x26,0x2,0x1,0x0,0x0,0x3,0x59,0x6,0x5, + 0x2,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0x4,0x5b,0x0,0x4,0x4,0x16,0x1,0x4c,0x0,0x0,0x0,0x1f,0x0,0x1e,0x23,0x24,0x23,0x23,0x24,0x7,0x7,0x19, + 0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x11,0x14,0x6,0x23,0x22,0x26,0x35,0x11,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x35,0x34,0x36,0x33,0x32,0x16, + 0x15,0x15,0x33,0x3,0x8d,0x1d,0x1d,0x22,0xbd,0x21,0x27,0x27,0x21,0xbd,0x22,0x1d,0x1d,0x22,0xbd,0x21,0x27,0x27,0x21,0xbd,0x3,0x9c,0x21,0x27,0x27,0x21, + 0xfe,0x4c,0x22,0x1d,0x1d,0x22,0x1,0xb4,0x21,0x27,0x27,0x21,0xde,0x22,0x1d,0x1d,0x22,0xde,0x0,0x1,0x1,0x22,0x0,0xdd,0x3,0xaa,0x4,0xb9,0x0,0x31, + 0x0,0xdf,0x4b,0xb0,0xc,0x50,0x58,0x40,0x20,0x7,0x1,0x5,0x8,0x1,0x4,0x3,0x5,0x4,0x61,0xa,0x9,0x2,0x3,0x2,0x1,0x0,0x1,0x3,0x0,0x61, + 0x0,0x1,0x1,0x6,0x5b,0x0,0x6,0x6,0x16,0x1,0x4c,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x22,0xa,0x9,0x2,0x3,0x2,0x1,0x0,0x1,0x3,0x0,0x61, + 0x8,0x1,0x4,0x4,0x5,0x59,0x7,0x1,0x5,0x5,0x11,0x4b,0x0,0x1,0x1,0x6,0x5b,0x0,0x6,0x6,0x16,0x1,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40, + 0x20,0x7,0x1,0x5,0x8,0x1,0x4,0x3,0x5,0x4,0x61,0xa,0x9,0x2,0x3,0x2,0x1,0x0,0x1,0x3,0x0,0x61,0x0,0x1,0x1,0x6,0x5b,0x0,0x6,0x6, + 0x16,0x1,0x4c,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x22,0xa,0x9,0x2,0x3,0x2,0x1,0x0,0x1,0x3,0x0,0x61,0x8,0x1,0x4,0x4,0x5,0x59,0x7,0x1, + 0x5,0x5,0x11,0x4b,0x0,0x1,0x1,0x6,0x5b,0x0,0x6,0x6,0x16,0x1,0x4c,0x1b,0x40,0x20,0x7,0x1,0x5,0x8,0x1,0x4,0x3,0x5,0x4,0x61,0xa,0x9, + 0x2,0x3,0x2,0x1,0x0,0x1,0x3,0x0,0x61,0x0,0x1,0x1,0x6,0x5b,0x0,0x6,0x6,0x16,0x1,0x4c,0x59,0x59,0x59,0x59,0x40,0x12,0x0,0x0,0x0,0x31, + 0x0,0x30,0x24,0x23,0x23,0x24,0x21,0x24,0x23,0x23,0x24,0xb,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x23,0x15,0x14,0x6,0x23,0x22,0x26,0x35,0x35, + 0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x35,0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x33,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x33,0x32,0x16,0x15,0x14, + 0x6,0x23,0x23,0x15,0x33,0x3,0x8d,0x1d,0x1d,0x22,0xbd,0x21,0x27,0x27,0x21,0xbd,0x22,0x1d,0x1d,0x22,0xbd,0xbd,0x22,0x1d,0x1d,0x22,0xbd,0x21,0x27,0x27, + 0x21,0xbd,0x22,0x1d,0x1d,0x22,0xbd,0xbd,0x2,0x58,0x21,0x27,0x27,0x21,0xac,0x22,0x1d,0x1d,0x22,0xac,0x21,0x27,0x27,0x21,0xe6,0x21,0x27,0x27,0x21,0xac, + 0x22,0x1d,0x1d,0x22,0xac,0x21,0x27,0x27,0x21,0xe6,0x0,0x1,0xfd,0x9,0xfd,0xf2,0xfe,0x4,0xff,0x6e,0x0,0x10,0x0,0x2e,0xb1,0x6,0x64,0x44,0x40,0x23, + 0xa,0x1,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x57,0x2,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x0,0x0,0x0,0x10,0x0, + 0xe,0x15,0x3,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x4,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x13,0x36,0x33,0x33,0xfe,0x4,0x6, + 0x75,0xf,0x2c,0xb,0x6,0x34,0x2,0x3f,0x8,0x22,0x74,0x92,0x1a,0xc,0xd,0xfe,0xdd,0x26,0x1,0x7,0x25,0x4,0xc,0x1,0x1f,0x20,0x0,0x0,0xff,0xff, + 0xfd,0x9,0xfd,0xf2,0xfe,0x4,0xff,0x6e,0x0,0x2,0x1,0x7e,0x0,0x0,0x0,0x1,0x1,0xa1,0x4,0xe,0x3,0x93,0x5,0x87,0x0,0x11,0x0,0x1f,0xb1,0x6, + 0x64,0x44,0x40,0x14,0xe,0x1,0x1,0x0,0x1,0x4a,0x0,0x0,0x1,0x0,0x72,0x0,0x1,0x1,0x69,0x27,0x20,0x2,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x0, + 0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x3,0x1f,0x13,0x22,0x21,0x1e,0x16,0xfe,0x8a,0x12,0xe,0x18,0x16, + 0x18,0x10,0x1,0x5c,0x5,0x87,0x29,0x27,0x1d,0x1a,0xd,0xdb,0xa,0x19,0x1b,0x19,0x13,0xc,0x1,0x0,0x0,0x1,0x0,0xfa,0x3,0x5e,0x2,0x9,0x5,0x20, + 0x0,0x10,0x0,0x19,0x40,0x16,0xa,0x1,0x0,0x1,0x1,0x4a,0x0,0x0,0x0,0x1,0x5b,0x0,0x1,0x1,0x10,0x0,0x4c,0x26,0x26,0x2,0x7,0x16,0x2b,0x0, + 0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x33,0x33,0x1,0xfb,0xe,0x5,0x86,0xd,0x3d,0x1c,0x1e,0x2,0x52,0x8,0x22,0x76, + 0x5,0x20,0xf,0xc,0x9,0xf,0xfe,0x95,0x24,0x16,0x14,0x4,0xa,0x1,0x6a,0x20,0x0,0x0,0x0,0x1,0x1,0x1e,0x4,0x2f,0x3,0xae,0x5,0x5c,0x0,0x1d, + 0x0,0x2e,0xb1,0x6,0x64,0x44,0x40,0x23,0xa,0x1,0x2,0x1,0x1,0x4a,0x3,0x1,0x1,0x2,0x1,0x72,0x0,0x2,0x0,0x0,0x2,0x57,0x0,0x2,0x2,0x0, + 0x5b,0x0,0x0,0x2,0x0,0x4f,0x13,0x23,0x19,0x26,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x26, + 0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x3,0x94,0x1a,0x1,0x17,0xa7,0x89,0x89,0xa7,0x17,0x1,0x1a, + 0x1c,0xf,0xd,0x22,0x9,0x17,0x64,0x50,0x51,0x64,0x16,0x9,0x22,0xd,0xf,0x5,0x53,0x17,0x13,0x8,0x5,0x71,0x7c,0x7c,0x71,0x5,0x8,0x13,0x17,0x6, + 0x3,0x18,0x47,0x44,0x44,0x47,0x18,0x3,0x0,0x1,0x1,0x27,0x4,0x11,0x3,0xa5,0x5,0x76,0x0,0x17,0x0,0x28,0xb1,0x6,0x64,0x44,0x40,0x1d,0x12,0xb, + 0x2,0x2,0x0,0x1,0x4a,0x1,0x1,0x0,0x2,0x0,0x72,0x3,0x1,0x2,0x2,0x69,0x0,0x0,0x0,0x17,0x0,0x16,0x25,0x17,0x4,0x7,0x16,0x2b,0xb1,0x6, + 0x0,0x44,0x0,0x27,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x17,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x7,0x6,0x23,0x2,0x42,0x16,0xf5, + 0x10,0x17,0x15,0x17,0x10,0xf,0xdd,0xdd,0xf,0x10,0x17,0x15,0x17,0x10,0xf5,0x16,0x24,0x4,0x11,0x14,0xe9,0xf,0x12,0x15,0x1a,0x18,0xc,0xad,0xad,0xc, + 0x18,0x1a,0x15,0x12,0xf,0xe9,0x14,0x0,0x0,0x1,0x1,0x8e,0x5,0x1b,0x3,0xc3,0x6,0x6c,0x0,0x13,0x0,0xf,0x40,0xc,0x10,0x1,0x0,0x47,0x0,0x0, + 0x0,0x69,0x20,0x1,0x7,0x15,0x2b,0x0,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x25,0x3,0x58,0xe, + 0x10,0x21,0x13,0x19,0x19,0xfe,0x1f,0x8,0x4,0xe,0x18,0x5,0x4,0x17,0x1,0xa0,0x6,0x6c,0x1e,0x23,0x2c,0x1c,0x1b,0x8,0xa3,0x2,0x13,0xf,0x9,0xd, + 0x1b,0xd,0xe6,0x0,0x0,0x0,0x0,0x1,0x0,0xec,0x5,0x3d,0x3,0xe0,0x6,0x5c,0x0,0x19,0x0,0x2d,0x40,0x2a,0xa,0x2,0x2,0x2,0x1,0x1,0x4a,0x4, + 0x3,0x2,0x1,0x2,0x1,0x72,0x0,0x2,0x0,0x0,0x2,0x57,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x0,0x0,0x0,0x19,0x0,0x18,0x23,0x26, + 0x26,0x5,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x36, + 0x33,0x3,0xb3,0x2d,0x1,0x19,0xc7,0x99,0x99,0xc7,0x19,0x1,0x2d,0x19,0x1d,0xa,0x22,0x82,0x69,0x69,0x82,0x22,0xa,0x1d,0x6,0x5c,0x1f,0x15,0x5,0x3, + 0x69,0x7a,0x7a,0x69,0x3,0x5,0x15,0x1f,0x14,0x42,0x39,0x39,0x42,0x14,0x0,0x1,0x1,0xa,0x5,0x1b,0x3,0xc2,0x6,0x71,0x0,0x19,0x0,0x1b,0x40,0x18, + 0x18,0x1,0x0,0x1,0x1,0x4a,0x1,0x1,0x1,0x48,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x28,0x2a,0x2,0x7,0x16,0x2b,0x0,0x33,0x32,0x16,0x17, + 0x16,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x25,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x5,0x25,0x3,0x84,0xc,0xc,0x15,0x7,0xa,0x10,0xfe, + 0xeb,0x16,0x21,0x20,0x17,0xfe,0xeb,0x10,0xa,0x7,0x15,0xc,0xb,0x8,0x1,0x17,0x1,0x17,0x6,0x71,0xe,0xc,0x11,0xf,0x13,0xf,0xe8,0x12,0x12,0xe8, + 0xf,0x13,0xf,0x11,0xc,0xe,0x5,0x9f,0x9f,0x0,0xff,0xff,0x1,0x5f,0xfe,0x28,0x3,0x62,0x0,0x1c,0x0,0x2,0x1,0x91,0x0,0x0,0x0,0x1,0x1,0xa, + 0x5,0x18,0x3,0xc2,0x6,0x6e,0x0,0x19,0x0,0x1b,0x40,0x18,0x18,0x1,0x1,0x0,0x1,0x4a,0x1,0x1,0x1,0x47,0x0,0x0,0x1,0x0,0x72,0x0,0x1,0x1, + 0x69,0x28,0x2a,0x2,0x7,0x16,0x2b,0x0,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x25,0x36,0x33,0x32,0x17,0x5,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22, + 0x27,0x25,0x5,0x1,0x47,0xb,0xc,0x15,0x7,0xa,0x10,0x1,0x15,0x17,0x20,0x20,0x17,0x1,0x15,0x10,0xa,0x7,0x15,0xc,0xc,0x7,0xfe,0xe9,0xfe,0xe9, + 0x5,0x18,0xe,0xc,0x11,0xf,0x13,0xf,0xe8,0x12,0x12,0xe8,0xf,0x13,0xf,0x11,0xc,0xe,0x5,0x9f,0x9f,0x0,0x0,0x2,0x1,0x35,0x5,0x53,0x3,0x97, + 0x6,0x57,0x0,0xd,0x0,0x1b,0x0,0x1d,0x40,0x1a,0x3,0x1,0x1,0x0,0x0,0x1,0x57,0x3,0x1,0x1,0x1,0x0,0x5b,0x2,0x1,0x0,0x1,0x0,0x4f,0x25, + 0x25,0x25,0x21,0x4,0x7,0x18,0x2b,0x0,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x4,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36, + 0x33,0x32,0x16,0x15,0x15,0x1,0xf3,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x1,0xa4,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x5,0x70,0x1d,0x1d,0x24, + 0x82,0x24,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0x0,0x0,0x0,0x1,0x2,0x7,0x5,0x53,0x2,0xc5,0x6,0x57,0x0,0xd, + 0x0,0x18,0x40,0x15,0x0,0x1,0x0,0x0,0x1,0x57,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x25,0x21,0x2,0x7,0x16,0x2b,0x0,0x6,0x23,0x22, + 0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x2,0xc5,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x5,0x70,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24, + 0x82,0x0,0x0,0x0,0x0,0x1,0x1,0x9,0x5,0x1b,0x3,0x3e,0x6,0x6c,0x0,0x11,0x0,0x11,0x40,0xe,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x29, + 0x13,0x2,0x7,0x16,0x2b,0x0,0x15,0x14,0x6,0x23,0x22,0x27,0x25,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x5,0x3,0x3e,0x1b,0x14,0x4,0x8,0xfe, + 0x1f,0x19,0x19,0x13,0x21,0x10,0xe,0x13,0x1,0xa0,0x5,0x6e,0x1b,0x16,0x22,0x2,0xa3,0x8,0x1b,0x1c,0x2c,0x23,0x1e,0xb,0xe6,0x0,0x0,0x0,0x0,0x2, + 0x1,0x2d,0x5,0x2b,0x4,0x50,0x6,0x77,0x0,0x11,0x0,0x23,0x0,0x1e,0x40,0x1b,0x1c,0x13,0xa,0x1,0x4,0x0,0x1,0x1,0x4a,0x3,0x1,0x1,0x0,0x1, + 0x72,0x2,0x1,0x0,0x0,0x69,0x27,0x27,0x27,0x25,0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x36,0x33, + 0x32,0x17,0x4,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x36,0x33,0x32,0x17,0x2,0xd4,0x12,0xfe,0xd3,0x13,0x15,0x16,0x14,0x16, + 0xe,0xf1,0x18,0x1e,0x1d,0x22,0x1,0xaf,0x12,0xfe,0xd3,0x14,0x14,0x16,0x14,0x16,0xe,0xf1,0x18,0x1e,0x1d,0x22,0x6,0x40,0x1a,0x10,0xc,0xd2,0xd,0xd, + 0xd,0x16,0xf,0xe,0xe9,0x16,0x16,0x21,0x1a,0x10,0xc,0xd2,0xd,0xd,0xd,0x16,0xf,0xe,0xe9,0x16,0x16,0x0,0x0,0x1,0x1,0xe,0x5,0x60,0x3,0xbe, + 0x5,0xf0,0x0,0xd,0x0,0x1f,0x40,0x1c,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0xd, + 0x0,0xb,0x34,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x3,0xa1,0x1d,0x1d,0x22,0xfd,0xce,0x22,0x1d, + 0x1d,0x22,0x2,0x32,0x5,0xf0,0x21,0x27,0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0xff,0xff,0x1,0x9b,0xfe,0x28,0x3,0x29,0x0,0x1c,0x0,0x2,0x1,0x98, + 0x0,0x0,0xff,0xff,0x1,0x70,0x5,0x37,0x3,0x5c,0x7,0x23,0x1,0x7,0x1,0x99,0x0,0x0,0x1,0xe,0x0,0x9,0xb1,0x0,0x2,0xb8,0x1,0xe,0xb0,0x33, + 0x2b,0x0,0x0,0x0,0x0,0x1,0x1,0xb,0x5,0x4c,0x3,0xc1,0x6,0x1f,0x0,0x23,0x0,0x60,0x4b,0xb0,0x22,0x50,0x58,0x40,0x1b,0x0,0x0,0x3,0x2,0x0, + 0x57,0x6,0x5,0x2,0x1,0x0,0x3,0x2,0x1,0x3,0x63,0x0,0x0,0x0,0x2,0x5b,0x4,0x1,0x2,0x0,0x2,0x4f,0x1b,0x40,0x29,0x0,0x1,0x5,0x0,0x5, + 0x1,0x0,0x70,0x0,0x4,0x3,0x2,0x3,0x4,0x2,0x70,0x0,0x0,0x3,0x2,0x0,0x57,0x6,0x1,0x5,0x0,0x3,0x4,0x5,0x3,0x63,0x0,0x0,0x0,0x2, + 0x5b,0x0,0x2,0x0,0x2,0x4f,0x59,0x40,0xe,0x0,0x0,0x0,0x23,0x0,0x22,0x13,0x24,0x26,0x13,0x24,0x7,0x7,0x19,0x2b,0x0,0x16,0x17,0x16,0x16,0x33, + 0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33, + 0x2,0x6,0x3b,0x30,0x2d,0x36,0x1d,0x41,0x46,0xa,0xa,0x17,0x13,0xb,0x11,0x6d,0x5b,0x22,0x3b,0x30,0x2d,0x36,0x1d,0x40,0x47,0xb,0x9,0x17,0x13,0xb, + 0x11,0x6d,0x5b,0x6,0x1f,0x10,0x11,0x10,0xe,0x2a,0x6,0x1f,0x12,0x13,0x18,0xd,0x5b,0x10,0x11,0x10,0xe,0x2a,0x6,0x1f,0x12,0x13,0x18,0xd,0x5b,0x0, + 0x0,0x0,0x0,0x1,0x1,0x5f,0xfe,0x28,0x3,0x62,0x0,0x1c,0x0,0x20,0x0,0x75,0xb1,0x6,0x64,0x44,0xb5,0xb,0x1,0x1,0x3,0x1,0x4a,0x4b,0xb0,0xa, + 0x50,0x58,0x40,0x27,0x0,0x0,0x5,0x4,0x3,0x0,0x68,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x5,0x0,0x4,0x2,0x5,0x4,0x63,0x0,0x3,0x1, + 0x1,0x3,0x57,0x0,0x3,0x3,0x1,0x5c,0x0,0x1,0x3,0x1,0x50,0x1b,0x40,0x28,0x0,0x0,0x5,0x4,0x5,0x0,0x4,0x70,0x0,0x2,0x4,0x3,0x4,0x2, + 0x3,0x70,0x0,0x5,0x0,0x4,0x2,0x5,0x4,0x63,0x0,0x3,0x1,0x1,0x3,0x57,0x0,0x3,0x3,0x1,0x5c,0x0,0x1,0x3,0x1,0x50,0x59,0x40,0x9,0x14, + 0x24,0x24,0x17,0x24,0x10,0x6,0x7,0x1a,0x2b,0xb1,0x6,0x0,0x44,0x5,0x36,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32, + 0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x7,0x22,0x26,0x35,0x35,0x33,0x2,0x97,0x65,0x66,0x7c,0x79,0x44,0x80,0x33,0x17,0x8,0x11,0x1d,0x8, + 0x5,0x2b,0x67,0x2f,0x33,0x3a,0x36,0x3e,0x27,0xf,0x13,0x84,0x71,0x1,0x5e,0x4b,0x57,0x68,0x18,0x18,0xa,0x19,0xe,0x15,0x2d,0x2,0x10,0x16,0x21,0x1f, + 0x21,0x20,0x1,0x15,0x17,0xcd,0x0,0x0,0x0,0x1,0x1,0x27,0x4,0xf,0x3,0xa5,0x5,0x74,0x0,0x17,0x0,0x28,0xb1,0x6,0x64,0x44,0x40,0x1d,0x12,0xb, + 0x2,0x0,0x2,0x1,0x4a,0x3,0x1,0x2,0x0,0x2,0x72,0x1,0x1,0x0,0x0,0x69,0x0,0x0,0x0,0x17,0x0,0x16,0x25,0x17,0x4,0x7,0x16,0x2b,0xb1,0x6, + 0x0,0x44,0x0,0x17,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x36,0x33,0x2,0x8a,0x16,0xf5, + 0x10,0x17,0x15,0x17,0x10,0xf,0xdd,0xdd,0xf,0x10,0x17,0x15,0x17,0x10,0xf5,0x16,0x24,0x5,0x74,0x14,0xe9,0xf,0x12,0x15,0x1a,0x18,0xc,0xad,0xad,0xc, + 0x18,0x1a,0x15,0x12,0xf,0xe9,0x14,0x0,0x0,0x2,0x1,0x35,0x4,0x4f,0x3,0x97,0x5,0x53,0x0,0xd,0x0,0x1b,0x0,0x25,0xb1,0x6,0x64,0x44,0x40,0x1a, + 0x3,0x1,0x1,0x0,0x0,0x1,0x57,0x3,0x1,0x1,0x1,0x0,0x5b,0x2,0x1,0x0,0x1,0x0,0x4f,0x25,0x25,0x25,0x21,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0, + 0x44,0x0,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x4,0x6,0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x1, + 0xf3,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x1,0xa4,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x4,0x6c,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82, + 0x24,0x1d,0x1d,0x24,0x82,0x24,0x1d,0x1d,0x24,0x82,0x0,0x0,0x0,0x1,0x2,0x7,0x4,0x4f,0x2,0xc5,0x5,0x53,0x0,0xd,0x0,0x20,0xb1,0x6,0x64,0x44, + 0x40,0x15,0x0,0x1,0x0,0x0,0x1,0x57,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x25,0x21,0x2,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x0,0x6, + 0x23,0x22,0x26,0x35,0x35,0x34,0x36,0x33,0x32,0x16,0x15,0x15,0x2,0xc5,0x28,0x37,0x37,0x28,0x28,0x37,0x37,0x28,0x4,0x6c,0x1d,0x1d,0x24,0x82,0x24,0x1d, + 0x1d,0x24,0x82,0x0,0x0,0x0,0x0,0x1,0x1,0x39,0x4,0xe,0x3,0x2b,0x5,0x87,0x0,0x11,0x0,0x19,0xb1,0x6,0x64,0x44,0x40,0xe,0x0,0x1,0x0,0x1, + 0x72,0x0,0x0,0x0,0x69,0x18,0x15,0x2,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x1,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x25,0x26,0x35,0x34,0x37,0x36, + 0x33,0x32,0x17,0x3,0x1b,0x10,0x18,0x16,0x18,0xe,0x12,0xfe,0x8a,0x16,0x1e,0x21,0x22,0x13,0x12,0x4,0x7a,0xc,0x13,0x19,0x1b,0x19,0xa,0xdb,0xd,0x1a, + 0x1d,0x27,0x29,0xd,0x0,0x2,0x1,0x3d,0x4,0xf,0x4,0x4f,0x5,0x76,0x0,0x11,0x0,0x23,0x0,0x26,0xb1,0x6,0x64,0x44,0x40,0x1b,0x1c,0x13,0xa,0x1, + 0x4,0x0,0x1,0x1,0x4a,0x3,0x1,0x1,0x0,0x1,0x72,0x2,0x1,0x0,0x0,0x69,0x27,0x27,0x27,0x25,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x0,0x15, + 0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x36,0x33,0x32,0x17,0x4,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37, + 0x36,0x33,0x32,0x17,0x2,0xd3,0x13,0xfe,0xf2,0x11,0x14,0x16,0x1c,0x1e,0xa,0xed,0x17,0x20,0x1c,0x1f,0x1,0xa9,0x13,0xfe,0xf2,0x11,0x14,0x16,0x1c,0x1e, + 0xa,0xed,0x17,0x20,0x1c,0x1f,0x5,0x47,0x1d,0x13,0x11,0xe9,0xe,0x11,0x13,0x16,0xd,0xa,0xfd,0x19,0x13,0x1c,0x1d,0x13,0x11,0xe9,0xe,0x11,0x13,0x16, + 0xd,0xa,0xfd,0x19,0x13,0x0,0x0,0x1,0x1,0x22,0x4,0x52,0x3,0xaa,0x4,0xe2,0x0,0xd,0x0,0x27,0xb1,0x6,0x64,0x44,0x40,0x1c,0x2,0x1,0x1,0x0, + 0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0xd,0x0,0xb,0x34,0x3,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0, + 0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x36,0x33,0x21,0x3,0x8d,0x1d,0x1d,0x22,0xfd,0xf6,0x22,0x1d,0x1d,0x22,0x2,0xa,0x4,0xe2,0x21,0x27, + 0x27,0x21,0x21,0x27,0x27,0x21,0x0,0x0,0x0,0x1,0x1,0x9b,0xfe,0x28,0x3,0x29,0x0,0x1c,0x0,0x19,0x0,0x4d,0xb1,0x6,0x64,0x44,0x4b,0xb0,0x1b,0x50, + 0x58,0x40,0x17,0x0,0x3,0x0,0x3,0x72,0x1,0x1,0x0,0x2,0x2,0x0,0x57,0x1,0x1,0x0,0x0,0x2,0x5c,0x0,0x2,0x0,0x2,0x50,0x1b,0x40,0x1a,0x0, + 0x3,0x1,0x3,0x72,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x2,0x2,0x0,0x57,0x0,0x0,0x0,0x2,0x5c,0x0,0x2,0x0,0x2,0x50,0x59,0xb6,0x15,0x27,0x31, + 0x24,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x4,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26, + 0x35,0x34,0x36,0x37,0x33,0x2,0x92,0x5b,0x2a,0x23,0x34,0x3d,0x8,0x3,0x1e,0x9,0x2,0x11,0x11,0x4b,0x59,0x5d,0x6b,0x61,0x5b,0xa5,0x42,0x86,0x3c,0x23, + 0x26,0x11,0x2,0x36,0x12,0x7,0x16,0x19,0x6,0x1a,0x68,0x57,0x51,0x96,0x4e,0x0,0x0,0x0,0x0,0x2,0x1,0x70,0x4,0x29,0x3,0x5c,0x6,0x15,0x0,0xf, + 0x0,0x1b,0x0,0x37,0xb1,0x6,0x64,0x44,0x40,0x2c,0x4,0x1,0x1,0x5,0x1,0x3,0x2,0x1,0x3,0x63,0x0,0x2,0x0,0x0,0x2,0x57,0x0,0x2,0x2,0x0, + 0x5b,0x0,0x0,0x2,0x0,0x4f,0x10,0x10,0x0,0x0,0x10,0x1b,0x10,0x1a,0x16,0x14,0x0,0xf,0x0,0xe,0x26,0x6,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0, + 0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x2,0xab,0x71, + 0x40,0x40,0x71,0x45,0x45,0x71,0x40,0x40,0x71,0x45,0x34,0x3e,0x3e,0x34,0x34,0x3e,0x3e,0x34,0x6,0x15,0x40,0x71,0x45,0x45,0x71,0x40,0x40,0x71,0x45,0x45, + 0x71,0x40,0x84,0x3e,0x34,0x34,0x3e,0x3e,0x34,0x34,0x3e,0x0,0x0,0x1,0x1,0xe,0x4,0x3e,0x3,0xbe,0x5,0x2d,0x0,0x27,0x0,0x81,0xb1,0x6,0x64,0x44, + 0x4b,0xb0,0x31,0x50,0x58,0x40,0xa,0xe,0x1,0x0,0x1,0x22,0x1,0x2,0x3,0x2,0x4a,0x1b,0x40,0xa,0xe,0x1,0x0,0x5,0x22,0x1,0x2,0x3,0x2,0x4a, + 0x59,0x4b,0xb0,0x31,0x50,0x58,0x40,0x1b,0x0,0x0,0x3,0x2,0x0,0x57,0x6,0x5,0x2,0x1,0x0,0x3,0x2,0x1,0x3,0x63,0x0,0x0,0x0,0x2,0x5b,0x4, + 0x1,0x2,0x0,0x2,0x4f,0x1b,0x40,0x23,0x0,0x1,0x5,0x1,0x72,0x0,0x4,0x2,0x4,0x73,0x0,0x0,0x3,0x2,0x0,0x57,0x6,0x1,0x5,0x0,0x3,0x2, + 0x5,0x3,0x63,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x0,0x2,0x4f,0x59,0x40,0xe,0x0,0x0,0x0,0x27,0x0,0x26,0x23,0x24,0x27,0x23,0x24,0x7,0x7,0x19, + 0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x26, + 0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x2,0x11,0x39,0x28,0x23,0x30,0x1a,0x20,0x3d,0x21,0xc,0x11,0x19,0x16,0x15, + 0xe,0x30,0x6d,0x35,0x23,0x39,0x28,0x23,0x30,0x1a,0x20,0x3d,0x21,0xc,0x11,0x19,0x16,0x15,0xe,0x30,0x6d,0x35,0x5,0x23,0x13,0x12,0x11,0x10,0x22,0x22, + 0xc,0x19,0x16,0x17,0x13,0x11,0x3e,0x3d,0x13,0x12,0x11,0x10,0x22,0x22,0xc,0x19,0x16,0x17,0x13,0x11,0x3e,0x3d,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x3, + 0x4,0x9b,0x81,0xb5,0x3,0x2d,0x5f,0xf,0x3c,0xf5,0x0,0x1,0x8,0x0,0x0,0x0,0x0,0x0,0xd2,0x42,0x4a,0x4,0x0,0x0,0x0,0x0,0xd2,0x42,0x4a,0x5a, + 0xfd,0x9,0xfc,0xba,0xc,0x8b,0x7,0x23,0x0,0x0,0x0,0x7,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x5,0x8d,0xfd,0x7d,0x0,0x0, + 0xe,0x64,0xfd,0x9,0xfe,0x39,0xc,0x8b,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x81,0x4,0x6c,0x0,0xd3, + 0x4,0xcc,0x0,0x0,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc, + 0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x64,0x4,0xcc,0x0,0x14,0x4,0xcc,0x0,0xcd,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96, + 0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0x32,0x4,0xcc,0x0,0xaf,0x4,0xcc, + 0x0,0xaf,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1, + 0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xf5,0x4,0xcc,0x0,0x6e,0x4,0xcc,0x0,0x6e,0x4,0xcc,0x0,0x6e,0x4,0xcc, + 0x0,0x6e,0x4,0xcc,0x0,0x6e,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0x1e,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xb3,0x4,0xcc,0x0,0xc8, + 0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0xc8,0x4,0xcc, + 0x0,0xc8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xd7,0x4,0xcc,0x0,0xd7,0x4,0xcc,0x0,0xf5,0x4,0xcc,0x0,0xe1,0x4,0xcc,0x0,0xf5, + 0x4,0xcc,0x0,0xf5,0x4,0xcc,0x0,0xf5,0x4,0xcc,0x0,0x3c,0x4,0xcc,0x0,0x90,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc, + 0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a, + 0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x54,0x4,0xcc,0x0,0xeb,0x4,0xcc, + 0x0,0xeb,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7, + 0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0x7a,0x4,0xcc,0x0,0x7a,0x4,0xcc,0x0,0x7a,0x4,0xcc, + 0x0,0x7a,0x4,0xcc,0x0,0x7a,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf, + 0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0x63,0x4,0xcc,0x0,0x43,0x4,0xcc, + 0x0,0x43,0x4,0xcc,0x0,0x43,0x4,0xcc,0x0,0x43,0x4,0xcc,0x0,0x43,0x4,0xcc,0x0,0x95,0x4,0xcc,0x0,0x7d,0x4,0xcc,0x0,0x7d,0x4,0xcc,0x0,0x7d, + 0x4,0xcc,0x0,0x7d,0x4,0xcc,0x0,0x7d,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0x9f,0x4,0xcc, + 0x0,0x9f,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9f, + 0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x4b,0x4,0xcc,0x0,0xc0,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x93,0x4,0xcc, + 0x0,0x93,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x89,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94, + 0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94,0x4,0xcc,0x0,0x94,0x4,0xcc, + 0x0,0x94,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0xca, + 0x4,0xcc,0x0,0x14,0x4,0xcc,0x0,0xca,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc, + 0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xde,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xbe, + 0x4,0xcc,0x0,0xbe,0x4,0xcc,0x0,0xbe,0x4,0xcc,0x0,0xe8,0x4,0xcc,0x0,0xe8,0x4,0xcc,0x0,0xb1,0x4,0xcc,0x0,0xb1,0x4,0xcc,0x0,0x93,0x4,0xcc, + 0x0,0xb1,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0xb1,0x4,0xcc,0x0,0x79,0x4,0xcc,0x0,0xca,0x4,0xcc,0x0,0xca,0x4,0xcc,0x0,0xca,0x4,0xcc,0x0,0xca, + 0x4,0xcc,0x0,0xca,0x4,0xcc,0x0,0xca,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x86,0x4,0xcc, + 0x0,0x86,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x54,0x4,0xcc,0x0,0x86,0x4,0xcc,0x0,0x46,0x4,0xcc,0x0,0xc0,0x4,0xcc,0x0,0xc0, + 0x4,0xcc,0x0,0x8b,0x4,0xcc,0x1,0x33,0x4,0xcc,0x1,0x33,0x4,0xcc,0x1,0x33,0x4,0xcc,0x1,0x33,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xb2,0x4,0xcc, + 0x0,0xb2,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0x75,0x4,0xcc,0x0,0x75,0x4,0xcc,0x0,0x75, + 0x4,0xcc,0x0,0x75,0x4,0xcc,0x0,0x75,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc, + 0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xbb,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0x7c,0x4,0xcc,0x0,0x3a, + 0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0x7b,0x4,0xcc,0x0,0x7b,0x4,0xcc, + 0x0,0x7b,0x4,0xcc,0x0,0x7b,0x4,0xcc,0x0,0x7b,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xb2,0x4,0xcc,0x0,0xb2,0x9,0x98,0x0,0xbb, + 0x9,0x98,0x0,0xbb,0x4,0xcc,0x0,0xfc,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x51,0x4,0xcc,0x0,0xda,0x4,0xcc,0x0,0x62,0x4,0xcc, + 0x0,0xbe,0x4,0xcc,0x0,0xdc,0x4,0xcc,0x0,0xc5,0x4,0xcc,0x0,0xb5,0x4,0xcc,0x0,0x91,0x4,0xcc,0x0,0xbc,0x4,0xcc,0x0,0xcb,0x4,0xcc,0x0,0xc7, + 0x4,0xcc,0x0,0xd2,0x4,0xcc,0x0,0xc2,0x4,0xcc,0x0,0x6f,0x4,0xcc,0x0,0x1,0x4,0xcc,0x0,0x1,0x4,0xcc,0x0,0x15,0x4,0xcc,0x1,0x3b,0x4,0xcc, + 0x1,0x20,0x4,0xcc,0x1,0x2e,0x4,0xcc,0x0,0xf2,0x4,0xcc,0x3,0xb,0x4,0xcc,0x2,0xa0,0x4,0xcc,0x3,0xb,0x4,0xcc,0x2,0xb4,0x4,0xcc,0xfe,0x39, + 0xe,0x64,0x3,0x5,0x4,0xcc,0x1,0x18,0x4,0xcc,0xfe,0x20,0xe,0x64,0x3,0x5,0x4,0xcc,0x0,0x6a,0x4,0xcc,0x0,0xc6,0x4,0xcc,0x1,0xdf,0x4,0xcc, + 0x1,0x7e,0x4,0xcc,0x1,0xdf,0x4,0xcc,0x1,0x74,0x4,0xcc,0x0,0x6d,0x4,0xcc,0x1,0xe9,0x4,0xcc,0x1,0xe9,0x4,0xcc,0x0,0x3c,0x4,0xcc,0x1,0xdf, + 0x4,0xcc,0x1,0x6,0x4,0xcc,0x1,0x6,0x4,0xcc,0x1,0x4,0x4,0xcc,0x1,0xe5,0x4,0xcc,0x1,0x88,0x4,0xcc,0x0,0xc6,0x4,0xcc,0x0,0x46,0x4,0xcc, + 0x0,0xb1,0x4,0xcc,0x0,0xee,0x4,0xcc,0x1,0x4a,0x4,0xcc,0x1,0x66,0x4,0xcc,0x1,0x29,0x4,0xcc,0x1,0x6b,0x4,0xcc,0x1,0xe,0x4,0xcc,0xfe,0x52, + 0x9,0x98,0xff,0xf0,0x9,0x98,0x1,0x1c,0x4,0xcc,0xff,0x1a,0x4,0xcc,0xff,0xe2,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x0,0x0, + 0x0,0x0,0x4,0xcc,0x0,0x99,0x4,0xcc,0x0,0x9d,0x4,0xcc,0x1,0x89,0x4,0xcc,0x1,0x8d,0x4,0xcc,0x0,0xc0,0x4,0xcc,0x0,0xb1,0x4,0xcc,0x0,0xc0, + 0x4,0xcc,0x1,0xa6,0x4,0xcc,0x1,0xb5,0x4,0xcc,0x1,0xb5,0x4,0xcc,0x0,0x0,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x6f,0x4,0xcc,0x0,0xae,0x4,0xcc, + 0x0,0x5a,0x4,0xcc,0x0,0x21,0x4,0xcc,0x0,0x32,0x4,0xcc,0x0,0xdc,0x4,0xcc,0xff,0xe2,0x4,0xcc,0x0,0x7d,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96, + 0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaf,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0x1c,0x4,0xcc,0x0,0x5,0x4,0xcc,0x0,0x7d,0x4,0xcc, + 0x0,0xaa,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xe7,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0x32,0x4,0xcc,0x0,0x32, + 0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xc3,0x4,0xcc,0x0,0x74,0x4,0xcc,0x0,0xa5,0x4,0xcc,0x0,0xcd,0x4,0xcc,0x2,0x1b,0x4,0xcc, + 0x2,0x1b,0x4,0xcc,0x0,0x32,0x4,0xcc,0x0,0x9d,0x4,0xcc,0x0,0x83,0x4,0xcc,0x0,0x24,0x4,0xcc,0x0,0x24,0x4,0xcc,0x0,0xc1,0x4,0xcc,0x0,0x3c, + 0x4,0xcc,0x0,0xf6,0x4,0xcc,0x0,0xe8,0x4,0xcc,0x1,0x22,0x4,0xcc,0x1,0x22,0x2,0x58,0x0,0x0,0x2,0x58,0x0,0x0,0x0,0x0,0xfd,0x9,0x0,0x0, + 0xfd,0x9,0x4,0xcc,0x1,0xa1,0x0,0xfa,0x1,0x1e,0x1,0x27,0x1,0x8e,0x0,0xec,0x1,0xa,0x1,0x5f,0x1,0xa,0x1,0x35,0x2,0x7,0x1,0x9,0x1,0x2d, + 0x1,0xe,0x1,0x9b,0x1,0x70,0x1,0xb,0x1,0x5f,0x1,0x27,0x1,0x35,0x2,0x7,0x1,0x39,0x1,0x3d,0x1,0x22,0x1,0x9b,0x1,0x70,0x1,0xe,0x0,0x0, + 0x0,0x78,0x0,0x78,0x0,0xc8,0x0,0xda,0x0,0xec,0x0,0xfe,0x1,0x10,0x1,0x22,0x1,0x34,0x1,0xc2,0x1,0xd4,0x1,0xe6,0x2,0x74,0x2,0xd6,0x3,0x34, + 0x3,0x46,0x3,0x58,0x4,0xc,0x4,0x1e,0x4,0x30,0x4,0x74,0x4,0xd6,0x4,0xe8,0x4,0xfa,0x5,0x46,0x5,0x58,0x5,0x6a,0x5,0x7c,0x5,0x8e,0x5,0xa0, + 0x5,0xb2,0x5,0xc4,0x5,0xd6,0x6,0x62,0x6,0xa4,0x7,0xe,0x7,0x20,0x7,0x32,0x7,0x3e,0x7,0x50,0x7,0x98,0x8,0x1c,0x8,0x2e,0x8,0x74,0x8,0xea, + 0x8,0xfc,0x9,0xe,0x9,0x20,0x9,0x32,0x9,0x44,0x9,0x56,0x9,0x68,0x9,0xee,0xa,0x0,0xa,0x4a,0xa,0x5c,0xa,0xb6,0xa,0xc2,0xa,0xf4,0xb,0x6, + 0xb,0x18,0xb,0x24,0xb,0x36,0xb,0x92,0xb,0xf0,0xc,0x4e,0xc,0x60,0xc,0x72,0xc,0x7e,0xc,0xe2,0xc,0xf4,0xd,0x3e,0xd,0x50,0xd,0x62,0xd,0x74, + 0xd,0x86,0xd,0x98,0xd,0xaa,0xd,0xbc,0xe,0x38,0xe,0x4a,0xe,0xaa,0xe,0xf4,0xf,0x5a,0xf,0xe0,0x10,0x34,0x10,0x46,0x10,0x58,0x10,0x64,0x10,0xde, + 0x10,0xf0,0x11,0x2,0x12,0x2,0x12,0x14,0x12,0x20,0x12,0x58,0x12,0xac,0x12,0xbe,0x13,0x48,0x13,0x54,0x13,0x94,0x13,0xa6,0x13,0xb8,0x13,0xca,0x13,0xdc, + 0x13,0xee,0x14,0x0,0x14,0x12,0x14,0x8e,0x14,0xa0,0x14,0xb2,0x14,0xf4,0x15,0x62,0x15,0x74,0x15,0x86,0x15,0x98,0x15,0xaa,0x16,0x0,0x16,0x44,0x16,0x56, + 0x16,0x68,0x16,0x7a,0x16,0x8c,0x16,0xce,0x16,0xe0,0x16,0xf2,0x17,0x4,0x17,0x94,0x17,0xa0,0x17,0xac,0x17,0xb8,0x17,0xc4,0x17,0xd0,0x17,0xdc,0x18,0x6e, + 0x18,0x7a,0x18,0x86,0x19,0x26,0x19,0x9e,0x19,0xf8,0x1a,0x4,0x1a,0x10,0x1a,0xc4,0x1a,0xd0,0x1a,0xdc,0x1b,0x54,0x1c,0xe,0x1c,0xc2,0x1d,0x74,0x1d,0xd4, + 0x1d,0xe0,0x1d,0xec,0x1d,0xf8,0x1e,0x4,0x1e,0x10,0x1e,0x1c,0x1e,0x28,0x1e,0x34,0x1e,0xb8,0x1f,0x10,0x1f,0xc0,0x1f,0xcc,0x1f,0xd8,0x20,0xb6,0x20,0xc2, + 0x21,0x12,0x21,0x92,0x21,0xa4,0x21,0xb0,0x21,0xf0,0x21,0xfc,0x22,0x8,0x22,0x14,0x22,0x20,0x22,0x2c,0x22,0x38,0x22,0xe0,0x22,0xec,0x23,0xa8,0x23,0xb4, + 0x23,0xc0,0x24,0xe,0x24,0x1a,0x24,0x68,0x24,0x74,0x24,0xb4,0x24,0xc6,0x24,0xd2,0x24,0xde,0x24,0xf0,0x25,0x5a,0x25,0xd8,0x26,0x36,0x26,0x42,0x26,0x4e, + 0x26,0x5a,0x26,0xdc,0x26,0xe8,0x27,0x30,0x27,0x3c,0x27,0x48,0x27,0x54,0x27,0x60,0x27,0x6c,0x27,0x78,0x27,0x84,0x28,0x14,0x28,0x20,0x28,0xa2,0x29,0x18, + 0x29,0x7c,0x29,0xf2,0x2a,0x70,0x2a,0x7c,0x2a,0x88,0x2a,0x94,0x2b,0xe,0x2b,0x1a,0x2b,0x26,0x2c,0x26,0x2c,0x32,0x2c,0x3e,0x2c,0xbc,0x2d,0x16,0x2d,0x8a, + 0x2d,0x9c,0x2e,0x7e,0x2e,0x8a,0x2e,0xe8,0x2e,0xf4,0x2f,0x0,0x2f,0xc,0x2f,0x18,0x2f,0x24,0x2f,0x30,0x2f,0x3c,0x2f,0xa6,0x2f,0xb2,0x2f,0xbe,0x30,0xc, + 0x30,0x6a,0x30,0x76,0x30,0x82,0x30,0x8e,0x30,0x9a,0x30,0xf0,0x31,0x44,0x31,0x50,0x31,0x5c,0x31,0x68,0x31,0x74,0x31,0xb6,0x31,0xc2,0x31,0xce,0x31,0xda, + 0x31,0xea,0x31,0xf6,0x32,0x40,0x32,0x76,0x32,0xa6,0x32,0xf6,0x33,0x3a,0x33,0x70,0x33,0xcc,0x34,0x16,0x34,0x6e,0x34,0xe4,0x35,0x2e,0x35,0xa0,0x36,0x6, + 0x36,0x42,0x36,0xbc,0x37,0x20,0x37,0x4e,0x37,0xfa,0x38,0xaa,0x39,0xbc,0x39,0xf0,0x3a,0x32,0x3a,0x86,0x3a,0xc0,0x3a,0xf0,0x3a,0xfa,0x3b,0x4,0x3b,0x3a, + 0x3b,0x88,0x3b,0xd6,0x3c,0x22,0x3c,0x6e,0x3c,0xbc,0x3d,0x28,0x3d,0x66,0x3d,0x76,0x3d,0xa0,0x3d,0xe2,0x3e,0x10,0x3e,0x64,0x3e,0xae,0x3e,0xf6,0x3f,0x92, + 0x3f,0xb8,0x40,0x28,0x40,0x98,0x40,0xa6,0x40,0xd4,0x41,0x1a,0x41,0x58,0x41,0x86,0x42,0x4a,0x43,0xc,0x43,0x8a,0x44,0x6,0x44,0x42,0x44,0x7e,0x44,0x9c, + 0x44,0xba,0x44,0xd8,0x44,0xf6,0x45,0x14,0x45,0x3e,0x45,0x68,0x45,0x92,0x45,0x9a,0x45,0x9a,0x45,0xa8,0x45,0xb6,0x45,0xee,0x46,0x26,0x46,0x34,0x46,0x42, + 0x46,0x50,0x46,0x7c,0x46,0xa6,0x46,0xd0,0x46,0xd0,0x47,0x40,0x47,0xca,0x48,0x82,0x49,0x1a,0x49,0x8e,0x49,0xec,0x4a,0x68,0x4b,0x12,0x4b,0x8e,0x4b,0xa6, + 0x4c,0x6,0x4c,0x66,0x4c,0x7e,0x4c,0xbc,0x4c,0xfe,0x4d,0x52,0x4d,0x96,0x4d,0xd4,0x4e,0x16,0x4e,0x4a,0x4e,0x68,0x4e,0xbc,0x4f,0x10,0x4f,0x62,0x50,0xc, + 0x50,0xea,0x51,0x32,0x51,0x94,0x51,0xc0,0x51,0xf6,0x52,0x40,0x52,0x7a,0x52,0xac,0x53,0x2,0x53,0xae,0x54,0x36,0x54,0x7e,0x55,0x22,0x55,0xc0,0x56,0x3e, + 0x56,0x9c,0x56,0xe2,0x57,0x2a,0x57,0x6c,0x58,0x1c,0x58,0x1c,0x58,0x1c,0x58,0x52,0x58,0x5a,0x58,0x8a,0x58,0xb6,0x58,0xfc,0x59,0x38,0x59,0x64,0x59,0xa4, + 0x59,0xde,0x59,0xe6,0x5a,0x20,0x5a,0x5a,0x5a,0x80,0x5a,0xaa,0x5a,0xf2,0x5b,0x1c,0x5b,0x24,0x5b,0x34,0x5b,0x9c,0x5c,0x8,0x5c,0x44,0x5c,0x82,0x5c,0xac, + 0x5c,0xd8,0x5d,0x24,0x5d,0x52,0x5d,0xa2,0x5d,0xea,0x5e,0x67,0x0,0x1,0x0,0x0,0x1,0x9b,0x0,0x6e,0x0,0xa,0x0,0x5e,0x0,0x4,0x0,0x2,0x0,0x26, + 0x0,0x36,0x0,0x77,0x0,0x0,0x0,0x9f,0xb,0xe2,0x0,0x3,0x0,0x1,0x0,0x0,0x0,0x1a,0x1,0x3e,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x26, + 0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x12,0x0,0x26,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x7,0x0,0x38,0x0,0x1,0x0,0x0, + 0x0,0x0,0x0,0x3,0x0,0x23,0x0,0x3f,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x12,0x0,0x62,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x5,0x0,0xe, + 0x0,0x74,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x18,0x0,0x82,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x12,0x0,0x9a,0x0,0x1,0x0,0x0, + 0x0,0x0,0x0,0x9,0x0,0x11,0x0,0xac,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xb,0x0,0x1b,0x0,0xbd,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x16, + 0x0,0xd8,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xd,0x11,0x3,0x0,0xee,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x1a,0x11,0xf1,0x0,0x3,0x0,0x1, + 0x4,0x9,0x0,0x0,0x0,0x4c,0x12,0xb,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x1,0x0,0x24,0x12,0x57,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x2,0x0,0xe, + 0x12,0x7b,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x3,0x0,0x46,0x12,0x89,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x4,0x0,0x30,0x12,0xcf,0x0,0x3,0x0,0x1, + 0x4,0x9,0x0,0x5,0x0,0x1c,0x12,0xff,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x6,0x0,0x30,0x13,0x1b,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x8,0x0,0x24, + 0x13,0x4b,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x9,0x0,0x22,0x13,0x6f,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0xb,0x0,0x36,0x13,0x91,0x0,0x3,0x0,0x1, + 0x4,0x9,0x0,0xc,0x0,0x2c,0x13,0xc7,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0xd,0x22,0x6,0x13,0xf3,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0xe,0x0,0x34, + 0x35,0xf9,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x35,0x20,0x51,0x75,0x6f,0x74,0x65,0x2d,0x55,0x6e,0x71, + 0x75,0x6f,0x74,0x65,0x20,0x41,0x70,0x70,0x73,0x2e,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x50,0x72,0x69,0x6d,0x65,0x20,0x43,0x6f,0x64,0x65,0x52,0x65, + 0x67,0x75,0x6c,0x61,0x72,0x33,0x2e,0x30,0x31,0x38,0x3b,0x51,0x55,0x51,0x41,0x3b,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x50,0x72,0x69,0x6d,0x65,0x43,0x6f, + 0x64,0x65,0x2d,0x52,0x65,0x67,0x75,0x6c,0x61,0x72,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x50,0x72,0x69,0x6d,0x65,0x20,0x43,0x6f,0x64,0x65,0x56,0x65, + 0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x2e,0x30,0x33,0x31,0x38,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x50,0x72,0x69,0x6d,0x65,0x43,0x6f,0x64,0x65,0x2d,0x52, + 0x65,0x67,0x75,0x6c,0x61,0x72,0x51,0x75,0x6f,0x74,0x65,0x2d,0x55,0x6e,0x71,0x75,0x6f,0x74,0x65,0x20,0x41,0x70,0x70,0x73,0x41,0x6c,0x61,0x6e,0x20,0x44, + 0x61,0x67,0x75,0x65,0x2d,0x47,0x72,0x65,0x65,0x6e,0x65,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x71,0x75,0x6f,0x74,0x65,0x75,0x6e,0x71,0x75,0x6f,0x74,0x65, + 0x61,0x70,0x70,0x73,0x2e,0x63,0x6f,0x6d,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x62,0x61,0x73,0x69,0x63,0x72,0x65,0x63,0x69,0x70,0x65,0x2e,0x63,0x6f,0x6d, + 0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x35,0xa,0x51,0x75,0x6f,0x74,0x65,0x2d,0x55,0x6e,0x71,0x75,0x6f, + 0x74,0x65,0x20,0x41,0x70,0x70,0x73,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x71,0x75,0x6f,0x74,0x65,0x75,0x6e,0x71,0x75,0x6f,0x74,0x65,0x61,0x70, + 0x70,0x73,0x2e,0x63,0x6f,0x6d,0x29,0xa,0x77,0x69,0x74,0x68,0x20,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,0x6d, + 0x65,0x20,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x50,0x72,0x69,0x6d,0x65,0x20,0x43,0x6f,0x64,0x65,0x2e,0xa,0xa,0x54,0x68,0x69,0x73,0x20,0x46,0x6f, + 0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x64,0x20,0x75,0x6e,0x64,0x65,0x72,0x20, + 0x74,0x68,0x65,0x20,0x53,0x49,0x4c,0x20,0x4f,0x70,0x65,0x6e,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4c,0x69,0x63,0x65,0x6e,0x73,0x65,0xa,0x56,0x65,0x72,0x73, + 0x69,0x6f,0x6e,0x20,0x31,0x2e,0x31,0x2e,0x20,0x54,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x69,0x73,0x20,0x63,0x6f,0x70,0x69,0x65, + 0x64,0x20,0x62,0x65,0x6c,0x6f,0x77,0xa,0x61,0x6e,0x64,0x20,0x69,0x73,0x20,0x61,0x6c,0x73,0x6f,0x20,0x61,0x76,0x61,0x69,0x6c,0x61,0x62,0x6c,0x65,0x20, + 0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x46,0x41,0x51,0x20,0x61,0x74,0x3a,0x20,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x2e, + 0x73,0x69,0x6c,0x2e,0x6f,0x72,0x67,0x2f,0x4f,0x46,0x4c,0xa,0xa,0xa,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0xa,0x53,0x49,0x4c,0x20,0x4f,0x50,0x45,0x4e,0x20,0x46,0x4f,0x4e,0x54,0x20,0x4c,0x49, + 0x43,0x45,0x4e,0x53,0x45,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x31,0x20,0x2d,0x20,0x32,0x36,0x20,0x46,0x65,0x62,0x72,0x75,0x61,0x72, + 0x79,0x20,0x32,0x30,0x30,0x37,0xa,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0xa,0xa,0x50,0x52,0x45,0x41,0x4d,0x42,0x4c,0x45,0xa,0x54,0x68,0x65,0x20,0x67,0x6f,0x61,0x6c,0x73,0x20,0x6f,0x66,0x20, + 0x74,0x68,0x65,0x20,0x4f,0x70,0x65,0x6e,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x28,0x4f,0x46,0x4c,0x29,0x20,0x61,0x72, + 0x65,0x20,0x74,0x6f,0x20,0x73,0x74,0x69,0x6d,0x75,0x6c,0x61,0x74,0x65,0x20,0x77,0x6f,0x72,0x6c,0x64,0x77,0x69,0x64,0x65,0x20,0x64,0x65,0x76,0x65,0x6c, + 0x6f,0x70,0x6d,0x65,0x6e,0x74,0x20,0x6f,0x66,0x20,0x63,0x6f,0x6c,0x6c,0x61,0x62,0x6f,0x72,0x61,0x74,0x69,0x76,0x65,0x20,0x66,0x6f,0x6e,0x74,0x20,0x70, + 0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0xa,0x74,0x6f,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x74,0x68,0x65,0x20,0x66,0x6f,0x6e,0x74,0x20,0x63,0x72, + 0x65,0x61,0x74,0x69,0x6f,0x6e,0x20,0x65,0x66,0x66,0x6f,0x72,0x74,0x73,0x20,0x6f,0x66,0x20,0x61,0x63,0x61,0x64,0x65,0x6d,0x69,0x63,0x20,0x61,0x6e,0x64, + 0x20,0x6c,0x69,0x6e,0x67,0x75,0x69,0x73,0x74,0x69,0x63,0x20,0x63,0x6f,0x6d,0x6d,0x75,0x6e,0x69,0x74,0x69,0x65,0x73,0xa,0x61,0x6e,0x64,0x20,0x74,0x6f, + 0x20,0x70,0x72,0x6f,0x76,0x69,0x64,0x65,0x20,0x61,0x20,0x66,0x72,0x65,0x65,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x6e,0x20,0x66,0x72,0x61,0x6d,0x65, + 0x77,0x6f,0x72,0x6b,0x20,0x69,0x6e,0x20,0x77,0x68,0x69,0x63,0x68,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x6d,0x61,0x79,0x20,0x62,0x65,0x20,0x73,0x68,0x61, + 0x72,0x65,0x64,0x20,0x61,0x6e,0x64,0x20,0x69,0x6d,0x70,0x72,0x6f,0x76,0x65,0x64,0x20,0x69,0x6e,0x20,0x70,0x61,0x72,0x74,0x6e,0x65,0x72,0x73,0x68,0x69, + 0x70,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x74,0x68,0x65,0x72,0x73,0x2e,0xa,0xa,0x54,0x68,0x65,0x20,0x4f,0x46,0x4c,0x20,0x61,0x6c,0x6c,0x6f,0x77,0x73, + 0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x64,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x74,0x6f,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64, + 0xa,0x73,0x74,0x75,0x64,0x69,0x65,0x64,0xa,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x61,0x6e,0x64,0x20,0x72,0x65,0x64,0x69,0x73,0x74,0x72,0x69, + 0x62,0x75,0x74,0x65,0x64,0x20,0x66,0x72,0x65,0x65,0x6c,0x79,0x20,0x61,0x73,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x73,0x20,0x74,0x68,0x65,0x79,0x20,0x61, + 0x72,0x65,0x20,0x6e,0x6f,0x74,0x20,0x73,0x6f,0x6c,0x64,0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x6d,0x73,0x65,0x6c,0x76,0x65,0x73,0x2e,0x20,0x54,0x68,0x65, + 0x20,0x66,0x6f,0x6e,0x74,0x73,0xa,0x69,0x6e,0x63,0x6c,0x75,0x64,0x69,0x6e,0x67,0x20,0x61,0x6e,0x79,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76, + 0x65,0x20,0x77,0x6f,0x72,0x6b,0x73,0xa,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x62,0x75,0x6e,0x64,0x6c,0x65,0x64,0xa,0x65,0x6d,0x62,0x65,0x64,0x64,0x65, + 0x64,0xa,0x72,0x65,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x61,0x6e,0x64,0x2f,0x6f,0x72,0x20,0x73,0x6f,0x6c,0x64,0x20,0x77,0x69, + 0x74,0x68,0x20,0x61,0x6e,0x79,0x20,0x73,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x70,0x72,0x6f,0x76,0x69,0x64,0x65,0x64,0x20,0x74,0x68,0x61,0x74,0x20, + 0x61,0x6e,0x79,0x20,0x72,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x6e,0x61,0x6d,0x65,0x73,0x20,0x61,0x72,0x65,0x20,0x6e,0x6f,0x74,0x20,0x75,0x73,0x65, + 0x64,0x20,0x62,0x79,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x20,0x77,0x6f,0x72,0x6b,0x73,0x2e,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x6e, + 0x74,0x73,0x20,0x61,0x6e,0x64,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x73,0xa,0x68,0x6f,0x77,0x65,0x76,0x65,0x72,0xa,0x63,0x61,0x6e, + 0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x64,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x61,0x6e,0x79,0x20,0x6f,0x74,0x68,0x65, + 0x72,0x20,0x74,0x79,0x70,0x65,0x20,0x6f,0x66,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x2e,0x20,0x54,0x68,0x65,0x20,0x72,0x65,0x71,0x75,0x69,0x72,0x65, + 0x6d,0x65,0x6e,0x74,0x20,0x66,0x6f,0x72,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72, + 0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x64,0x6f,0x65,0x73,0x20,0x6e,0x6f,0x74,0x20,0x61,0x70,0x70,0x6c,0x79,0x20,0x74, + 0x6f,0x20,0x61,0x6e,0x79,0x20,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x20,0x63,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x75,0x73,0x69,0x6e,0x67,0x20,0x74, + 0x68,0x65,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x6f,0x72,0x20,0x74,0x68,0x65,0x69,0x72,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x73,0x2e, + 0xa,0xa,0x44,0x45,0x46,0x49,0x4e,0x49,0x54,0x49,0x4f,0x4e,0x53,0xa,0x22,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x22,0x20, + 0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x73,0x65,0x74,0x20,0x6f,0x66,0x20,0x66,0x69,0x6c,0x65,0x73,0x20,0x72,0x65,0x6c, + 0x65,0x61,0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64,0x65,0x72,0x28, + 0x73,0x29,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x61,0x6e,0x64,0x20,0x63,0x6c,0x65,0x61, + 0x72,0x6c,0x79,0x20,0x6d,0x61,0x72,0x6b,0x65,0x64,0x20,0x61,0x73,0x20,0x73,0x75,0x63,0x68,0x2e,0x20,0x54,0x68,0x69,0x73,0x20,0x6d,0x61,0x79,0x20,0x69, + 0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x66,0x69,0x6c,0x65,0x73,0xa,0x62,0x75,0x69,0x6c,0x64,0x20,0x73,0x63,0x72,0x69, + 0x70,0x74,0x73,0x20,0x61,0x6e,0x64,0x20,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x2e,0xa,0xa,0x22,0x52,0x65,0x73,0x65,0x72, + 0x76,0x65,0x64,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,0x6d,0x65,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x6e, + 0x61,0x6d,0x65,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x20,0x61,0x73,0x20,0x73,0x75,0x63,0x68,0x20,0x61,0x66,0x74,0x65,0x72,0x20,0x74, + 0x68,0x65,0x20,0x63,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x73,0x74,0x61,0x74,0x65,0x6d,0x65,0x6e,0x74,0x28,0x73,0x29,0x2e,0xa,0xa,0x22,0x4f, + 0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x74,0x68,0x65, + 0x20,0x63,0x6f,0x6c,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x63, + 0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0x20,0x61,0x73,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64,0x65,0x72,0x28,0x73,0x29,0x2e,0xa,0xa,0x22,0x4d,0x6f,0x64,0x69,0x66, + 0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x64,0x65,0x72, + 0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x20,0x6d,0x61,0x64,0x65,0x20,0x62,0x79,0x20,0x61,0x64,0x64,0x69,0x6e,0x67,0x20,0x74,0x6f,0xa,0x64,0x65,0x6c,0x65, + 0x74,0x69,0x6e,0x67,0xa,0x6f,0x72,0x20,0x73,0x75,0x62,0x73,0x74,0x69,0x74,0x75,0x74,0x69,0x6e,0x67,0x20,0x2d,0x2d,0x20,0x69,0x6e,0x20,0x70,0x61,0x72, + 0x74,0x20,0x6f,0x72,0x20,0x69,0x6e,0x20,0x77,0x68,0x6f,0x6c,0x65,0x20,0x2d,0x2d,0x20,0x61,0x6e,0x79,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x63,0x6f, + 0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x4f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x56,0x65,0x72,0x73,0x69, + 0x6f,0x6e,0xa,0x62,0x79,0x20,0x63,0x68,0x61,0x6e,0x67,0x69,0x6e,0x67,0x20,0x66,0x6f,0x72,0x6d,0x61,0x74,0x73,0x20,0x6f,0x72,0x20,0x62,0x79,0x20,0x70, + 0x6f,0x72,0x74,0x69,0x6e,0x67,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x74,0x6f,0x20,0x61,0x20, + 0x6e,0x65,0x77,0x20,0x65,0x6e,0x76,0x69,0x72,0x6f,0x6e,0x6d,0x65,0x6e,0x74,0x2e,0xa,0xa,0x22,0x41,0x75,0x74,0x68,0x6f,0x72,0x22,0x20,0x72,0x65,0x66, + 0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x64,0x65,0x73,0x69,0x67,0x6e,0x65,0x72,0xa,0x65,0x6e,0x67,0x69,0x6e,0x65,0x65,0x72,0xa,0x70, + 0x72,0x6f,0x67,0x72,0x61,0x6d,0x6d,0x65,0x72,0xa,0x74,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c,0x20,0x77,0x72,0x69,0x74,0x65,0x72,0x20,0x6f,0x72,0x20, + 0x6f,0x74,0x68,0x65,0x72,0x20,0x70,0x65,0x72,0x73,0x6f,0x6e,0x20,0x77,0x68,0x6f,0x20,0x63,0x6f,0x6e,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x74, + 0x6f,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x2e,0xa,0xa,0x50,0x45,0x52,0x4d,0x49,0x53,0x53,0x49, + 0x4f,0x4e,0x20,0x26,0x20,0x43,0x4f,0x4e,0x44,0x49,0x54,0x49,0x4f,0x4e,0x53,0xa,0x50,0x65,0x72,0x6d,0x69,0x73,0x73,0x69,0x6f,0x6e,0x20,0x69,0x73,0x20, + 0x68,0x65,0x72,0x65,0x62,0x79,0x20,0x67,0x72,0x61,0x6e,0x74,0x65,0x64,0xa,0x66,0x72,0x65,0x65,0x20,0x6f,0x66,0x20,0x63,0x68,0x61,0x72,0x67,0x65,0xa, + 0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x70,0x65,0x72,0x73,0x6f,0x6e,0x20,0x6f,0x62,0x74,0x61,0x69,0x6e,0x69,0x6e,0x67,0x20,0x61,0x20,0x63,0x6f,0x70,0x79, + 0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x74,0x6f,0x20,0x75,0x73,0x65,0xa,0x73, + 0x74,0x75,0x64,0x79,0xa,0x63,0x6f,0x70,0x79,0xa,0x6d,0x65,0x72,0x67,0x65,0xa,0x65,0x6d,0x62,0x65,0x64,0xa,0x6d,0x6f,0x64,0x69,0x66,0x79,0xa,0x72, + 0x65,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0xa,0x61,0x6e,0x64,0x20,0x73,0x65,0x6c,0x6c,0x20,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20, + 0x61,0x6e,0x64,0x20,0x75,0x6e,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x63,0x6f,0x70,0x69,0x65,0x73,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46, + 0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x73,0x75,0x62,0x6a,0x65,0x63,0x74,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x66,0x6f, + 0x6c,0x6c,0x6f,0x77,0x69,0x6e,0x67,0x20,0x63,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x73,0x3a,0xa,0xa,0x31,0x29,0x20,0x4e,0x65,0x69,0x74,0x68,0x65, + 0x72,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x6e,0x6f,0x72,0x20,0x61,0x6e,0x79,0x20,0x6f,0x66, + 0x20,0x69,0x74,0x73,0x20,0x69,0x6e,0x64,0x69,0x76,0x69,0x64,0x75,0x61,0x6c,0x20,0x63,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0xa,0x69,0x6e,0x20, + 0x4f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x6f,0x72,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x73,0xa, + 0x6d,0x61,0x79,0x20,0x62,0x65,0x20,0x73,0x6f,0x6c,0x64,0x20,0x62,0x79,0x20,0x69,0x74,0x73,0x65,0x6c,0x66,0x2e,0xa,0xa,0x32,0x29,0x20,0x4f,0x72,0x69, + 0x67,0x69,0x6e,0x61,0x6c,0x20,0x6f,0x72,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x73,0x20,0x6f,0x66,0x20, + 0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x6d,0x61,0x79,0x20,0x62,0x65,0x20,0x62,0x75,0x6e,0x64,0x6c, + 0x65,0x64,0xa,0x72,0x65,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x61,0x6e,0x64,0x2f,0x6f,0x72,0x20,0x73,0x6f,0x6c,0x64,0x20,0x77, + 0x69,0x74,0x68,0x20,0x61,0x6e,0x79,0x20,0x73,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x70,0x72,0x6f,0x76,0x69,0x64,0x65,0x64,0x20,0x74,0x68,0x61,0x74, + 0x20,0x65,0x61,0x63,0x68,0x20,0x63,0x6f,0x70,0x79,0x20,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x73,0x20,0x74,0x68,0x65,0x20,0x61,0x62,0x6f,0x76,0x65,0x20, + 0x63,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x6e,0x6f,0x74,0x69,0x63,0x65,0x20,0x61,0x6e,0x64,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65, + 0x6e,0x73,0x65,0x2e,0x20,0x54,0x68,0x65,0x73,0x65,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x64,0x20,0x65,0x69,0x74, + 0x68,0x65,0x72,0x20,0x61,0x73,0x20,0x73,0x74,0x61,0x6e,0x64,0x2d,0x61,0x6c,0x6f,0x6e,0x65,0x20,0x74,0x65,0x78,0x74,0x20,0x66,0x69,0x6c,0x65,0x73,0xa, + 0x68,0x75,0x6d,0x61,0x6e,0x2d,0x72,0x65,0x61,0x64,0x61,0x62,0x6c,0x65,0x20,0x68,0x65,0x61,0x64,0x65,0x72,0x73,0x20,0x6f,0x72,0x20,0x69,0x6e,0x20,0x74, + 0x68,0x65,0x20,0x61,0x70,0x70,0x72,0x6f,0x70,0x72,0x69,0x61,0x74,0x65,0x20,0x6d,0x61,0x63,0x68,0x69,0x6e,0x65,0x2d,0x72,0x65,0x61,0x64,0x61,0x62,0x6c, + 0x65,0x20,0x6d,0x65,0x74,0x61,0x64,0x61,0x74,0x61,0x20,0x66,0x69,0x65,0x6c,0x64,0x73,0x20,0x77,0x69,0x74,0x68,0x69,0x6e,0x20,0x74,0x65,0x78,0x74,0x20, + 0x6f,0x72,0x20,0x62,0x69,0x6e,0x61,0x72,0x79,0x20,0x66,0x69,0x6c,0x65,0x73,0x20,0x61,0x73,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x73,0x20,0x74,0x68,0x6f, + 0x73,0x65,0x20,0x66,0x69,0x65,0x6c,0x64,0x73,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x65,0x61,0x73,0x69,0x6c,0x79,0x20,0x76,0x69,0x65,0x77,0x65,0x64, + 0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x75,0x73,0x65,0x72,0x2e,0xa,0xa,0x33,0x29,0x20,0x4e,0x6f,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20, + 0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x6d, + 0x61,0x79,0x20,0x75,0x73,0x65,0x20,0x74,0x68,0x65,0x20,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,0x6d,0x65,0x28, + 0x73,0x29,0x20,0x75,0x6e,0x6c,0x65,0x73,0x73,0x20,0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x70,0x65,0x72, + 0x6d,0x69,0x73,0x73,0x69,0x6f,0x6e,0x20,0x69,0x73,0x20,0x67,0x72,0x61,0x6e,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x63,0x6f,0x72,0x72, + 0x65,0x73,0x70,0x6f,0x6e,0x64,0x69,0x6e,0x67,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64,0x65,0x72,0x2e,0x20,0x54,0x68, + 0x69,0x73,0x20,0x72,0x65,0x73,0x74,0x72,0x69,0x63,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x6e,0x6c,0x79,0x20,0x61,0x70,0x70,0x6c,0x69,0x65,0x73,0x20,0x74,0x6f, + 0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x69,0x6d,0x61,0x72,0x79,0x20,0x66,0x6f,0x6e,0x74,0x20,0x6e,0x61,0x6d,0x65,0x20,0x61,0x73,0x20,0x70,0x72,0x65,0x73, + 0x65,0x6e,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x75,0x73,0x65,0x72,0x73,0x2e,0xa,0xa,0x34,0x29,0x20,0x54,0x68,0x65,0x20,0x6e,0x61, + 0x6d,0x65,0x28,0x73,0x29,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64,0x65,0x72,0x28, + 0x73,0x29,0x20,0x6f,0x72,0x20,0x74,0x68,0x65,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x28,0x73,0x29,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e, + 0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x73,0x68,0x61,0x6c,0x6c,0x20,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x74, + 0x6f,0x20,0x70,0x72,0x6f,0x6d,0x6f,0x74,0x65,0xa,0x65,0x6e,0x64,0x6f,0x72,0x73,0x65,0x20,0x6f,0x72,0x20,0x61,0x64,0x76,0x65,0x72,0x74,0x69,0x73,0x65, + 0x20,0x61,0x6e,0x79,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0xa,0x65,0x78,0x63,0x65,0x70,0x74,0x20,0x74, + 0x6f,0x20,0x61,0x63,0x6b,0x6e,0x6f,0x77,0x6c,0x65,0x64,0x67,0x65,0x20,0x74,0x68,0x65,0x20,0x63,0x6f,0x6e,0x74,0x72,0x69,0x62,0x75,0x74,0x69,0x6f,0x6e, + 0x28,0x73,0x29,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64,0x65,0x72,0x28,0x73,0x29, + 0x20,0x61,0x6e,0x64,0x20,0x74,0x68,0x65,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x28,0x73,0x29,0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x68,0x65, + 0x69,0x72,0x20,0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x70,0x65,0x72,0x6d,0x69,0x73,0x73,0x69,0x6f,0x6e, + 0x2e,0xa,0xa,0x35,0x29,0x20,0x54,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x6d,0x6f,0x64,0x69,0x66,0x69, + 0x65,0x64,0x20,0x6f,0x72,0x20,0x75,0x6e,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0xa,0x69,0x6e,0x20,0x70,0x61,0x72,0x74,0x20,0x6f,0x72,0x20,0x69,0x6e, + 0x20,0x77,0x68,0x6f,0x6c,0x65,0xa,0x6d,0x75,0x73,0x74,0x20,0x62,0x65,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x65,0x6e,0x74, + 0x69,0x72,0x65,0x6c,0x79,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0xa,0x61,0x6e,0x64,0x20,0x6d, + 0x75,0x73,0x74,0x20,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x61, + 0x6e,0x79,0x20,0x6f,0x74,0x68,0x65,0x72,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x2e,0x20,0x54,0x68,0x65,0x20,0x72,0x65,0x71,0x75,0x69,0x72,0x65,0x6d, + 0x65,0x6e,0x74,0x20,0x66,0x6f,0x72,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20,0x75,0x6e,0x64,0x65,0x72,0x20, + 0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x64,0x6f,0x65,0x73,0x20,0x6e,0x6f,0x74,0x20,0x61,0x70,0x70,0x6c,0x79,0x20,0x74,0x6f, + 0x20,0x61,0x6e,0x79,0x20,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x20,0x63,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x75,0x73,0x69,0x6e,0x67,0x20,0x74,0x68, + 0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x2e,0xa,0xa,0x54,0x45,0x52,0x4d,0x49,0x4e,0x41,0x54,0x49,0x4f,0x4e,0xa, + 0x54,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x62,0x65,0x63,0x6f,0x6d,0x65,0x73,0x20,0x6e,0x75,0x6c,0x6c,0x20,0x61,0x6e,0x64,0x20, + 0x76,0x6f,0x69,0x64,0x20,0x69,0x66,0x20,0x61,0x6e,0x79,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x61,0x62,0x6f,0x76,0x65,0x20,0x63,0x6f,0x6e,0x64,0x69, + 0x74,0x69,0x6f,0x6e,0x73,0x20,0x61,0x72,0x65,0x20,0x6e,0x6f,0x74,0x20,0x6d,0x65,0x74,0x2e,0xa,0xa,0x44,0x49,0x53,0x43,0x4c,0x41,0x49,0x4d,0x45,0x52, + 0xa,0x54,0x48,0x45,0x20,0x46,0x4f,0x4e,0x54,0x20,0x53,0x4f,0x46,0x54,0x57,0x41,0x52,0x45,0x20,0x49,0x53,0x20,0x50,0x52,0x4f,0x56,0x49,0x44,0x45,0x44, + 0x20,0x22,0x41,0x53,0x20,0x49,0x53,0x22,0xa,0x57,0x49,0x54,0x48,0x4f,0x55,0x54,0x20,0x57,0x41,0x52,0x52,0x41,0x4e,0x54,0x59,0x20,0x4f,0x46,0x20,0x41, + 0x4e,0x59,0x20,0x4b,0x49,0x4e,0x44,0xa,0x45,0x58,0x50,0x52,0x45,0x53,0x53,0x20,0x4f,0x52,0x20,0x49,0x4d,0x50,0x4c,0x49,0x45,0x44,0xa,0x49,0x4e,0x43, + 0x4c,0x55,0x44,0x49,0x4e,0x47,0x20,0x42,0x55,0x54,0x20,0x4e,0x4f,0x54,0x20,0x4c,0x49,0x4d,0x49,0x54,0x45,0x44,0x20,0x54,0x4f,0x20,0x41,0x4e,0x59,0x20, + 0x57,0x41,0x52,0x52,0x41,0x4e,0x54,0x49,0x45,0x53,0x20,0x4f,0x46,0x20,0x4d,0x45,0x52,0x43,0x48,0x41,0x4e,0x54,0x41,0x42,0x49,0x4c,0x49,0x54,0x59,0xa, + 0x46,0x49,0x54,0x4e,0x45,0x53,0x53,0x20,0x46,0x4f,0x52,0x20,0x41,0x20,0x50,0x41,0x52,0x54,0x49,0x43,0x55,0x4c,0x41,0x52,0x20,0x50,0x55,0x52,0x50,0x4f, + 0x53,0x45,0x20,0x41,0x4e,0x44,0x20,0x4e,0x4f,0x4e,0x49,0x4e,0x46,0x52,0x49,0x4e,0x47,0x45,0x4d,0x45,0x4e,0x54,0x20,0x4f,0x46,0x20,0x43,0x4f,0x50,0x59, + 0x52,0x49,0x47,0x48,0x54,0xa,0x50,0x41,0x54,0x45,0x4e,0x54,0xa,0x54,0x52,0x41,0x44,0x45,0x4d,0x41,0x52,0x4b,0xa,0x4f,0x52,0x20,0x4f,0x54,0x48,0x45, + 0x52,0x20,0x52,0x49,0x47,0x48,0x54,0x2e,0x20,0x49,0x4e,0x20,0x4e,0x4f,0x20,0x45,0x56,0x45,0x4e,0x54,0x20,0x53,0x48,0x41,0x4c,0x4c,0x20,0x54,0x48,0x45, + 0x20,0x43,0x4f,0x50,0x59,0x52,0x49,0x47,0x48,0x54,0x20,0x48,0x4f,0x4c,0x44,0x45,0x52,0x20,0x42,0x45,0x20,0x4c,0x49,0x41,0x42,0x4c,0x45,0x20,0x46,0x4f, + 0x52,0x20,0x41,0x4e,0x59,0x20,0x43,0x4c,0x41,0x49,0x4d,0xa,0x44,0x41,0x4d,0x41,0x47,0x45,0x53,0x20,0x4f,0x52,0x20,0x4f,0x54,0x48,0x45,0x52,0x20,0x4c, + 0x49,0x41,0x42,0x49,0x4c,0x49,0x54,0x59,0xa,0x49,0x4e,0x43,0x4c,0x55,0x44,0x49,0x4e,0x47,0x20,0x41,0x4e,0x59,0x20,0x47,0x45,0x4e,0x45,0x52,0x41,0x4c, + 0xa,0x53,0x50,0x45,0x43,0x49,0x41,0x4c,0xa,0x49,0x4e,0x44,0x49,0x52,0x45,0x43,0x54,0xa,0x49,0x4e,0x43,0x49,0x44,0x45,0x4e,0x54,0x41,0x4c,0xa,0x4f, + 0x52,0x20,0x43,0x4f,0x4e,0x53,0x45,0x51,0x55,0x45,0x4e,0x54,0x49,0x41,0x4c,0x20,0x44,0x41,0x4d,0x41,0x47,0x45,0x53,0xa,0x57,0x48,0x45,0x54,0x48,0x45, + 0x52,0x20,0x49,0x4e,0x20,0x41,0x4e,0x20,0x41,0x43,0x54,0x49,0x4f,0x4e,0x20,0x4f,0x46,0x20,0x43,0x4f,0x4e,0x54,0x52,0x41,0x43,0x54,0xa,0x54,0x4f,0x52, + 0x54,0x20,0x4f,0x52,0x20,0x4f,0x54,0x48,0x45,0x52,0x57,0x49,0x53,0x45,0xa,0x41,0x52,0x49,0x53,0x49,0x4e,0x47,0x20,0x46,0x52,0x4f,0x4d,0xa,0x4f,0x55, + 0x54,0x20,0x4f,0x46,0x20,0x54,0x48,0x45,0x20,0x55,0x53,0x45,0x20,0x4f,0x52,0x20,0x49,0x4e,0x41,0x42,0x49,0x4c,0x49,0x54,0x59,0x20,0x54,0x4f,0x20,0x55, + 0x53,0x45,0x20,0x54,0x48,0x45,0x20,0x46,0x4f,0x4e,0x54,0x20,0x53,0x4f,0x46,0x54,0x57,0x41,0x52,0x45,0x20,0x4f,0x52,0x20,0x46,0x52,0x4f,0x4d,0x20,0x4f, + 0x54,0x48,0x45,0x52,0x20,0x44,0x45,0x41,0x4c,0x49,0x4e,0x47,0x53,0x20,0x49,0x4e,0x20,0x54,0x48,0x45,0x20,0x46,0x4f,0x4e,0x54,0x20,0x53,0x4f,0x46,0x54, + 0x57,0x41,0x52,0x45,0x2e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x2e,0x73,0x69,0x6c,0x2e,0x6f,0x72,0x67,0x2f,0x4f,0x46, + 0x4c,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x28,0x0,0x63,0x0,0x29,0x0,0x20,0x0, + 0x32,0x0,0x30,0x0,0x31,0x0,0x35,0x0,0x20,0x0,0x51,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x2d,0x0,0x55,0x0,0x6e,0x0,0x71,0x0,0x75,0x0, + 0x6f,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x41,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x2e,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0, + 0x72,0x0,0x20,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0,0x52,0x0,0x65,0x0,0x67,0x0, + 0x75,0x0,0x6c,0x0,0x61,0x0,0x72,0x0,0x33,0x0,0x2e,0x0,0x30,0x0,0x31,0x0,0x38,0x0,0x3b,0x0,0x51,0x0,0x55,0x0,0x51,0x0,0x41,0x0,0x3b,0x0, + 0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x43,0x0,0x6f,0x0,0x64,0x0, + 0x65,0x0,0x2d,0x0,0x52,0x0,0x65,0x0,0x67,0x0,0x75,0x0,0x6c,0x0,0x61,0x0,0x72,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0, + 0x72,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0,0x2d,0x0,0x52,0x0,0x65,0x0,0x67,0x0,0x75,0x0, + 0x6c,0x0,0x61,0x0,0x72,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x33,0x0,0x2e,0x0,0x30,0x0,0x33,0x0, + 0x31,0x0,0x38,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x43,0x0, + 0x6f,0x0,0x64,0x0,0x65,0x0,0x2d,0x0,0x52,0x0,0x65,0x0,0x67,0x0,0x75,0x0,0x6c,0x0,0x61,0x0,0x72,0x0,0x51,0x0,0x75,0x0,0x6f,0x0,0x74,0x0, + 0x65,0x0,0x2d,0x0,0x55,0x0,0x6e,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x41,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x41,0x0, + 0x6c,0x0,0x61,0x0,0x6e,0x0,0x20,0x0,0x44,0x0,0x61,0x0,0x67,0x0,0x75,0x0,0x65,0x0,0x2d,0x0,0x47,0x0,0x72,0x0,0x65,0x0,0x65,0x0,0x6e,0x0, + 0x65,0x0,0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x75,0x0,0x6e,0x0, + 0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x68,0x0,0x74,0x0, + 0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x62,0x0,0x61,0x0,0x73,0x0,0x69,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x63,0x0,0x69,0x0,0x70,0x0, + 0x65,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0, + 0x28,0x0,0x63,0x0,0x29,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x31,0x0,0x35,0x0,0xa,0x0,0x51,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x2d,0x0, + 0x55,0x0,0x6e,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x41,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x20,0x0,0x28,0x0,0x68,0x0, + 0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x75,0x0,0x6e,0x0,0x71,0x0,0x75,0x0, + 0x6f,0x0,0x74,0x0,0x65,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x29,0x0,0xa,0x0,0x77,0x0,0x69,0x0, + 0x74,0x0,0x68,0x0,0x20,0x0,0x52,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0, + 0x74,0x0,0x20,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0,0x20,0x0, + 0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x54,0x0,0x68,0x0, + 0x69,0x0,0x73,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0, + 0x65,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0, + 0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x53,0x0,0x49,0x0,0x4c,0x0,0x20,0x0,0x4f,0x0,0x70,0x0, + 0x65,0x0,0x6e,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x4c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0, + 0xa,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x31,0x0,0x2e,0x0,0x31,0x0,0x2e,0x0,0x20,0x0,0x54,0x0, + 0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0, + 0x63,0x0,0x6f,0x0,0x70,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x6c,0x0,0x6f,0x0,0x77,0x0,0xa,0x0,0x61,0x0,0x6e,0x0, + 0x64,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x6c,0x0,0x73,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x76,0x0,0x61,0x0,0x69,0x0,0x6c,0x0, + 0x61,0x0,0x62,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x20,0x0,0x46,0x0,0x41,0x0,0x51,0x0, + 0x20,0x0,0x61,0x0,0x74,0x0,0x3a,0x0,0x20,0x0,0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x73,0x0,0x63,0x0,0x72,0x0, + 0x69,0x0,0x70,0x0,0x74,0x0,0x73,0x0,0x2e,0x0,0x73,0x0,0x69,0x0,0x6c,0x0,0x2e,0x0,0x6f,0x0,0x72,0x0,0x67,0x0,0x2f,0x0,0x4f,0x0,0x46,0x0, + 0x4c,0x0,0xa,0x0,0xa,0x0,0xa,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0xa,0x0,0x53,0x0,0x49,0x0,0x4c,0x0,0x20,0x0,0x4f,0x0,0x50,0x0,0x45,0x0,0x4e,0x0,0x20,0x0,0x46,0x0,0x4f,0x0, + 0x4e,0x0,0x54,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x43,0x0,0x45,0x0,0x4e,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0, + 0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x31,0x0,0x2e,0x0,0x31,0x0,0x20,0x0,0x2d,0x0,0x20,0x0,0x32,0x0,0x36,0x0,0x20,0x0,0x46,0x0,0x65,0x0, + 0x62,0x0,0x72,0x0,0x75,0x0,0x61,0x0,0x72,0x0,0x79,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x30,0x0,0x37,0x0,0xa,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0xa,0x0,0xa,0x0,0x50,0x0,0x52,0x0, + 0x45,0x0,0x41,0x0,0x4d,0x0,0x42,0x0,0x4c,0x0,0x45,0x0,0xa,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x67,0x0,0x6f,0x0,0x61,0x0,0x6c,0x0, + 0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x4f,0x0,0x70,0x0,0x65,0x0,0x6e,0x0,0x20,0x0,0x46,0x0, + 0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x4c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x28,0x0,0x4f,0x0,0x46,0x0, + 0x4c,0x0,0x29,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x73,0x0,0x74,0x0,0x69,0x0,0x6d,0x0,0x75,0x0, + 0x6c,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6c,0x0,0x64,0x0,0x77,0x0,0x69,0x0,0x64,0x0,0x65,0x0,0x20,0x0, + 0x64,0x0,0x65,0x0,0x76,0x0,0x65,0x0,0x6c,0x0,0x6f,0x0,0x70,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0, + 0x63,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x61,0x0,0x62,0x0,0x6f,0x0,0x72,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x66,0x0, + 0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x6a,0x0,0x65,0x0,0x63,0x0,0x74,0x0,0x73,0x0,0xa,0x0,0x74,0x0,0x6f,0x0, + 0x20,0x0,0x73,0x0,0x75,0x0,0x70,0x0,0x70,0x0,0x6f,0x0,0x72,0x0,0x74,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0, + 0x6e,0x0,0x74,0x0,0x20,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x65,0x0,0x66,0x0,0x66,0x0, + 0x6f,0x0,0x72,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x61,0x0,0x63,0x0,0x61,0x0,0x64,0x0,0x65,0x0,0x6d,0x0,0x69,0x0, + 0x63,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x75,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x69,0x0, + 0x63,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x6d,0x0,0x75,0x0,0x6e,0x0,0x69,0x0,0x74,0x0,0x69,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x61,0x0, + 0x6e,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x69,0x0,0x64,0x0,0x65,0x0,0x20,0x0,0x61,0x0, + 0x20,0x0,0x66,0x0,0x72,0x0,0x65,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x6f,0x0,0x70,0x0,0x65,0x0,0x6e,0x0,0x20,0x0, + 0x66,0x0,0x72,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6b,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x77,0x0,0x68,0x0, + 0x69,0x0,0x63,0x0,0x68,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x62,0x0, + 0x65,0x0,0x20,0x0,0x73,0x0,0x68,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x69,0x0,0x6d,0x0, + 0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x61,0x0,0x72,0x0,0x74,0x0,0x6e,0x0, + 0x65,0x0,0x72,0x0,0x73,0x0,0x68,0x0,0x69,0x0,0x70,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0, + 0x65,0x0,0x72,0x0,0x73,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x4c,0x0,0x20,0x0,0x61,0x0, + 0x6c,0x0,0x6c,0x0,0x6f,0x0,0x77,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0, + 0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x62,0x0,0x65,0x0, + 0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x73,0x0,0x74,0x0,0x75,0x0,0x64,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x6d,0x0, + 0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x64,0x0, + 0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x66,0x0,0x72,0x0,0x65,0x0,0x65,0x0, + 0x6c,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x6f,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x73,0x0,0x6f,0x0,0x6c,0x0, + 0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x6d,0x0,0x73,0x0,0x65,0x0,0x6c,0x0,0x76,0x0,0x65,0x0,0x73,0x0, + 0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0xa,0x0,0x69,0x0,0x6e,0x0,0x63,0x0, + 0x6c,0x0,0x75,0x0,0x64,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0, + 0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6b,0x0,0x73,0x0,0xa,0x0,0x63,0x0,0x61,0x0, + 0x6e,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x62,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x6c,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x65,0x0,0x6d,0x0, + 0x62,0x0,0x65,0x0,0x64,0x0,0x64,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0, + 0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x2f,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x73,0x0,0x6f,0x0, + 0x6c,0x0,0x64,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x73,0x0,0x6f,0x0,0x66,0x0, + 0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x69,0x0,0x64,0x0,0x65,0x0,0x64,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x61,0x0,0x74,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0, + 0x65,0x0,0x64,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0, + 0x74,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0,0x76,0x0, + 0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6b,0x0,0x73,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0, + 0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0, + 0x69,0x0,0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x68,0x0,0x6f,0x0,0x77,0x0,0x65,0x0,0x76,0x0,0x65,0x0, + 0x72,0x0,0xa,0x0,0x63,0x0,0x61,0x0,0x6e,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6c,0x0, + 0x65,0x0,0x61,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0, + 0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x79,0x0,0x70,0x0,0x65,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0, + 0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x72,0x0,0x65,0x0, + 0x71,0x0,0x75,0x0,0x69,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x66,0x0, + 0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x20,0x0, + 0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0, + 0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x61,0x0,0x70,0x0, + 0x70,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x63,0x0,0x75,0x0, + 0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x73,0x0, + 0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6f,0x0, + 0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x69,0x0,0x72,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0,0x76,0x0,0x61,0x0,0x74,0x0, + 0x69,0x0,0x76,0x0,0x65,0x0,0x73,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x44,0x0,0x45,0x0,0x46,0x0,0x49,0x0,0x4e,0x0,0x49,0x0,0x54,0x0,0x49,0x0, + 0x4f,0x0,0x4e,0x0,0x53,0x0,0xa,0x0,0x22,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0, + 0x61,0x0,0x72,0x0,0x65,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x65,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x6c,0x0,0x65,0x0, + 0x73,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6c,0x0,0x65,0x0,0x61,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0, + 0x6c,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0, + 0x20,0x0,0x63,0x0,0x6c,0x0,0x65,0x0,0x61,0x0,0x72,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x72,0x0,0x6b,0x0,0x65,0x0,0x64,0x0, + 0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x75,0x0,0x63,0x0,0x68,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0, + 0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x63,0x0,0x6c,0x0,0x75,0x0,0x64,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x6f,0x0,0x75,0x0, + 0x72,0x0,0x63,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x62,0x0,0x75,0x0,0x69,0x0,0x6c,0x0,0x64,0x0, + 0x20,0x0,0x73,0x0,0x63,0x0,0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x64,0x0,0x6f,0x0, + 0x63,0x0,0x75,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x22,0x0, + 0x52,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x4e,0x0, + 0x61,0x0,0x6d,0x0,0x65,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0, + 0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x70,0x0,0x65,0x0,0x63,0x0,0x69,0x0, + 0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x75,0x0,0x63,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x66,0x0, + 0x74,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0, + 0x68,0x0,0x74,0x0,0x20,0x0,0x73,0x0,0x74,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x28,0x0,0x73,0x0,0x29,0x0, + 0x2e,0x0,0xa,0x0,0xa,0x0,0x22,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x56,0x0,0x65,0x0, + 0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0, + 0x6f,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x65,0x0,0x63,0x0,0x74,0x0,0x69,0x0,0x6f,0x0, + 0x6e,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0, + 0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0, + 0x61,0x0,0x73,0x0,0x20,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0, + 0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0, + 0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0,0x6c,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x22,0x0, + 0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0, + 0x6e,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0, + 0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0,0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0, + 0x64,0x0,0x65,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x64,0x0,0x64,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x6f,0x0, + 0xa,0x0,0x64,0x0,0x65,0x0,0x6c,0x0,0x65,0x0,0x74,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0xa,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x73,0x0,0x75,0x0, + 0x62,0x0,0x73,0x0,0x74,0x0,0x69,0x0,0x74,0x0,0x75,0x0,0x74,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x2d,0x0,0x2d,0x0,0x20,0x0,0x69,0x0, + 0x6e,0x0,0x20,0x0,0x70,0x0,0x61,0x0,0x72,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x77,0x0,0x68,0x0, + 0x6f,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x2d,0x0,0x2d,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6f,0x0, + 0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0, + 0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0xa,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x63,0x0,0x68,0x0,0x61,0x0,0x6e,0x0, + 0x67,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x72,0x0,0x6d,0x0,0x61,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x72,0x0, + 0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x70,0x0,0x6f,0x0,0x72,0x0,0x74,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0, + 0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0, + 0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x20,0x0,0x6e,0x0,0x65,0x0,0x77,0x0,0x20,0x0,0x65,0x0,0x6e,0x0,0x76,0x0,0x69,0x0,0x72,0x0,0x6f,0x0, + 0x6e,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x22,0x0,0x41,0x0,0x75,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x72,0x0, + 0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0, + 0x20,0x0,0x64,0x0,0x65,0x0,0x73,0x0,0x69,0x0,0x67,0x0,0x6e,0x0,0x65,0x0,0x72,0x0,0xa,0x0,0x65,0x0,0x6e,0x0,0x67,0x0,0x69,0x0,0x6e,0x0, + 0x65,0x0,0x65,0x0,0x72,0x0,0xa,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x67,0x0,0x72,0x0,0x61,0x0,0x6d,0x0,0x6d,0x0,0x65,0x0,0x72,0x0,0xa,0x0, + 0x74,0x0,0x65,0x0,0x63,0x0,0x68,0x0,0x6e,0x0,0x69,0x0,0x63,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x77,0x0,0x72,0x0,0x69,0x0,0x74,0x0,0x65,0x0, + 0x72,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0,0x73,0x0, + 0x6f,0x0,0x6e,0x0,0x20,0x0,0x77,0x0,0x68,0x0,0x6f,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0, + 0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0, + 0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x50,0x0,0x45,0x0,0x52,0x0, + 0x4d,0x0,0x49,0x0,0x53,0x0,0x53,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x20,0x0,0x26,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x4e,0x0,0x44,0x0,0x49,0x0, + 0x54,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x53,0x0,0xa,0x0,0x50,0x0,0x65,0x0,0x72,0x0,0x6d,0x0,0x69,0x0,0x73,0x0,0x73,0x0,0x69,0x0,0x6f,0x0, + 0x6e,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x65,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x67,0x0,0x72,0x0,0x61,0x0, + 0x6e,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x66,0x0,0x72,0x0,0x65,0x0,0x65,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x63,0x0,0x68,0x0, + 0x61,0x0,0x72,0x0,0x67,0x0,0x65,0x0,0xa,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0, + 0x73,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0,0x62,0x0,0x74,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x61,0x0, + 0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0, + 0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0,0x74,0x0,0x6f,0x0,0x20,0x0, + 0x75,0x0,0x73,0x0,0x65,0x0,0xa,0x0,0x73,0x0,0x74,0x0,0x75,0x0,0x64,0x0,0x79,0x0,0xa,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0xa,0x0, + 0x6d,0x0,0x65,0x0,0x72,0x0,0x67,0x0,0x65,0x0,0xa,0x0,0x65,0x0,0x6d,0x0,0x62,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x6d,0x0,0x6f,0x0,0x64,0x0, + 0x69,0x0,0x66,0x0,0x79,0x0,0xa,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0, + 0x65,0x0,0xa,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x73,0x0,0x65,0x0,0x6c,0x0,0x6c,0x0,0x20,0x0,0x6d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0, + 0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x6d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0, + 0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x69,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0, + 0x72,0x0,0x65,0x0,0xa,0x0,0x73,0x0,0x75,0x0,0x62,0x0,0x6a,0x0,0x65,0x0,0x63,0x0,0x74,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x77,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x63,0x0,0x6f,0x0, + 0x6e,0x0,0x64,0x0,0x69,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x73,0x0,0x3a,0x0,0xa,0x0,0xa,0x0,0x31,0x0,0x29,0x0,0x20,0x0,0x4e,0x0, + 0x65,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0, + 0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x61,0x0, + 0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x69,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x64,0x0,0x69,0x0,0x76,0x0, + 0x69,0x0,0x64,0x0,0x75,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x6e,0x0,0x74,0x0, + 0x73,0x0,0xa,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x6f,0x0, + 0x72,0x0,0x20,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0, + 0x69,0x0,0x6f,0x0,0x6e,0x0,0x73,0x0,0xa,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x6f,0x0,0x6c,0x0, + 0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x69,0x0,0x74,0x0,0x73,0x0,0x65,0x0,0x6c,0x0,0x66,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x32,0x0, + 0x29,0x0,0x20,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x4d,0x0, + 0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0, + 0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0, + 0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0, + 0x62,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x6c,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0, + 0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x2f,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x73,0x0, + 0x6f,0x0,0x6c,0x0,0x64,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x73,0x0,0x6f,0x0, + 0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x69,0x0,0x64,0x0,0x65,0x0,0x64,0x0, + 0x20,0x0,0x74,0x0,0x68,0x0,0x61,0x0,0x74,0x0,0x20,0x0,0x65,0x0,0x61,0x0,0x63,0x0,0x68,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0, + 0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x61,0x0, + 0x62,0x0,0x6f,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0, + 0x6e,0x0,0x6f,0x0,0x74,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0, + 0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x73,0x0,0x65,0x0, + 0x20,0x0,0x63,0x0,0x61,0x0,0x6e,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x63,0x0,0x6c,0x0,0x75,0x0,0x64,0x0,0x65,0x0, + 0x64,0x0,0x20,0x0,0x65,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x74,0x0,0x61,0x0, + 0x6e,0x0,0x64,0x0,0x2d,0x0,0x61,0x0,0x6c,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x65,0x0,0x78,0x0,0x74,0x0,0x20,0x0,0x66,0x0, + 0x69,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x68,0x0,0x75,0x0,0x6d,0x0,0x61,0x0,0x6e,0x0,0x2d,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x64,0x0, + 0x61,0x0,0x62,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x68,0x0,0x65,0x0,0x61,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x72,0x0, + 0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x70,0x0,0x72,0x0, + 0x69,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x63,0x0,0x68,0x0,0x69,0x0,0x6e,0x0,0x65,0x0,0x2d,0x0,0x72,0x0,0x65,0x0, + 0x61,0x0,0x64,0x0,0x61,0x0,0x62,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x65,0x0,0x74,0x0,0x61,0x0,0x64,0x0,0x61,0x0,0x74,0x0,0x61,0x0, + 0x20,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x6c,0x0,0x64,0x0,0x73,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x6e,0x0,0x20,0x0, + 0x74,0x0,0x65,0x0,0x78,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x62,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x72,0x0,0x79,0x0,0x20,0x0, + 0x66,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x6f,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x61,0x0, + 0x73,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x6c,0x0,0x64,0x0,0x73,0x0,0x20,0x0, + 0x63,0x0,0x61,0x0,0x6e,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x65,0x0,0x61,0x0,0x73,0x0,0x69,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x76,0x0, + 0x69,0x0,0x65,0x0,0x77,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x75,0x0,0x73,0x0, + 0x65,0x0,0x72,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x33,0x0,0x29,0x0,0x20,0x0,0x4e,0x0,0x6f,0x0,0x20,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0, + 0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0,0x66,0x0, + 0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0, + 0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0, + 0x20,0x0,0x52,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0, + 0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x20,0x0, + 0x65,0x0,0x78,0x0,0x70,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x69,0x0,0x74,0x0,0x20,0x0,0x77,0x0,0x72,0x0,0x69,0x0,0x74,0x0,0x74,0x0,0x65,0x0, + 0x6e,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0,0x6d,0x0,0x69,0x0,0x73,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x69,0x0,0x73,0x0, + 0x20,0x0,0x67,0x0,0x72,0x0,0x61,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0, + 0x20,0x0,0x63,0x0,0x6f,0x0,0x72,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x64,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0, + 0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0,0x6c,0x0,0x64,0x0,0x65,0x0, + 0x72,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x63,0x0, + 0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0,0x6e,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x6c,0x0,0x69,0x0, + 0x65,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x61,0x0, + 0x72,0x0,0x79,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x73,0x0, + 0x20,0x0,0x70,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x34,0x0,0x29,0x0,0x20,0x0,0x54,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0, + 0x6c,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0, + 0x41,0x0,0x75,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0, + 0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0, + 0x20,0x0,0x73,0x0,0x68,0x0,0x61,0x0,0x6c,0x0,0x6c,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x75,0x0, + 0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x6d,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0xa,0x0, + 0x65,0x0,0x6e,0x0,0x64,0x0,0x6f,0x0,0x72,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x64,0x0,0x76,0x0,0x65,0x0, + 0x72,0x0,0x74,0x0,0x69,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0, + 0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0xa,0x0,0x65,0x0,0x78,0x0,0x63,0x0, + 0x65,0x0,0x70,0x0,0x74,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x63,0x0,0x6b,0x0,0x6e,0x0,0x6f,0x0,0x77,0x0,0x6c,0x0,0x65,0x0, + 0x64,0x0,0x67,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0, + 0x75,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0, + 0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0,0x6c,0x0,0x64,0x0, + 0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x41,0x0, + 0x75,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0, + 0x68,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x69,0x0,0x72,0x0,0x20,0x0,0x65,0x0,0x78,0x0,0x70,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x69,0x0, + 0x74,0x0,0x20,0x0,0x77,0x0,0x72,0x0,0x69,0x0,0x74,0x0,0x74,0x0,0x65,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0,0x6d,0x0,0x69,0x0, + 0x73,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x35,0x0,0x29,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0, + 0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0,0x6d,0x0, + 0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x6d,0x0,0x6f,0x0, + 0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x61,0x0,0x72,0x0,0x74,0x0,0x20,0x0, + 0x6f,0x0,0x72,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x77,0x0,0x68,0x0,0x6f,0x0,0x6c,0x0,0x65,0x0,0xa,0x0,0x6d,0x0,0x75,0x0,0x73,0x0, + 0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0, + 0x64,0x0,0x20,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x69,0x0,0x72,0x0,0x65,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0, + 0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0xa,0x0, + 0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x6d,0x0,0x75,0x0,0x73,0x0,0x74,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0, + 0x20,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x6e,0x0, + 0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x6c,0x0, + 0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x71,0x0, + 0x75,0x0,0x69,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x66,0x0,0x6f,0x0, + 0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x75,0x0, + 0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0, + 0x73,0x0,0x65,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x61,0x0,0x70,0x0,0x70,0x0, + 0x6c,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x63,0x0,0x75,0x0,0x6d,0x0, + 0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x69,0x0, + 0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0, + 0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x54,0x0,0x45,0x0,0x52,0x0,0x4d,0x0,0x49,0x0,0x4e,0x0,0x41,0x0, + 0x54,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0xa,0x0,0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0, + 0x73,0x0,0x65,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6e,0x0,0x75,0x0,0x6c,0x0,0x6c,0x0, + 0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x76,0x0,0x6f,0x0,0x69,0x0,0x64,0x0,0x20,0x0,0x69,0x0,0x66,0x0,0x20,0x0,0x61,0x0,0x6e,0x0, + 0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x62,0x0,0x6f,0x0,0x76,0x0,0x65,0x0,0x20,0x0, + 0x63,0x0,0x6f,0x0,0x6e,0x0,0x64,0x0,0x69,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0, + 0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x6d,0x0,0x65,0x0,0x74,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x44,0x0,0x49,0x0,0x53,0x0,0x43,0x0,0x4c,0x0, + 0x41,0x0,0x49,0x0,0x4d,0x0,0x45,0x0,0x52,0x0,0xa,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x4e,0x0,0x54,0x0,0x20,0x0, + 0x53,0x0,0x4f,0x0,0x46,0x0,0x54,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x45,0x0,0x20,0x0,0x49,0x0,0x53,0x0,0x20,0x0,0x50,0x0,0x52,0x0,0x4f,0x0, + 0x56,0x0,0x49,0x0,0x44,0x0,0x45,0x0,0x44,0x0,0x20,0x0,0x22,0x0,0x41,0x0,0x53,0x0,0x20,0x0,0x49,0x0,0x53,0x0,0x22,0x0,0xa,0x0,0x57,0x0, + 0x49,0x0,0x54,0x0,0x48,0x0,0x4f,0x0,0x55,0x0,0x54,0x0,0x20,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x52,0x0,0x41,0x0,0x4e,0x0,0x54,0x0,0x59,0x0, + 0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x4b,0x0,0x49,0x0,0x4e,0x0,0x44,0x0,0xa,0x0,0x45,0x0,0x58,0x0, + 0x50,0x0,0x52,0x0,0x45,0x0,0x53,0x0,0x53,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x49,0x0,0x4d,0x0,0x50,0x0,0x4c,0x0,0x49,0x0,0x45,0x0, + 0x44,0x0,0xa,0x0,0x49,0x0,0x4e,0x0,0x43,0x0,0x4c,0x0,0x55,0x0,0x44,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x20,0x0,0x42,0x0,0x55,0x0,0x54,0x0, + 0x20,0x0,0x4e,0x0,0x4f,0x0,0x54,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x4d,0x0,0x49,0x0,0x54,0x0,0x45,0x0,0x44,0x0,0x20,0x0,0x54,0x0,0x4f,0x0, + 0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x52,0x0,0x41,0x0,0x4e,0x0,0x54,0x0,0x49,0x0,0x45,0x0,0x53,0x0, + 0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x4d,0x0,0x45,0x0,0x52,0x0,0x43,0x0,0x48,0x0,0x41,0x0,0x4e,0x0,0x54,0x0,0x41,0x0,0x42,0x0,0x49,0x0, + 0x4c,0x0,0x49,0x0,0x54,0x0,0x59,0x0,0xa,0x0,0x46,0x0,0x49,0x0,0x54,0x0,0x4e,0x0,0x45,0x0,0x53,0x0,0x53,0x0,0x20,0x0,0x46,0x0,0x4f,0x0, + 0x52,0x0,0x20,0x0,0x41,0x0,0x20,0x0,0x50,0x0,0x41,0x0,0x52,0x0,0x54,0x0,0x49,0x0,0x43,0x0,0x55,0x0,0x4c,0x0,0x41,0x0,0x52,0x0,0x20,0x0, + 0x50,0x0,0x55,0x0,0x52,0x0,0x50,0x0,0x4f,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x44,0x0,0x20,0x0,0x4e,0x0,0x4f,0x0,0x4e,0x0, + 0x49,0x0,0x4e,0x0,0x46,0x0,0x52,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x45,0x0,0x4d,0x0,0x45,0x0,0x4e,0x0,0x54,0x0,0x20,0x0,0x4f,0x0,0x46,0x0, + 0x20,0x0,0x43,0x0,0x4f,0x0,0x50,0x0,0x59,0x0,0x52,0x0,0x49,0x0,0x47,0x0,0x48,0x0,0x54,0x0,0xa,0x0,0x50,0x0,0x41,0x0,0x54,0x0,0x45,0x0, + 0x4e,0x0,0x54,0x0,0xa,0x0,0x54,0x0,0x52,0x0,0x41,0x0,0x44,0x0,0x45,0x0,0x4d,0x0,0x41,0x0,0x52,0x0,0x4b,0x0,0xa,0x0,0x4f,0x0,0x52,0x0, + 0x20,0x0,0x4f,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x52,0x0,0x49,0x0,0x47,0x0,0x48,0x0,0x54,0x0,0x2e,0x0,0x20,0x0,0x49,0x0, + 0x4e,0x0,0x20,0x0,0x4e,0x0,0x4f,0x0,0x20,0x0,0x45,0x0,0x56,0x0,0x45,0x0,0x4e,0x0,0x54,0x0,0x20,0x0,0x53,0x0,0x48,0x0,0x41,0x0,0x4c,0x0, + 0x4c,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x50,0x0,0x59,0x0,0x52,0x0,0x49,0x0,0x47,0x0,0x48,0x0,0x54,0x0, + 0x20,0x0,0x48,0x0,0x4f,0x0,0x4c,0x0,0x44,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x42,0x0,0x45,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x41,0x0,0x42,0x0, + 0x4c,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x43,0x0,0x4c,0x0,0x41,0x0,0x49,0x0, + 0x4d,0x0,0xa,0x0,0x44,0x0,0x41,0x0,0x4d,0x0,0x41,0x0,0x47,0x0,0x45,0x0,0x53,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x4f,0x0,0x54,0x0, + 0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x41,0x0,0x42,0x0,0x49,0x0,0x4c,0x0,0x49,0x0,0x54,0x0,0x59,0x0,0xa,0x0,0x49,0x0, + 0x4e,0x0,0x43,0x0,0x4c,0x0,0x55,0x0,0x44,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x47,0x0,0x45,0x0, + 0x4e,0x0,0x45,0x0,0x52,0x0,0x41,0x0,0x4c,0x0,0xa,0x0,0x53,0x0,0x50,0x0,0x45,0x0,0x43,0x0,0x49,0x0,0x41,0x0,0x4c,0x0,0xa,0x0,0x49,0x0, + 0x4e,0x0,0x44,0x0,0x49,0x0,0x52,0x0,0x45,0x0,0x43,0x0,0x54,0x0,0xa,0x0,0x49,0x0,0x4e,0x0,0x43,0x0,0x49,0x0,0x44,0x0,0x45,0x0,0x4e,0x0, + 0x54,0x0,0x41,0x0,0x4c,0x0,0xa,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x4e,0x0,0x53,0x0,0x45,0x0,0x51,0x0,0x55,0x0,0x45,0x0, + 0x4e,0x0,0x54,0x0,0x49,0x0,0x41,0x0,0x4c,0x0,0x20,0x0,0x44,0x0,0x41,0x0,0x4d,0x0,0x41,0x0,0x47,0x0,0x45,0x0,0x53,0x0,0xa,0x0,0x57,0x0, + 0x48,0x0,0x45,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x49,0x0,0x4e,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x20,0x0,0x41,0x0,0x43,0x0, + 0x54,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x4e,0x0,0x54,0x0,0x52,0x0,0x41,0x0,0x43,0x0, + 0x54,0x0,0xa,0x0,0x54,0x0,0x4f,0x0,0x52,0x0,0x54,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x4f,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0, + 0x57,0x0,0x49,0x0,0x53,0x0,0x45,0x0,0xa,0x0,0x41,0x0,0x52,0x0,0x49,0x0,0x53,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x20,0x0,0x46,0x0,0x52,0x0, + 0x4f,0x0,0x4d,0x0,0xa,0x0,0x4f,0x0,0x55,0x0,0x54,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x55,0x0, + 0x53,0x0,0x45,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x49,0x0,0x4e,0x0,0x41,0x0,0x42,0x0,0x49,0x0,0x4c,0x0,0x49,0x0,0x54,0x0,0x59,0x0, + 0x20,0x0,0x54,0x0,0x4f,0x0,0x20,0x0,0x55,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x4e,0x0, + 0x54,0x0,0x20,0x0,0x53,0x0,0x4f,0x0,0x46,0x0,0x54,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x45,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x46,0x0, + 0x52,0x0,0x4f,0x0,0x4d,0x0,0x20,0x0,0x4f,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x44,0x0,0x45,0x0,0x41,0x0,0x4c,0x0,0x49,0x0, + 0x4e,0x0,0x47,0x0,0x53,0x0,0x20,0x0,0x49,0x0,0x4e,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x4e,0x0,0x54,0x0, + 0x20,0x0,0x53,0x0,0x4f,0x0,0x46,0x0,0x54,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x45,0x0,0x2e,0x0,0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0, + 0x2f,0x0,0x2f,0x0,0x73,0x0,0x63,0x0,0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x73,0x0,0x2e,0x0,0x73,0x0,0x69,0x0,0x6c,0x0,0x2e,0x0,0x6f,0x0, + 0x72,0x0,0x67,0x0,0x2f,0x0,0x4f,0x0,0x46,0x0,0x4c,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x47,0x0,0x82,0x0,0x0,0x0,0x1,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x9b,0x0,0x0,0x0,0x3,0x0,0x24,0x0,0xc9,0x1,0x2,0x0,0xc7,0x0,0x62, + 0x0,0xad,0x1,0x3,0x1,0x4,0x0,0x63,0x0,0xae,0x0,0x90,0x0,0x25,0x0,0x26,0x0,0xfd,0x0,0xff,0x0,0x64,0x1,0x5,0x1,0x6,0x0,0x27,0x0,0xe9, + 0x1,0x7,0x1,0x8,0x0,0x28,0x0,0x65,0x1,0x9,0x1,0xa,0x0,0xc8,0x0,0xca,0x1,0xb,0x0,0xcb,0x1,0xc,0x1,0xd,0x0,0x29,0x0,0x2a,0x0,0xf8, + 0x1,0xe,0x1,0xf,0x1,0x10,0x0,0x2b,0x1,0x11,0x1,0x12,0x0,0x2c,0x1,0x13,0x0,0xcc,0x1,0x14,0x0,0xcd,0x0,0xce,0x0,0xfa,0x0,0xcf,0x1,0x15, + 0x1,0x16,0x1,0x17,0x0,0x2d,0x1,0x18,0x0,0x2e,0x1,0x19,0x0,0x2f,0x1,0x1a,0x1,0x1b,0x1,0x1c,0x1,0x1d,0x0,0xe2,0x0,0x30,0x0,0x31,0x1,0x1e, + 0x1,0x1f,0x1,0x20,0x1,0x21,0x0,0x66,0x0,0x32,0x0,0xd0,0x1,0x22,0x0,0xd1,0x0,0x67,0x0,0xd3,0x1,0x23,0x1,0x24,0x0,0x91,0x0,0xaf,0x0,0xb0, + 0x0,0x33,0x0,0xed,0x0,0x34,0x0,0x35,0x1,0x25,0x1,0x26,0x1,0x27,0x0,0x36,0x1,0x28,0x0,0xe4,0x0,0xfb,0x1,0x29,0x1,0x2a,0x0,0x37,0x1,0x2b, + 0x1,0x2c,0x1,0x2d,0x1,0x2e,0x0,0x38,0x0,0xd4,0x1,0x2f,0x0,0xd5,0x0,0x68,0x0,0xd6,0x1,0x30,0x1,0x31,0x1,0x32,0x1,0x33,0x1,0x34,0x0,0x39, + 0x0,0x3a,0x1,0x35,0x1,0x36,0x1,0x37,0x1,0x38,0x0,0x3b,0x0,0x3c,0x0,0xeb,0x1,0x39,0x0,0xbb,0x1,0x3a,0x0,0x3d,0x1,0x3b,0x0,0xe6,0x1,0x3c, + 0x0,0x44,0x0,0x69,0x1,0x3d,0x0,0x6b,0x0,0x6c,0x0,0x6a,0x1,0x3e,0x1,0x3f,0x0,0x6e,0x0,0x6d,0x0,0xa0,0x0,0x45,0x0,0x46,0x0,0xfe,0x1,0x0, + 0x0,0x6f,0x1,0x40,0x1,0x41,0x0,0x47,0x0,0xea,0x1,0x42,0x1,0x1,0x0,0x48,0x0,0x70,0x1,0x43,0x1,0x44,0x0,0x72,0x0,0x73,0x1,0x45,0x0,0x71, + 0x1,0x46,0x1,0x47,0x0,0x49,0x0,0x4a,0x0,0xf9,0x1,0x48,0x1,0x49,0x1,0x4a,0x0,0x4b,0x1,0x4b,0x1,0x4c,0x0,0x4c,0x0,0xd7,0x0,0x74,0x1,0x4d, + 0x0,0x76,0x0,0x77,0x1,0x4e,0x0,0x75,0x1,0x4f,0x1,0x50,0x1,0x51,0x1,0x52,0x0,0x4d,0x1,0x53,0x1,0x54,0x0,0x4e,0x1,0x55,0x0,0x4f,0x1,0x56, + 0x1,0x57,0x1,0x58,0x1,0x59,0x0,0xe3,0x0,0x50,0x0,0x51,0x1,0x5a,0x1,0x5b,0x1,0x5c,0x1,0x5d,0x0,0x78,0x0,0x52,0x0,0x79,0x1,0x5e,0x0,0x7b, + 0x0,0x7c,0x0,0x7a,0x1,0x5f,0x1,0x60,0x0,0xa1,0x0,0x7d,0x0,0xb1,0x0,0x53,0x0,0xee,0x0,0x54,0x0,0x55,0x1,0x61,0x1,0x62,0x1,0x63,0x0,0x56, + 0x1,0x64,0x0,0xe5,0x0,0xfc,0x1,0x65,0x1,0x66,0x0,0x89,0x0,0x57,0x1,0x67,0x1,0x68,0x1,0x69,0x1,0x6a,0x0,0x58,0x0,0x7e,0x1,0x6b,0x0,0x80, + 0x0,0x81,0x0,0x7f,0x1,0x6c,0x1,0x6d,0x1,0x6e,0x1,0x6f,0x1,0x70,0x0,0x59,0x0,0x5a,0x1,0x71,0x1,0x72,0x1,0x73,0x1,0x74,0x0,0x5b,0x0,0x5c, + 0x0,0xec,0x1,0x75,0x0,0xba,0x1,0x76,0x0,0x5d,0x1,0x77,0x0,0xe7,0x1,0x78,0x0,0xc0,0x0,0xc1,0x0,0x9d,0x0,0x9e,0x1,0x79,0x1,0x7a,0x1,0x7b, + 0x0,0x9b,0x0,0x13,0x0,0x14,0x0,0x15,0x0,0x16,0x0,0x17,0x0,0x18,0x0,0x19,0x0,0x1a,0x0,0x1b,0x0,0x1c,0x0,0xbc,0x0,0xf4,0x0,0xf5,0x0,0xf6, + 0x1,0x7c,0x1,0x7d,0x1,0x7e,0x1,0x7f,0x1,0x80,0x1,0x81,0x1,0x82,0x1,0x83,0x1,0x84,0x1,0x85,0x1,0x86,0x1,0x87,0x1,0x88,0x0,0xd,0x0,0x3f, + 0x0,0xc3,0x0,0x87,0x0,0x1d,0x0,0xf,0x0,0xab,0x0,0x4,0x0,0xa3,0x0,0x6,0x0,0x11,0x0,0x22,0x0,0xa2,0x0,0x5,0x0,0xa,0x0,0x1e,0x0,0x12, + 0x0,0x42,0x0,0x5e,0x0,0x60,0x0,0x3e,0x0,0x40,0x0,0xb,0x0,0xc,0x1,0x89,0x1,0x8a,0x1,0x8b,0x1,0x8c,0x1,0x8d,0x0,0xb3,0x0,0xb2,0x0,0x10, + 0x1,0x8e,0x1,0x8f,0x0,0xa9,0x0,0xaa,0x0,0xbe,0x0,0xbf,0x0,0xc5,0x0,0xb4,0x0,0xb5,0x0,0xb6,0x0,0xb7,0x0,0xc4,0x1,0x90,0x0,0x84,0x0,0xbd, + 0x0,0x7,0x1,0x91,0x0,0xa6,0x0,0xf7,0x0,0x85,0x1,0x92,0x0,0x96,0x0,0xa7,0x0,0x61,0x0,0xb8,0x0,0x20,0x0,0x21,0x0,0x95,0x0,0x92,0x0,0x9c, + 0x0,0x1f,0x0,0x94,0x0,0xa4,0x0,0xef,0x0,0xf0,0x0,0x8f,0x0,0x98,0x0,0x8,0x0,0xc6,0x0,0xe,0x0,0x93,0x0,0x9a,0x0,0xa5,0x0,0x99,0x0,0xb9, + 0x0,0x5f,0x0,0xe8,0x0,0x23,0x0,0x9,0x0,0x88,0x0,0x8b,0x0,0x8a,0x0,0x86,0x0,0x8c,0x0,0x83,0x0,0x41,0x0,0x82,0x0,0xc2,0x1,0x93,0x1,0x94, + 0x1,0x95,0x1,0x96,0x0,0x8d,0x1,0x97,0x0,0xdb,0x0,0xe1,0x1,0x98,0x1,0x99,0x1,0x9a,0x1,0x9b,0x1,0x9c,0x1,0x9d,0x1,0x9e,0x1,0x9f,0x1,0xa0, + 0x1,0xa1,0x1,0xa2,0x1,0xa3,0x1,0xa4,0x0,0xde,0x0,0xd8,0x0,0x8e,0x0,0xdc,0x0,0x43,0x0,0xdf,0x0,0xda,0x0,0xe0,0x0,0xdd,0x0,0xd9,0x6,0x41, + 0x62,0x72,0x65,0x76,0x65,0x7,0x41,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x41,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x43,0x63,0x69,0x72,0x63,0x75,0x6d,0x66, + 0x6c,0x65,0x78,0xa,0x43,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x44,0x63,0x61,0x72,0x6f,0x6e,0x6,0x44,0x63,0x72,0x6f,0x61,0x74,0x6,0x45, + 0x62,0x72,0x65,0x76,0x65,0x6,0x45,0x63,0x61,0x72,0x6f,0x6e,0xa,0x45,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x7,0x45,0x6d,0x61,0x63,0x72,0x6f, + 0x6e,0x7,0x45,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x47,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x47,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63, + 0x63,0x65,0x6e,0x74,0xa,0x47,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x48,0x62,0x61,0x72,0xb,0x48,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c, + 0x65,0x78,0x2,0x49,0x4a,0x6,0x49,0x62,0x72,0x65,0x76,0x65,0x7,0x49,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x49,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x6,0x49, + 0x74,0x69,0x6c,0x64,0x65,0xb,0x4a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x4b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74, + 0x6,0x4c,0x61,0x63,0x75,0x74,0x65,0x6,0x4c,0x63,0x61,0x72,0x6f,0x6e,0xc,0x4c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x4c,0x64, + 0x6f,0x74,0x6,0x4e,0x61,0x63,0x75,0x74,0x65,0x6,0x4e,0x63,0x61,0x72,0x6f,0x6e,0xc,0x4e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x3, + 0x45,0x6e,0x67,0x6,0x4f,0x62,0x72,0x65,0x76,0x65,0xd,0x4f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x4f,0x6d,0x61,0x63,0x72, + 0x6f,0x6e,0x6,0x52,0x61,0x63,0x75,0x74,0x65,0x6,0x52,0x63,0x61,0x72,0x6f,0x6e,0xc,0x52,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x6, + 0x53,0x61,0x63,0x75,0x74,0x65,0xb,0x53,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x53,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e, + 0x74,0x4,0x54,0x62,0x61,0x72,0x6,0x54,0x63,0x61,0x72,0x6f,0x6e,0x7,0x75,0x6e,0x69,0x30,0x31,0x36,0x32,0x7,0x75,0x6e,0x69,0x30,0x32,0x31,0x41,0x6, + 0x55,0x62,0x72,0x65,0x76,0x65,0xd,0x55,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x55,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x55, + 0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x5,0x55,0x72,0x69,0x6e,0x67,0x6,0x55,0x74,0x69,0x6c,0x64,0x65,0x6,0x57,0x61,0x63,0x75,0x74,0x65,0xb,0x57,0x63,0x69, + 0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x9,0x57,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x6,0x57,0x67,0x72,0x61,0x76,0x65,0xb,0x59,0x63,0x69,0x72, + 0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x6,0x59,0x67,0x72,0x61,0x76,0x65,0x6,0x5a,0x61,0x63,0x75,0x74,0x65,0xa,0x5a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65, + 0x6e,0x74,0x6,0x61,0x62,0x72,0x65,0x76,0x65,0x7,0x61,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x61,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x63,0x63,0x69,0x72, + 0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xa,0x63,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x64,0x63,0x61,0x72,0x6f,0x6e,0x6,0x65,0x62,0x72,0x65, + 0x76,0x65,0x6,0x65,0x63,0x61,0x72,0x6f,0x6e,0xa,0x65,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x7,0x65,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x65, + 0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x67,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x67,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e, + 0x74,0xa,0x67,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x68,0x62,0x61,0x72,0xb,0x68,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x6, + 0x69,0x62,0x72,0x65,0x76,0x65,0x9,0x69,0x2e,0x6c,0x6f,0x63,0x6c,0x54,0x52,0x4b,0x2,0x69,0x6a,0x7,0x69,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x69,0x6f, + 0x67,0x6f,0x6e,0x65,0x6b,0x6,0x69,0x74,0x69,0x6c,0x64,0x65,0x7,0x75,0x6e,0x69,0x30,0x32,0x33,0x37,0xb,0x6a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c, + 0x65,0x78,0xc,0x6b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x6c,0x61,0x63,0x75,0x74,0x65,0x6,0x6c,0x63,0x61,0x72,0x6f,0x6e,0xc, + 0x6c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x6c,0x64,0x6f,0x74,0x6,0x6e,0x61,0x63,0x75,0x74,0x65,0x6,0x6e,0x63,0x61,0x72,0x6f, + 0x6e,0xc,0x6e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x3,0x65,0x6e,0x67,0x6,0x6f,0x62,0x72,0x65,0x76,0x65,0xd,0x6f,0x68,0x75,0x6e, + 0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x6f,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x6,0x72,0x61,0x63,0x75,0x74,0x65,0x6,0x72,0x63,0x61,0x72,0x6f, + 0x6e,0xc,0x72,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x73,0x61,0x63,0x75,0x74,0x65,0xb,0x73,0x63,0x69,0x72,0x63,0x75,0x6d,0x66, + 0x6c,0x65,0x78,0xc,0x73,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x74,0x62,0x61,0x72,0x6,0x74,0x63,0x61,0x72,0x6f,0x6e,0x7,0x75, + 0x6e,0x69,0x30,0x31,0x36,0x33,0x7,0x75,0x6e,0x69,0x30,0x32,0x31,0x42,0x6,0x75,0x62,0x72,0x65,0x76,0x65,0xd,0x75,0x68,0x75,0x6e,0x67,0x61,0x72,0x75, + 0x6d,0x6c,0x61,0x75,0x74,0x7,0x75,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x75,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x5,0x75,0x72,0x69,0x6e,0x67,0x6,0x75,0x74, + 0x69,0x6c,0x64,0x65,0x6,0x77,0x61,0x63,0x75,0x74,0x65,0xb,0x77,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x9,0x77,0x64,0x69,0x65,0x72,0x65, + 0x73,0x69,0x73,0x6,0x77,0x67,0x72,0x61,0x76,0x65,0xb,0x79,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x6,0x79,0x67,0x72,0x61,0x76,0x65,0x6, + 0x7a,0x61,0x63,0x75,0x74,0x65,0xa,0x7a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x7,0x75,0x6e,0x69,0x30,0x33,0x39,0x34,0x7,0x75,0x6e,0x69,0x30, + 0x33,0x41,0x39,0x7,0x75,0x6e,0x69,0x30,0x33,0x42,0x43,0x7,0x75,0x6e,0x69,0x30,0x30,0x42,0x39,0x7,0x75,0x6e,0x69,0x30,0x30,0x42,0x32,0x7,0x75,0x6e, + 0x69,0x30,0x30,0x42,0x33,0x7,0x75,0x6e,0x69,0x32,0x30,0x37,0x34,0x9,0x63,0x6f,0x6c,0x6f,0x6e,0x2e,0x61,0x6c,0x74,0x9,0x63,0x6f,0x6d,0x6d,0x61,0x2e, + 0x61,0x6c,0x74,0xa,0x70,0x65,0x72,0x69,0x6f,0x64,0x2e,0x61,0x6c,0x74,0xd,0x73,0x65,0x6d,0x69,0x63,0x6f,0x6c,0x6f,0x6e,0x2e,0x61,0x6c,0x74,0xd,0x65, + 0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x31,0xd,0x65,0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x32,0xd,0x65,0x6c,0x6c, + 0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x33,0xd,0x65,0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x34,0xd,0x65,0x6c,0x6c,0x69,0x70, + 0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x35,0xa,0x68,0x79,0x70,0x68,0x65,0x6e,0x2e,0x61,0x6c,0x74,0xb,0x65,0x6d,0x64,0x61,0x73,0x68,0x2e,0x61,0x6c,0x74, + 0x31,0xb,0x65,0x6d,0x64,0x61,0x73,0x68,0x2e,0x61,0x6c,0x74,0x32,0xb,0x65,0x6d,0x64,0x61,0x73,0x68,0x2e,0x61,0x6c,0x74,0x33,0xb,0x65,0x6d,0x64,0x61, + 0x73,0x68,0x2e,0x61,0x6c,0x74,0x34,0x7,0x75,0x6e,0x69,0x32,0x30,0x31,0x31,0x7,0x75,0x6e,0x69,0x30,0x30,0x41,0x44,0x7,0x75,0x6e,0x69,0x30,0x30,0x41, + 0x30,0x4,0x45,0x75,0x72,0x6f,0x7,0x75,0x6e,0x69,0x32,0x30,0x41,0x39,0x6,0x6d,0x69,0x6e,0x75,0x74,0x65,0x6,0x73,0x65,0x63,0x6f,0x6e,0x64,0x7,0x75, + 0x6e,0x69,0x30,0x33,0x32,0x36,0xc,0x75,0x6e,0x69,0x30,0x33,0x32,0x36,0x2e,0x63,0x61,0x73,0x65,0x9,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x61,0x6c,0x74,0xa, + 0x61,0x63,0x75,0x74,0x65,0x2e,0x63,0x61,0x73,0x65,0xa,0x62,0x72,0x65,0x76,0x65,0x2e,0x63,0x61,0x73,0x65,0xa,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x63,0x61, + 0x73,0x65,0xc,0x63,0x65,0x64,0x69,0x6c,0x6c,0x61,0x2e,0x63,0x61,0x73,0x65,0xf,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x63,0x61,0x73, + 0x65,0xd,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e,0x63,0x61,0x73,0x65,0xe,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x63,0x61,0x73,0x65, + 0xa,0x67,0x72,0x61,0x76,0x65,0x2e,0x63,0x61,0x73,0x65,0x11,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x2e,0x63,0x61,0x73,0x65,0xb, + 0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x63,0x61,0x73,0x65,0xb,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x2e,0x63,0x61,0x73,0x65,0x9,0x72,0x69,0x6e,0x67,0x2e,0x63, + 0x61,0x73,0x65,0xa,0x74,0x69,0x6c,0x64,0x65,0x2e,0x63,0x61,0x73,0x65,0x0,0x1,0x0,0x1,0xff,0xff,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9a,0x0,0x9a,0x0,0x94,0x0,0x94,0x4,0xa3,0x0,0x0,0x5,0x2a,0x3,0x9c,0x0,0x0, + 0xfe,0x70,0x7,0x5,0xfc,0xb9,0x4,0xb9,0xff,0xea,0x5,0x2a,0x3,0xb2,0xff,0xea,0xfe,0x70,0x7,0x5,0xfc,0xb9,0xb0,0x0,0x2c,0x20,0xb0,0x0,0x55,0x58, + 0x45,0x59,0x20,0x20,0x4b,0xb8,0x0,0xe,0x51,0x4b,0xb0,0x6,0x53,0x5a,0x58,0xb0,0x34,0x1b,0xb0,0x28,0x59,0x60,0x66,0x20,0x8a,0x55,0x58,0xb0,0x2,0x25, + 0x61,0xb9,0x8,0x0,0x8,0x0,0x63,0x63,0x23,0x62,0x1b,0x21,0x21,0xb0,0x0,0x59,0xb0,0x0,0x43,0x23,0x44,0xb2,0x0,0x1,0x0,0x43,0x60,0x42,0x2d,0xb0, + 0x1,0x2c,0xb0,0x20,0x60,0x66,0x2d,0xb0,0x2,0x2c,0x20,0x64,0x20,0xb0,0xc0,0x50,0xb0,0x4,0x26,0x5a,0xb2,0x28,0x1,0xa,0x43,0x45,0x63,0x45,0xb0,0x6, + 0x45,0x58,0x21,0xb0,0x3,0x25,0x59,0x52,0x5b,0x58,0x21,0x23,0x21,0x1b,0x8a,0x58,0x20,0xb0,0x50,0x50,0x58,0x21,0xb0,0x40,0x59,0x1b,0x20,0xb0,0x38,0x50, + 0x58,0x21,0xb0,0x38,0x59,0x59,0x20,0xb1,0x1,0xa,0x43,0x45,0x63,0x45,0x61,0x64,0xb0,0x28,0x50,0x58,0x21,0xb1,0x1,0xa,0x43,0x45,0x63,0x45,0x20,0xb0, + 0x30,0x50,0x58,0x21,0xb0,0x30,0x59,0x1b,0x20,0xb0,0xc0,0x50,0x58,0x20,0x66,0x20,0x8a,0x8a,0x61,0x20,0xb0,0xa,0x50,0x58,0x60,0x1b,0x20,0xb0,0x20,0x50, + 0x58,0x21,0xb0,0xa,0x60,0x1b,0x20,0xb0,0x36,0x50,0x58,0x21,0xb0,0x36,0x60,0x1b,0x60,0x59,0x59,0x59,0x1b,0xb0,0x1,0x2b,0x59,0x59,0x23,0xb0,0x0,0x50, + 0x58,0x65,0x59,0x59,0x2d,0xb0,0x3,0x2c,0x20,0x45,0x20,0xb0,0x4,0x25,0x61,0x64,0x20,0xb0,0x5,0x43,0x50,0x58,0xb0,0x5,0x23,0x42,0xb0,0x6,0x23,0x42, + 0x1b,0x21,0x21,0x59,0xb0,0x1,0x60,0x2d,0xb0,0x4,0x2c,0x23,0x21,0x23,0x21,0x20,0x64,0xb1,0x5,0x62,0x42,0x20,0xb0,0x6,0x23,0x42,0xb0,0x6,0x45,0x58, + 0x1b,0xb1,0x1,0xa,0x43,0x45,0x63,0xb1,0x1,0xa,0x43,0xb0,0x1,0x60,0x45,0x63,0xb0,0x3,0x2a,0x21,0x20,0xb0,0x6,0x43,0x20,0x8a,0x20,0x8a,0xb0,0x1, + 0x2b,0xb1,0x30,0x5,0x25,0xb0,0x4,0x26,0x51,0x58,0x60,0x50,0x1b,0x61,0x52,0x59,0x58,0x23,0x59,0x21,0x59,0x20,0xb0,0x40,0x53,0x58,0xb0,0x1,0x2b,0x1b, + 0x21,0xb0,0x40,0x59,0x23,0xb0,0x0,0x50,0x58,0x65,0x59,0x2d,0xb0,0x5,0x2c,0xb0,0x7,0x43,0x2b,0xb2,0x0,0x2,0x0,0x43,0x60,0x42,0x2d,0xb0,0x6,0x2c, + 0xb0,0x7,0x23,0x42,0x23,0x20,0xb0,0x0,0x23,0x42,0x61,0xb0,0x2,0x62,0x66,0xb0,0x1,0x63,0xb0,0x1,0x60,0xb0,0x5,0x2a,0x2d,0xb0,0x7,0x2c,0x20,0x20, + 0x45,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x44,0xb0,0x1,0x60,0x2d,0xb0, + 0x8,0x2c,0xb2,0x7,0xb,0x0,0x43,0x45,0x42,0x2a,0x21,0xb2,0x0,0x1,0x0,0x43,0x60,0x42,0x2d,0xb0,0x9,0x2c,0xb0,0x0,0x43,0x23,0x44,0xb2,0x0,0x1, + 0x0,0x43,0x60,0x42,0x2d,0xb0,0xa,0x2c,0x20,0x20,0x45,0x20,0xb0,0x1,0x2b,0x23,0xb0,0x0,0x43,0xb0,0x4,0x25,0x60,0x20,0x45,0x8a,0x23,0x61,0x20,0x64, + 0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x0,0x1b,0xb0,0x30,0x50,0x58,0xb0,0x20,0x1b,0xb0,0x40,0x59,0x59,0x23,0xb0,0x0,0x50,0x58,0x65,0x59,0xb0,0x3,0x25, + 0x23,0x61,0x44,0x44,0xb0,0x1,0x60,0x2d,0xb0,0xb,0x2c,0x20,0x20,0x45,0x20,0xb0,0x1,0x2b,0x23,0xb0,0x0,0x43,0xb0,0x4,0x25,0x60,0x20,0x45,0x8a,0x23, + 0x61,0x20,0x64,0xb0,0x24,0x50,0x58,0xb0,0x0,0x1b,0xb0,0x40,0x59,0x23,0xb0,0x0,0x50,0x58,0x65,0x59,0xb0,0x3,0x25,0x23,0x61,0x44,0x44,0xb0,0x1,0x60, + 0x2d,0xb0,0xc,0x2c,0x20,0xb0,0x0,0x23,0x42,0xb2,0xb,0xa,0x3,0x45,0x58,0x21,0x1b,0x23,0x21,0x59,0x2a,0x21,0x2d,0xb0,0xd,0x2c,0xb1,0x2,0x2,0x45, + 0xb0,0x64,0x61,0x44,0x2d,0xb0,0xe,0x2c,0xb0,0x1,0x60,0x20,0x20,0xb0,0xc,0x43,0x4a,0xb0,0x0,0x50,0x58,0x20,0xb0,0xc,0x23,0x42,0x59,0xb0,0xd,0x43, + 0x4a,0xb0,0x0,0x52,0x58,0x20,0xb0,0xd,0x23,0x42,0x59,0x2d,0xb0,0xf,0x2c,0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0x20,0xb8,0x4,0x0,0x63,0x8a,0x23, + 0x61,0xb0,0xe,0x43,0x60,0x20,0x8a,0x60,0x20,0xb0,0xe,0x23,0x42,0x23,0x2d,0xb0,0x10,0x2c,0x4b,0x54,0x58,0xb1,0x4,0x64,0x44,0x59,0x24,0xb0,0xd,0x65, + 0x23,0x78,0x2d,0xb0,0x11,0x2c,0x4b,0x51,0x58,0x4b,0x53,0x58,0xb1,0x4,0x64,0x44,0x59,0x1b,0x21,0x59,0x24,0xb0,0x13,0x65,0x23,0x78,0x2d,0xb0,0x12,0x2c, + 0xb1,0x0,0xf,0x43,0x55,0x58,0xb1,0xf,0xf,0x43,0xb0,0x1,0x61,0x42,0xb0,0xf,0x2b,0x59,0xb0,0x0,0x43,0xb0,0x2,0x25,0x42,0xb1,0xc,0x2,0x25,0x42, + 0xb1,0xd,0x2,0x25,0x42,0xb0,0x1,0x16,0x23,0x20,0xb0,0x3,0x25,0x50,0x58,0xb1,0x1,0x0,0x43,0x60,0xb0,0x4,0x25,0x42,0x8a,0x8a,0x20,0x8a,0x23,0x61, + 0xb0,0xe,0x2a,0x21,0x23,0xb0,0x1,0x61,0x20,0x8a,0x23,0x61,0xb0,0xe,0x2a,0x21,0x1b,0xb1,0x1,0x0,0x43,0x60,0xb0,0x2,0x25,0x42,0xb0,0x2,0x25,0x61, + 0xb0,0xe,0x2a,0x21,0x59,0xb0,0xc,0x43,0x47,0xb0,0xd,0x43,0x47,0x60,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63, + 0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0xb1,0x0,0x0,0x13,0x23,0x44,0xb0, + 0x1,0x43,0xb0,0x0,0x3e,0xb2,0x1,0x1,0x1,0x43,0x60,0x42,0x2d,0xb0,0x13,0x2c,0x0,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0xf,0x23,0x42,0x20,0x45,0xb0, + 0xb,0x23,0x42,0xb0,0xa,0x23,0xb0,0x1,0x60,0x42,0x20,0x60,0xb0,0x1,0x61,0xb5,0x10,0x10,0x1,0x0,0xe,0x0,0x42,0x42,0x8a,0x60,0xb1,0x12,0x6,0x2b, + 0xb0,0x75,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x14,0x2c,0xb1,0x0,0x13,0x2b,0x2d,0xb0,0x15,0x2c,0xb1,0x1,0x13,0x2b,0x2d,0xb0,0x16,0x2c,0xb1,0x2,0x13,0x2b, + 0x2d,0xb0,0x17,0x2c,0xb1,0x3,0x13,0x2b,0x2d,0xb0,0x18,0x2c,0xb1,0x4,0x13,0x2b,0x2d,0xb0,0x19,0x2c,0xb1,0x5,0x13,0x2b,0x2d,0xb0,0x1a,0x2c,0xb1,0x6, + 0x13,0x2b,0x2d,0xb0,0x1b,0x2c,0xb1,0x7,0x13,0x2b,0x2d,0xb0,0x1c,0x2c,0xb1,0x8,0x13,0x2b,0x2d,0xb0,0x1d,0x2c,0xb1,0x9,0x13,0x2b,0x2d,0xb0,0x29,0x2c, + 0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0xb0,0x6,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x1,0x5d,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2a,0x2c,0x23, + 0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0xb0,0x16,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x1,0x71,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2b,0x2c,0x23,0x20, + 0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0xb0,0x26,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x1,0x72,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x1e,0x2c,0x0,0xb0,0xd, + 0x2b,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0xf,0x23,0x42,0x20,0x45,0xb0,0xb,0x23,0x42,0xb0,0xa,0x23,0xb0,0x1,0x60,0x42,0x20,0x60,0xb0,0x1,0x61,0xb5, + 0x10,0x10,0x1,0x0,0xe,0x0,0x42,0x42,0x8a,0x60,0xb1,0x12,0x6,0x2b,0xb0,0x75,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x1f,0x2c,0xb1,0x0,0x1e,0x2b,0x2d,0xb0, + 0x20,0x2c,0xb1,0x1,0x1e,0x2b,0x2d,0xb0,0x21,0x2c,0xb1,0x2,0x1e,0x2b,0x2d,0xb0,0x22,0x2c,0xb1,0x3,0x1e,0x2b,0x2d,0xb0,0x23,0x2c,0xb1,0x4,0x1e,0x2b, + 0x2d,0xb0,0x24,0x2c,0xb1,0x5,0x1e,0x2b,0x2d,0xb0,0x25,0x2c,0xb1,0x6,0x1e,0x2b,0x2d,0xb0,0x26,0x2c,0xb1,0x7,0x1e,0x2b,0x2d,0xb0,0x27,0x2c,0xb1,0x8, + 0x1e,0x2b,0x2d,0xb0,0x28,0x2c,0xb1,0x9,0x1e,0x2b,0x2d,0xb0,0x2c,0x2c,0x20,0x3c,0xb0,0x1,0x60,0x2d,0xb0,0x2d,0x2c,0x20,0x60,0xb0,0x10,0x60,0x20,0x43, + 0x23,0xb0,0x1,0x60,0x43,0xb0,0x2,0x25,0x61,0xb0,0x1,0x60,0xb0,0x2c,0x2a,0x21,0x2d,0xb0,0x2e,0x2c,0xb0,0x2d,0x2b,0xb0,0x2d,0x2a,0x2d,0xb0,0x2f,0x2c, + 0x20,0x20,0x47,0x20,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x23,0x61,0x38, + 0x23,0x20,0x8a,0x55,0x58,0x20,0x47,0x20,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63, + 0x60,0x23,0x61,0x38,0x1b,0x21,0x59,0x2d,0xb0,0x30,0x2c,0x0,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0x1,0x16,0xb0,0x2f,0x2a,0xb1,0x5,0x1,0x15,0x45,0x58, + 0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x31,0x2c,0x0,0xb0,0xd,0x2b,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0x1,0x16,0xb0,0x2f,0x2a,0xb1,0x5,0x1,0x15,0x45, + 0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x32,0x2c,0x20,0x35,0xb0,0x1,0x60,0x2d,0xb0,0x33,0x2c,0x0,0xb0,0x1,0x45,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0, + 0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0xb0,0x1,0x2b,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60, + 0x59,0x66,0xb0,0x1,0x63,0xb0,0x1,0x2b,0xb0,0x0,0x16,0xb4,0x0,0x0,0x0,0x0,0x0,0x44,0x3e,0x23,0x38,0xb1,0x32,0x1,0x15,0x2a,0x2d,0xb0,0x34,0x2c, + 0x20,0x3c,0x20,0x47,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0xb0,0x0,0x43, + 0x61,0x38,0x2d,0xb0,0x35,0x2c,0x2e,0x17,0x3c,0x2d,0xb0,0x36,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50, + 0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0xb0,0x0,0x43,0x61,0xb0,0x1,0x43,0x63,0x38,0x2d,0xb0,0x37,0x2c,0xb1,0x2,0x0,0x16,0x25,0x20,0x2e, + 0x20,0x47,0xb0,0x0,0x23,0x42,0xb0,0x2,0x25,0x49,0x8a,0x8a,0x47,0x23,0x47,0x23,0x61,0x20,0x58,0x62,0x1b,0x21,0x59,0xb0,0x1,0x23,0x42,0xb2,0x36,0x1, + 0x1,0x15,0x14,0x2a,0x2d,0xb0,0x38,0x2c,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x9,0x43,0x2b,0x65,0x8a,0x2e,0x23, + 0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x39,0x2c,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x4,0x23,0x42, + 0xb0,0x9,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x2,0x20,0x3,0x20,0x1b,0xb3,0x2,0x26,0x3,0x1a,0x59,0x42,0x42,0x23,0x20, + 0xb0,0x8,0x43,0x20,0x8a,0x23,0x47,0x23,0x47,0x23,0x61,0x23,0x46,0x60,0xb0,0x4,0x43,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66, + 0xb0,0x1,0x63,0x60,0x20,0xb0,0x1,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x2,0x43,0x60,0x64,0x23,0xb0,0x3,0x43,0x61,0x64,0x50,0x58,0xb0,0x2,0x43,0x61, + 0x1b,0xb0,0x3,0x43,0x60,0x59,0xb0,0x3,0x25,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x61,0x23,0x20,0x20,0xb0, + 0x4,0x26,0x23,0x46,0x61,0x38,0x1b,0x23,0xb0,0x8,0x43,0x46,0xb0,0x2,0x25,0xb0,0x8,0x43,0x47,0x23,0x47,0x23,0x61,0x60,0x20,0xb0,0x4,0x43,0xb0,0x2, + 0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x23,0x20,0xb0,0x1,0x2b,0x23,0xb0,0x4,0x43,0x60,0xb0,0x1,0x2b,0xb0,0x5, + 0x25,0x61,0xb0,0x5,0x25,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0xb0,0x4,0x26,0x61,0x20,0xb0,0x4,0x25,0x60, + 0x64,0x23,0xb0,0x3,0x25,0x60,0x64,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x23,0x20,0x20,0xb0,0x4,0x26,0x23,0x46,0x61,0x38,0x59,0x2d,0xb0,0x3a,0x2c,0xb0, + 0x0,0x16,0x20,0x20,0x20,0xb0,0x5,0x26,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x23,0x3c,0x38,0x2d,0xb0,0x3b,0x2c,0xb0,0x0,0x16,0x20,0xb0,0x8,0x23,0x42, + 0x20,0x20,0x20,0x46,0x23,0x47,0xb0,0x1,0x2b,0x23,0x61,0x38,0x2d,0xb0,0x3c,0x2c,0xb0,0x0,0x16,0xb0,0x3,0x25,0xb0,0x2,0x25,0x47,0x23,0x47,0x23,0x61, + 0xb0,0x0,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x2,0x25,0xb0,0x2,0x25,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x5,0x25,0xb0,0x4,0x25,0x47,0x23, + 0x47,0x23,0x61,0xb0,0x6,0x25,0xb0,0x5,0x25,0x49,0xb0,0x2,0x25,0x61,0xb9,0x8,0x0,0x8,0x0,0x63,0x63,0x23,0x20,0x58,0x62,0x1b,0x21,0x59,0x63,0xb8, + 0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x23,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x21,0x59,0x2d,0xb0, + 0x3d,0x2c,0xb0,0x0,0x16,0x20,0xb0,0x8,0x43,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58, + 0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x3e,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58,0x20,0x3c, + 0x59,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x3f,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x2e,0x1,0x14,0x2b, + 0x2d,0xb0,0x40,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x50,0x58,0x20,0x3c,0x59, + 0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x41,0x2c,0xb0,0x38,0x2b,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x2e,0x1, + 0x14,0x2b,0x2d,0xb0,0x42,0x2c,0xb0,0x39,0x2b,0x8a,0x20,0x20,0x3c,0xb0,0x4,0x23,0x42,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58,0x20, + 0x3c,0x59,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0xb0,0x4,0x43,0x2e,0xb0,0x2e,0x2b,0x2d,0xb0,0x43,0x2c,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x26,0x20,0x2e, + 0x47,0x23,0x47,0x23,0x61,0xb0,0x9,0x43,0x2b,0x23,0x20,0x3c,0x20,0x2e,0x23,0x38,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x44,0x2c,0xb1,0x8,0x4,0x25,0x42, + 0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x4,0x23,0x42,0xb0,0x9,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58, + 0x20,0xb0,0x40,0x51,0x58,0xb3,0x2,0x20,0x3,0x20,0x1b,0xb3,0x2,0x26,0x3,0x1a,0x59,0x42,0x42,0x23,0x20,0x47,0xb0,0x4,0x43,0xb0,0x2,0x62,0x20,0xb0, + 0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x20,0xb0,0x1,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x2,0x43,0x60,0x64,0x23,0xb0,0x3,0x43, + 0x61,0x64,0x50,0x58,0xb0,0x2,0x43,0x61,0x1b,0xb0,0x3,0x43,0x60,0x59,0xb0,0x3,0x25,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66, + 0xb0,0x1,0x63,0x61,0xb0,0x2,0x25,0x46,0x61,0x38,0x23,0x20,0x3c,0x23,0x38,0x1b,0x21,0x20,0x20,0x46,0x23,0x47,0xb0,0x1,0x2b,0x23,0x61,0x38,0x21,0x59, + 0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x45,0x2c,0xb0,0x38,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x46,0x2c,0xb0,0x39,0x2b,0x21,0x23,0x20,0x20,0x3c, + 0xb0,0x4,0x23,0x42,0x23,0x38,0xb1,0x2e,0x1,0x14,0x2b,0xb0,0x4,0x43,0x2e,0xb0,0x2e,0x2b,0x2d,0xb0,0x47,0x2c,0xb0,0x0,0x15,0x20,0x47,0xb0,0x0,0x23, + 0x42,0xb2,0x0,0x1,0x1,0x15,0x14,0x13,0x2e,0xb0,0x34,0x2a,0x2d,0xb0,0x48,0x2c,0xb0,0x0,0x15,0x20,0x47,0xb0,0x0,0x23,0x42,0xb2,0x0,0x1,0x1,0x15, + 0x14,0x13,0x2e,0xb0,0x34,0x2a,0x2d,0xb0,0x49,0x2c,0xb1,0x0,0x1,0x14,0x13,0xb0,0x35,0x2a,0x2d,0xb0,0x4a,0x2c,0xb0,0x37,0x2a,0x2d,0xb0,0x4b,0x2c,0xb0, + 0x0,0x16,0x45,0x23,0x20,0x2e,0x20,0x46,0x8a,0x23,0x61,0x38,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x4c,0x2c,0xb0,0x8,0x23,0x42,0xb0,0x4b,0x2b,0x2d,0xb0, + 0x4d,0x2c,0xb2,0x0,0x0,0x44,0x2b,0x2d,0xb0,0x4e,0x2c,0xb2,0x0,0x1,0x44,0x2b,0x2d,0xb0,0x4f,0x2c,0xb2,0x1,0x0,0x44,0x2b,0x2d,0xb0,0x50,0x2c,0xb2, + 0x1,0x1,0x44,0x2b,0x2d,0xb0,0x51,0x2c,0xb2,0x0,0x0,0x45,0x2b,0x2d,0xb0,0x52,0x2c,0xb2,0x0,0x1,0x45,0x2b,0x2d,0xb0,0x53,0x2c,0xb2,0x1,0x0,0x45, + 0x2b,0x2d,0xb0,0x54,0x2c,0xb2,0x1,0x1,0x45,0x2b,0x2d,0xb0,0x55,0x2c,0xb2,0x0,0x0,0x41,0x2b,0x2d,0xb0,0x56,0x2c,0xb2,0x0,0x1,0x41,0x2b,0x2d,0xb0, + 0x57,0x2c,0xb2,0x1,0x0,0x41,0x2b,0x2d,0xb0,0x58,0x2c,0xb2,0x1,0x1,0x41,0x2b,0x2d,0xb0,0x59,0x2c,0xb2,0x0,0x0,0x43,0x2b,0x2d,0xb0,0x5a,0x2c,0xb2, + 0x0,0x1,0x43,0x2b,0x2d,0xb0,0x5b,0x2c,0xb2,0x1,0x0,0x43,0x2b,0x2d,0xb0,0x5c,0x2c,0xb2,0x1,0x1,0x43,0x2b,0x2d,0xb0,0x5d,0x2c,0xb2,0x0,0x0,0x46, + 0x2b,0x2d,0xb0,0x5e,0x2c,0xb2,0x0,0x1,0x46,0x2b,0x2d,0xb0,0x5f,0x2c,0xb2,0x1,0x0,0x46,0x2b,0x2d,0xb0,0x60,0x2c,0xb2,0x1,0x1,0x46,0x2b,0x2d,0xb0, + 0x61,0x2c,0xb2,0x0,0x0,0x42,0x2b,0x2d,0xb0,0x62,0x2c,0xb2,0x0,0x1,0x42,0x2b,0x2d,0xb0,0x63,0x2c,0xb2,0x1,0x0,0x42,0x2b,0x2d,0xb0,0x64,0x2c,0xb2, + 0x1,0x1,0x42,0x2b,0x2d,0xb0,0x65,0x2c,0xb0,0x3a,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x66,0x2c,0xb0,0x3a,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0,0x67, + 0x2c,0xb0,0x3a,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x68,0x2c,0xb0,0x0,0x16,0xb0,0x3a,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x69,0x2c,0xb0,0x3b,0x2b,0x2e,0xb1,0x2e, + 0x1,0x14,0x2b,0x2d,0xb0,0x6a,0x2c,0xb0,0x3b,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0,0x6b,0x2c,0xb0,0x3b,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x6c,0x2c,0xb0,0x3b,0x2b, + 0xb0,0x40,0x2b,0x2d,0xb0,0x6d,0x2c,0xb0,0x3c,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x6e,0x2c,0xb0,0x3c,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0,0x6f,0x2c, + 0xb0,0x3c,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x70,0x2c,0xb0,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x71,0x2c,0xb0,0x3d,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d, + 0xb0,0x72,0x2c,0xb0,0x3d,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0,0x73,0x2c,0xb0,0x3d,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x74,0x2c,0xb0,0x3d,0x2b,0xb0,0x40,0x2b,0x2d, + 0xb0,0x75,0x2c,0xb3,0x9,0x4,0x2,0x3,0x45,0x58,0x21,0x1b,0x23,0x21,0x59,0x42,0x2b,0xb0,0x8,0x65,0xb0,0x3,0x24,0x50,0x78,0xb1,0x5,0x1,0x15,0x45, + 0x58,0x30,0x59,0x2d,0x0,0x0,0x0,0x4b,0xb8,0x0,0xc8,0x52,0x58,0xb1,0x1,0x1,0x8e,0x59,0xb0,0x1,0xb9,0x8,0x0,0x8,0x0,0x63,0x70,0xb1,0x0,0x7, + 0x42,0xb2,0x19,0x1,0x0,0x2a,0xb1,0x0,0x7,0x42,0xb3,0xc,0x8,0x1,0x8,0x2a,0xb1,0x0,0x7,0x42,0xb3,0x16,0x6,0x1,0x8,0x2a,0xb1,0x0,0x8,0x42, + 0xba,0x3,0x40,0x0,0x1,0x0,0x9,0x2a,0xb1,0x0,0x9,0x42,0xba,0x0,0x40,0x0,0x1,0x0,0x9,0x2a,0xb1,0x3,0x0,0x44,0xb1,0x24,0x1,0x88,0x51,0x58, + 0xb0,0x40,0x88,0x58,0xb1,0x3,0x64,0x44,0xb1,0x26,0x1,0x88,0x51,0x58,0xba,0x8,0x80,0x0,0x1,0x4,0x40,0x88,0x63,0x54,0x58,0xb1,0x3,0x0,0x44,0x59, + 0x59,0x59,0x59,0xb3,0xe,0x8,0x1,0xc,0x2a,0xb8,0x1,0xff,0x85,0xb0,0x4,0x8d,0xb1,0x2,0x0,0x44,0xb3,0x5,0x64,0x6,0x0,0x44,0x44,0x0,0x0,0x0, + 0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0 +}; + + +static const unsigned char courier_prime_code_italic[] = { + 0x0,0x1,0x0,0x0,0x0,0x10,0x1,0x0,0x0,0x4,0x0,0x0,0x44,0x53,0x49,0x47,0x0,0x0,0x0,0x1,0x0,0x1,0x2f,0x68,0x0,0x0,0x0,0x8,0x47,0x53, + 0x55,0x42,0xc9,0x7f,0xcd,0x51,0x0,0x0,0x1,0xc,0x0,0x0,0x5,0x90,0x4f,0x53,0x2f,0x32,0x71,0x19,0x89,0xb2,0x0,0x0,0x6,0x9c,0x0,0x0,0x0,0x60, + 0x63,0x6d,0x61,0x70,0xd7,0xce,0xb9,0xf9,0x0,0x0,0x6,0xfc,0x0,0x0,0x6,0x46,0x63,0x76,0x74,0x20,0x22,0xd5,0xfe,0xb1,0x0,0x1,0x22,0xb8,0x0,0x0, + 0x0,0x3c,0x66,0x70,0x67,0x6d,0x3f,0xae,0x1b,0x9f,0x0,0x1,0x22,0xf4,0x0,0x0,0xb,0xe2,0x67,0x61,0x73,0x70,0x0,0x0,0x0,0x10,0x0,0x1,0x22,0xb0, + 0x0,0x0,0x0,0x8,0x67,0x6c,0x79,0x66,0xc4,0x78,0x68,0xc5,0x0,0x0,0xd,0x44,0x0,0x0,0xca,0xce,0x68,0x65,0x61,0x64,0xc,0x51,0xe2,0x51,0x0,0x0, + 0xd8,0x14,0x0,0x0,0x0,0x36,0x68,0x68,0x65,0x61,0xc,0x71,0xf,0x79,0x0,0x0,0xd8,0x4c,0x0,0x0,0x0,0x24,0x68,0x6d,0x74,0x78,0x5e,0x3b,0xb,0xb9, + 0x0,0x0,0xd8,0x70,0x0,0x0,0x6,0x38,0x6c,0x6f,0x63,0x61,0xa6,0x2b,0xdc,0x25,0x0,0x0,0xde,0xa8,0x0,0x0,0x3,0x38,0x6d,0x61,0x78,0x70,0x2,0xde, + 0xc,0xf6,0x0,0x0,0xe1,0xe0,0x0,0x0,0x0,0x20,0x6e,0x61,0x6d,0x65,0x23,0xb0,0x4b,0xa,0x0,0x0,0xe2,0x0,0x0,0x0,0x37,0x6b,0x70,0x6f,0x73,0x74, + 0xae,0xbe,0xe9,0xb5,0x0,0x1,0x19,0x6c,0x0,0x0,0x9,0x44,0x70,0x72,0x65,0x70,0x19,0x50,0x2,0x10,0x0,0x1,0x2e,0xd8,0x0,0x0,0x0,0x8d,0x0,0x1, + 0x0,0x0,0x0,0xa,0x0,0xf2,0x2,0xf8,0x0,0x3,0x44,0x46,0x4c,0x54,0x0,0x14,0x67,0x72,0x65,0x6b,0x0,0x28,0x6c,0x61,0x74,0x6e,0x0,0x3c,0x0,0x4, + 0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x5,0x0,0x0,0x0,0x7,0x0,0xe,0x0,0x1d,0x0,0x24,0x0,0x4,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x5,0x0,0x1, + 0x0,0x8,0x0,0xf,0x0,0x1e,0x0,0x25,0x0,0x34,0x0,0x8,0x41,0x5a,0x45,0x20,0x0,0x44,0x43,0x41,0x54,0x20,0x0,0x4c,0x43,0x52,0x54,0x20,0x0,0x5e, + 0x4b,0x41,0x5a,0x20,0x0,0x66,0x4d,0x4f,0x4c,0x20,0x0,0x6e,0x52,0x4f,0x4d,0x20,0x0,0x80,0x54,0x41,0x54,0x20,0x0,0x92,0x54,0x52,0x4b,0x20,0x0,0x9a, + 0x0,0x0,0xff,0xff,0x0,0x5,0x0,0x2,0x0,0x9,0x0,0x10,0x0,0x1f,0x0,0x26,0x0,0x0,0xff,0xff,0x0,0x1,0x0,0x15,0x0,0x0,0xff,0xff,0x0,0x6, + 0x0,0x3,0x0,0xa,0x0,0x11,0x0,0x16,0x0,0x20,0x0,0x27,0x0,0x0,0xff,0xff,0x0,0x1,0x0,0x17,0x0,0x0,0xff,0xff,0x0,0x1,0x0,0x18,0x0,0x0, + 0xff,0xff,0x0,0x6,0x0,0x4,0x0,0xb,0x0,0x12,0x0,0x19,0x0,0x21,0x0,0x28,0x0,0x0,0xff,0xff,0x0,0x6,0x0,0x5,0x0,0xc,0x0,0x13,0x0,0x1a, + 0x0,0x22,0x0,0x29,0x0,0x0,0xff,0xff,0x0,0x1,0x0,0x1b,0x0,0x0,0xff,0xff,0x0,0x6,0x0,0x6,0x0,0xd,0x0,0x14,0x0,0x1c,0x0,0x23,0x0,0x2a, + 0x0,0x2b,0x61,0x61,0x6c,0x74,0x1,0x4,0x61,0x61,0x6c,0x74,0x1,0xa,0x61,0x61,0x6c,0x74,0x1,0x10,0x61,0x61,0x6c,0x74,0x1,0x16,0x61,0x61,0x6c,0x74, + 0x1,0x1c,0x61,0x61,0x6c,0x74,0x1,0x22,0x61,0x61,0x6c,0x74,0x1,0x28,0x63,0x61,0x73,0x65,0x1,0x2e,0x63,0x61,0x73,0x65,0x1,0x34,0x63,0x61,0x73,0x65, + 0x1,0x3a,0x63,0x61,0x73,0x65,0x1,0x40,0x63,0x61,0x73,0x65,0x1,0x46,0x63,0x61,0x73,0x65,0x1,0x4c,0x63,0x61,0x73,0x65,0x1,0x52,0x66,0x72,0x61,0x63, + 0x1,0x58,0x66,0x72,0x61,0x63,0x1,0x5e,0x66,0x72,0x61,0x63,0x1,0x64,0x66,0x72,0x61,0x63,0x1,0x6a,0x66,0x72,0x61,0x63,0x1,0x70,0x66,0x72,0x61,0x63, + 0x1,0x76,0x66,0x72,0x61,0x63,0x1,0x7c,0x6c,0x6f,0x63,0x6c,0x1,0x82,0x6c,0x6f,0x63,0x6c,0x1,0x88,0x6c,0x6f,0x63,0x6c,0x1,0x8e,0x6c,0x6f,0x63,0x6c, + 0x1,0x94,0x6c,0x6f,0x63,0x6c,0x1,0x9a,0x6c,0x6f,0x63,0x6c,0x1,0xa0,0x6c,0x6f,0x63,0x6c,0x1,0xa6,0x6c,0x6f,0x63,0x6c,0x1,0xac,0x6f,0x72,0x64,0x6e, + 0x1,0xb2,0x6f,0x72,0x64,0x6e,0x1,0xb8,0x6f,0x72,0x64,0x6e,0x1,0xbe,0x6f,0x72,0x64,0x6e,0x1,0xc4,0x6f,0x72,0x64,0x6e,0x1,0xca,0x6f,0x72,0x64,0x6e, + 0x1,0xd0,0x6f,0x72,0x64,0x6e,0x1,0xd6,0x73,0x75,0x70,0x73,0x1,0xdc,0x73,0x75,0x70,0x73,0x1,0xe2,0x73,0x75,0x70,0x73,0x1,0xe8,0x73,0x75,0x70,0x73, + 0x1,0xee,0x73,0x75,0x70,0x73,0x1,0xf4,0x73,0x75,0x70,0x73,0x1,0xfa,0x73,0x75,0x70,0x73,0x2,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1, + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1, + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0xc,0x0,0x0,0x0,0x1,0x0,0xc,0x0,0x0,0x0,0x1,0x0,0xc,0x0,0x0,0x0,0x1,0x0,0xc,0x0,0x0,0x0,0x1, + 0x0,0xc,0x0,0x0,0x0,0x1,0x0,0xc,0x0,0x0,0x0,0x1,0x0,0xc,0x0,0x0,0x0,0x1,0x0,0xa,0x0,0x0,0x0,0x1,0x0,0xa,0x0,0x0,0x0,0x1, + 0x0,0xa,0x0,0x0,0x0,0x1,0x0,0xa,0x0,0x0,0x0,0x1,0x0,0xa,0x0,0x0,0x0,0x1,0x0,0xa,0x0,0x0,0x0,0x1,0x0,0xa,0x0,0x0,0x0,0x1, + 0x0,0x8,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x7,0x0,0x0,0x0,0x1,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x3,0x0,0x0,0x0,0x1, + 0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x6,0x0,0x0,0x0,0x1,0x0,0xb,0x0,0x0,0x0,0x1,0x0,0xb,0x0,0x0,0x0,0x1, + 0x0,0xb,0x0,0x0,0x0,0x1,0x0,0xb,0x0,0x0,0x0,0x1,0x0,0xb,0x0,0x0,0x0,0x1,0x0,0xb,0x0,0x0,0x0,0x1,0x0,0xb,0x0,0x0,0x0,0x1, + 0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x9,0x0,0x0,0x0,0x1, + 0x0,0x9,0x0,0x0,0x0,0x1,0x0,0x9,0x0,0xf,0x0,0x20,0x0,0x28,0x0,0x32,0x0,0x3a,0x0,0x42,0x0,0x4a,0x0,0x52,0x0,0x5a,0x0,0x62,0x0,0x6a, + 0x0,0x72,0x0,0x7a,0x0,0x84,0x0,0x8c,0x0,0x94,0x0,0x1,0x0,0x0,0x0,0x1,0x1,0x56,0x0,0x6,0x0,0x0,0x0,0x2,0x0,0x74,0x0,0x88,0x0,0x1, + 0x0,0x0,0x0,0x1,0x0,0x92,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x98,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x9e,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x9c, + 0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x9a,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x98,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x96,0x0,0x1,0x0,0x0,0x0,0x1, + 0x0,0x94,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x92,0x0,0x6,0x0,0x0,0x0,0x2,0x0,0xb6,0x0,0xc8,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0xd0,0x0,0x4, + 0x0,0x0,0x0,0x1,0x1,0x26,0x0,0x1,0x0,0x0,0x0,0x1,0x1,0x3c,0x0,0x3,0x0,0x0,0x0,0x2,0x1,0x42,0x1,0x48,0x0,0x1,0x1,0x42,0x0,0x1, + 0x0,0x0,0x0,0xd,0x0,0x3,0x0,0x0,0x0,0x2,0x1,0x3a,0x1,0x34,0x0,0x1,0x1,0x3a,0x0,0x1,0x0,0x0,0x0,0xd,0x0,0x2,0x1,0x2c,0x0,0x4, + 0x0,0x5e,0x0,0x63,0x0,0xdd,0x0,0xe3,0x0,0x2,0x1,0x1e,0x0,0x4,0x0,0x5e,0x0,0x63,0x0,0xdd,0x0,0xe3,0x0,0x1,0x1,0x1c,0x0,0x6,0x0,0x1, + 0x1,0x16,0x0,0x6,0x0,0x1,0x1,0x10,0x0,0x6,0x0,0x1,0x1,0xa,0x0,0x6,0x0,0x1,0x1,0x4,0x0,0x6,0x0,0x1,0x1,0x4,0x0,0xd,0x0,0x1, + 0x1,0x8,0x0,0x2,0x0,0xa,0x0,0x20,0x0,0x2,0x0,0x6,0x0,0xe,0x1,0x12,0x0,0x3,0x1,0x32,0x1,0x9,0x1,0x13,0x0,0x3,0x1,0x32,0x1,0xb, + 0x0,0x1,0x0,0x4,0x1,0x14,0x0,0x3,0x1,0x32,0x1,0xb,0x0,0x3,0x0,0x1,0x0,0xe4,0x0,0x1,0x0,0xee,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xe, + 0x0,0x3,0x0,0x1,0x0,0xd2,0x0,0x1,0x0,0xe4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xe,0x0,0x2,0x0,0xda,0x0,0xe,0x1,0x7f,0x1,0x84,0x1,0x85, + 0x1,0x86,0x1,0x87,0x1,0x88,0x1,0x89,0x1,0x8a,0x1,0x8b,0x1,0x8c,0x1,0x8d,0x1,0x8e,0x1,0x8f,0x1,0x90,0x0,0x2,0x0,0xd4,0x0,0x1b,0x1,0x1, + 0x1,0x2,0x0,0x5e,0x0,0x63,0x1,0x1,0x0,0xae,0x1,0x2,0x0,0xdd,0x0,0xe3,0x1,0x15,0x1,0x16,0x1,0x17,0x1,0x18,0x1,0x7f,0x1,0x84,0x1,0x85, + 0x1,0x86,0x1,0x87,0x1,0x88,0x1,0x89,0x1,0x8a,0x1,0x8b,0x1,0x8c,0x1,0x8d,0x1,0x8e,0x1,0x8f,0x1,0x90,0x0,0x1,0x0,0xd2,0x0,0x2,0x0,0xa, + 0x0,0x14,0x0,0x1,0x0,0x4,0x0,0x3e,0x0,0x2,0x1,0x24,0x0,0x1,0x0,0x4,0x0,0xbd,0x0,0x2,0x1,0x24,0x0,0x2,0x0,0xbc,0x0,0x4,0x1,0x1, + 0x1,0x2,0x1,0x1,0x1,0x2,0x0,0x1,0x0,0x1,0x0,0xb9,0x0,0x1,0x0,0x1,0x1,0x24,0x0,0x1,0x0,0x1,0x0,0x3a,0x0,0x1,0x0,0x4,0x0,0x5c, + 0x0,0x62,0x0,0xdb,0x0,0xe2,0x0,0x1,0x0,0x1,0x0,0xa8,0x0,0x2,0x0,0x1,0x1,0x8,0x1,0xb,0x0,0x0,0x0,0x1,0x0,0x2,0x1,0x8,0x1,0xa, + 0x0,0x2,0x0,0x1,0x1,0x7,0x1,0x10,0x0,0x0,0x0,0x1,0x0,0x2,0x0,0x2,0x0,0x7f,0x0,0x1,0x0,0x2,0x0,0x47,0x0,0xc6,0x0,0x2,0x0,0x4, + 0x1,0x7e,0x1,0x7e,0x0,0x0,0x1,0x80,0x1,0x80,0x0,0x1,0x1,0x82,0x1,0x83,0x0,0x2,0x1,0x91,0x1,0x9a,0x0,0x4,0x0,0x1,0x0,0x1b,0x0,0x2, + 0x0,0x47,0x0,0x5c,0x0,0x62,0x0,0x7f,0x0,0xa8,0x0,0xc6,0x0,0xdb,0x0,0xe2,0x1,0x8,0x1,0x9,0x1,0xa,0x1,0xb,0x1,0x7e,0x1,0x80,0x1,0x82, + 0x1,0x83,0x1,0x91,0x1,0x92,0x1,0x93,0x1,0x94,0x1,0x95,0x1,0x96,0x1,0x97,0x1,0x98,0x1,0x99,0x1,0x9a,0x0,0x1,0x0,0x2,0x0,0x3a,0x0,0xb9, + 0x0,0x1,0x0,0x4,0x0,0x2,0x0,0x47,0x0,0x7f,0x0,0xc6,0x0,0x3,0x4,0xe0,0x1,0x90,0x0,0x5,0x0,0x8,0x5,0x33,0x4,0xcc,0xff,0xe5,0x0,0x99, + 0x5,0x33,0x4,0xcc,0x0,0x7e,0x2,0xcc,0x0,0x82,0x2,0x2a,0x0,0x0,0x0,0x0,0x5,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x7,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x51,0x55,0x51,0x41,0x0,0x1,0x0,0x20,0xfb,0x2,0x5,0x8d,0xfd,0x7d,0x0,0xc2,0x7,0x5,0x3,0x47, + 0x20,0x0,0x0,0x93,0x0,0x0,0x0,0x0,0x3,0x9c,0x4,0xa3,0x0,0x0,0x0,0x20,0x0,0x3,0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x3,0x0,0x0,0x2,0x14, + 0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1c,0x0,0x3,0x0,0x1,0x0,0x0,0x2,0x14,0x0,0x6,0x1,0xf8,0x0,0x0,0x0,0x9,0x0,0xf7,0x0,0x1,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x1,0x29,0x1,0x2f,0x1,0x2b,0x1,0x51,0x1,0x67,0x1,0x72,0x1,0x30,0x1,0x38, + 0x1,0x39,0x1,0x22,0x1,0x69,0x1,0x27,0x1,0x41,0x1,0x2c,0x1,0x32,0x1,0x7,0x1,0x8,0x1,0x9,0x1,0xa,0x1,0xb,0x1,0xc,0x1,0xd,0x1,0xe, + 0x1,0xf,0x1,0x10,0x1,0x26,0x1,0x31,0x1,0x60,0x1,0x5b,0x1,0x5c,0x1,0x2d,0x1,0x71,0x0,0x2,0x0,0xd,0x0,0xe,0x0,0x14,0x0,0x18,0x0,0x22, + 0x0,0x23,0x0,0x28,0x0,0x2b,0x0,0x36,0x0,0x38,0x0,0x3a,0x0,0x40,0x0,0x41,0x0,0x47,0x0,0x52,0x0,0x54,0x0,0x55,0x0,0x59,0x0,0x5f,0x0,0x64, + 0x0,0x6f,0x0,0x70,0x0,0x75,0x0,0x76,0x0,0x7b,0x1,0x36,0x1,0x23,0x1,0x37,0x1,0x79,0x1,0x33,0x1,0x95,0x0,0x7f,0x0,0x8a,0x0,0x8b,0x0,0x91, + 0x0,0x95,0x0,0x9f,0x0,0xa0,0x0,0xa5,0x0,0xa8,0x0,0xb4,0x0,0xb7,0x0,0xb9,0x0,0xbf,0x0,0xc0,0x0,0xc6,0x0,0xd1,0x0,0xd3,0x0,0xd4,0x0,0xd8, + 0x0,0xdf,0x0,0xe4,0x0,0xef,0x0,0xf0,0x0,0xf5,0x0,0xf6,0x0,0xfb,0x1,0x34,0x1,0x6f,0x1,0x35,0x1,0x59,0x0,0x0,0x0,0x6,0x0,0xa,0x0,0x11, + 0x0,0x19,0x0,0x46,0x0,0x4b,0x0,0x68,0x0,0x80,0x0,0x84,0x0,0x82,0x0,0x83,0x0,0x88,0x0,0x87,0x0,0x8e,0x0,0x96,0x0,0x9c,0x0,0x99,0x0,0x9a, + 0x0,0xaa,0x0,0xaf,0x0,0xac,0x0,0xad,0x0,0xc5,0x0,0xc7,0x0,0xcb,0x0,0xc9,0x0,0xca,0x0,0xcf,0x0,0xe5,0x0,0xe9,0x0,0xe7,0x0,0xe8,0x1,0x7a, + 0x1,0x78,0x1,0x4f,0x1,0x55,0x1,0x76,0x1,0x25,0x1,0x73,0x0,0xde,0x1,0x75,0x1,0x74,0x1,0x77,0x1,0x80,0x1,0x93,0x1,0x65,0x0,0xc,0x0,0x4f, + 0x1,0x5e,0x1,0x6a,0x1,0x61,0x1,0x5d,0x1,0x57,0x0,0x0,0x1,0x66,0x1,0x6d,0x1,0x6b,0x1,0x6,0x1,0x5f,0x1,0x1,0x1,0x2,0x1,0x4,0x0,0x89, + 0x0,0xce,0x1,0x2e,0x1,0x2a,0x1,0x62,0x1,0x6c,0x1,0x53,0x1,0x58,0x0,0x0,0x1,0x44,0x1,0x45,0x1,0x28,0x1,0x4e,0x0,0x7,0x0,0xb,0x0,0x50, + 0x0,0x51,0x0,0xd0,0x1,0x40,0x1,0x3f,0x1,0x49,0x1,0x4a,0x1,0x4b,0x1,0x4c,0x1,0x5a,0x1,0x6e,0x0,0xf9,0x0,0x79,0x1,0x11,0x1,0x52,0x1,0x46, + 0x1,0x47,0x0,0xff,0x1,0x0,0x1,0x7b,0x1,0x24,0x1,0x4d,0x1,0x48,0x1,0x68,0x0,0x5,0x0,0x1c,0x0,0x3,0x0,0x1d,0x0,0x1f,0x0,0x2d,0x0,0x2f, + 0x0,0x30,0x0,0x32,0x0,0x48,0x0,0x4a,0x0,0x0,0x0,0x4c,0x0,0x65,0x0,0x67,0x0,0x69,0x0,0xa9,0x1,0x92,0x1,0x9a,0x1,0x97,0x1,0x82,0x1,0x94, + 0x1,0x99,0x1,0x91,0x1,0x96,0x1,0x98,0x1,0x83,0x0,0x4,0x4,0x32,0x0,0x0,0x0,0x5a,0x0,0x40,0x0,0x5,0x0,0x1a,0x0,0x2f,0x0,0x7e,0x0,0xb4, + 0x1,0x37,0x1,0x48,0x1,0x7e,0x1,0x92,0x2,0x1b,0x2,0x37,0x2,0xc7,0x2,0xdd,0x3,0x26,0x3,0x94,0x3,0xa9,0x3,0xbc,0x3,0xc0,0x1e,0x85,0x1e,0xf3, + 0x20,0x11,0x20,0x14,0x20,0x1a,0x20,0x1e,0x20,0x22,0x20,0x26,0x20,0x30,0x20,0x33,0x20,0x3a,0x20,0x44,0x20,0x74,0x20,0xa3,0x20,0xa9,0x20,0xac,0x21,0x22, + 0x22,0x2,0x22,0xf,0x22,0x12,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60,0x22,0x65,0x25,0xca,0xfb,0x2,0xff,0xff,0x0,0x0,0x0,0x20,0x0,0x30, + 0x0,0xa0,0x0,0xb6,0x1,0x39,0x1,0x4a,0x1,0x92,0x2,0x18,0x2,0x37,0x2,0xc6,0x2,0xd8,0x3,0x26,0x3,0x94,0x3,0xa9,0x3,0xbc,0x3,0xc0,0x1e,0x80, + 0x1e,0xf2,0x20,0x11,0x20,0x13,0x20,0x18,0x20,0x1c,0x20,0x20,0x20,0x26,0x20,0x30,0x20,0x32,0x20,0x39,0x20,0x44,0x20,0x74,0x20,0xa3,0x20,0xa9,0x20,0xac, + 0x21,0x22,0x22,0x2,0x22,0xf,0x22,0x11,0x22,0x1a,0x22,0x1e,0x22,0x2b,0x22,0x48,0x22,0x60,0x22,0x64,0x25,0xca,0xfb,0x1,0xff,0xff,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0xc1,0x0,0x0,0xfe,0x7e,0x0,0x0,0x0,0x0,0xfe,0x58,0xfd,0x6f,0xfd,0x5b,0xfd,0x49,0xfd,0x46,0x0,0x0, + 0x0,0x0,0xe1,0x31,0x0,0x0,0xe1,0x33,0x0,0x0,0x0,0x0,0xe1,0x2,0xe1,0x38,0xe1,0x4a,0xe1,0xd,0xe0,0xcd,0xe0,0xa4,0xe0,0xb1,0xe0,0xad,0xe0,0xa6, + 0xe0,0x55,0xdf,0x64,0xdf,0x5c,0x0,0x0,0xdf,0x52,0xdf,0x40,0xdf,0x34,0xdf,0x10,0xdf,0x5,0x0,0x0,0xdb,0xa4,0x0,0x0,0x0,0x1,0x0,0x5a,0x0,0x78, + 0x1,0x14,0x1,0x3c,0x2,0x3e,0x2,0x5c,0x0,0x0,0x2,0xc2,0x0,0x0,0x2,0xc6,0x2,0xc8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0xc8, + 0x2,0xd2,0x0,0x0,0x2,0xd2,0x0,0x0,0x2,0xd2,0x2,0xd6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x2,0xc2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0xba,0x0,0x0,0x2,0xba,0x0,0x0,0x0,0x1,0x1,0x29, + 0x1,0x2f,0x1,0x2b,0x1,0x51,0x1,0x67,0x1,0x72,0x1,0x30,0x1,0x38,0x1,0x39,0x1,0x22,0x1,0x69,0x1,0x27,0x1,0x41,0x1,0x2c,0x1,0x32,0x1,0x7, + 0x1,0x8,0x1,0x9,0x1,0xa,0x1,0xb,0x1,0xc,0x1,0xd,0x1,0xe,0x1,0xf,0x1,0x10,0x1,0x26,0x1,0x31,0x1,0x60,0x1,0x5b,0x1,0x5c,0x1,0x2d, + 0x1,0x71,0x0,0x2,0x0,0xd,0x0,0xe,0x0,0x14,0x0,0x18,0x0,0x22,0x0,0x23,0x0,0x28,0x0,0x2b,0x0,0x36,0x0,0x38,0x0,0x3a,0x0,0x40,0x0,0x41, + 0x0,0x47,0x0,0x52,0x0,0x54,0x0,0x55,0x0,0x59,0x0,0x5f,0x0,0x64,0x0,0x6f,0x0,0x70,0x0,0x75,0x0,0x76,0x0,0x7b,0x1,0x36,0x1,0x23,0x1,0x37, + 0x1,0x79,0x1,0x33,0x1,0x95,0x0,0x7f,0x0,0x8a,0x0,0x8b,0x0,0x91,0x0,0x95,0x0,0x9f,0x0,0xa0,0x0,0xa5,0x0,0xa8,0x0,0xb4,0x0,0xb7,0x0,0xb9, + 0x0,0xbf,0x0,0xc0,0x0,0xc6,0x0,0xd1,0x0,0xd3,0x0,0xd4,0x0,0xd8,0x0,0xdf,0x0,0xe4,0x0,0xef,0x0,0xf0,0x0,0xf5,0x0,0xf6,0x0,0xfb,0x1,0x34, + 0x1,0x6f,0x1,0x35,0x1,0x59,0x1,0x4e,0x1,0x2a,0x1,0x4f,0x1,0x55,0x1,0x50,0x1,0x57,0x1,0x70,0x1,0x76,0x1,0x93,0x1,0x74,0x1,0x1,0x1,0x44, + 0x1,0x62,0x1,0x43,0x1,0x75,0x1,0x97,0x1,0x78,0x1,0x6a,0x1,0x16,0x1,0x17,0x1,0x80,0x1,0x73,0x1,0x24,0x1,0x91,0x1,0x15,0x1,0x2,0x1,0x45, + 0x1,0x13,0x1,0x12,0x1,0x14,0x1,0x2e,0x0,0x7,0x0,0x3,0x0,0x5,0x0,0xb,0x0,0x6,0x0,0xa,0x0,0xc,0x0,0x11,0x0,0x1f,0x0,0x19,0x0,0x1c, + 0x0,0x1d,0x0,0x32,0x0,0x2d,0x0,0x2f,0x0,0x30,0x0,0x15,0x0,0x46,0x0,0x4c,0x0,0x48,0x0,0x4a,0x0,0x50,0x0,0x4b,0x1,0x64,0x0,0x4f,0x0,0x69, + 0x0,0x65,0x0,0x67,0x0,0x68,0x0,0x77,0x0,0x53,0x0,0xde,0x0,0x84,0x0,0x80,0x0,0x82,0x0,0x88,0x0,0x83,0x0,0x87,0x0,0x89,0x0,0x8e,0x0,0x9c, + 0x0,0x96,0x0,0x99,0x0,0x9a,0x0,0xaf,0x0,0xaa,0x0,0xac,0x0,0xad,0x0,0x92,0x0,0xc5,0x0,0xcb,0x0,0xc7,0x0,0xc9,0x0,0xcf,0x0,0xca,0x1,0x5a, + 0x0,0xce,0x0,0xe9,0x0,0xe5,0x0,0xe7,0x0,0xe8,0x0,0xf7,0x0,0xd2,0x0,0xf9,0x0,0x8,0x0,0x85,0x0,0x4,0x0,0x81,0x0,0x9,0x0,0x86,0x0,0xf, + 0x0,0x8c,0x0,0x12,0x0,0x8f,0x0,0x13,0x0,0x90,0x0,0x10,0x0,0x8d,0x0,0x16,0x0,0x93,0x0,0x17,0x0,0x94,0x0,0x20,0x0,0x9d,0x0,0x1a,0x0,0x97, + 0x0,0x1e,0x0,0x9b,0x0,0x21,0x0,0x9e,0x0,0x1b,0x0,0x98,0x0,0x25,0x0,0xa2,0x0,0x24,0x0,0xa1,0x0,0x27,0x0,0xa4,0x0,0x26,0x0,0xa3,0x0,0x2a, + 0x0,0xa7,0x0,0x29,0x0,0xa6,0x0,0x35,0x0,0xb3,0x0,0x33,0x0,0xb1,0x0,0x2e,0x0,0xab,0x0,0x34,0x0,0xb2,0x0,0x31,0x0,0xa9,0x0,0x2c,0x0,0xb0, + 0x0,0x37,0x0,0xb6,0x0,0x39,0x0,0xb8,0x0,0x3b,0x0,0xba,0x0,0x3d,0x0,0xbc,0x0,0x3c,0x0,0xbb,0x0,0x3e,0x0,0xbd,0x0,0x3f,0x0,0xbe,0x0,0x42, + 0x0,0xc1,0x0,0x44,0x0,0xc3,0x0,0x43,0x0,0xc2,0x0,0x45,0x0,0xc4,0x0,0x4e,0x0,0xcd,0x0,0x49,0x0,0xc8,0x0,0x4d,0x0,0xcc,0x0,0x51,0x0,0xd0, + 0x0,0x56,0x0,0xd5,0x0,0x58,0x0,0xd7,0x0,0x57,0x0,0xd6,0x0,0x5a,0x0,0xd9,0x0,0x5d,0x0,0xdc,0x0,0x5c,0x0,0xdb,0x0,0x5b,0x0,0xda,0x0,0x62, + 0x0,0xe2,0x0,0x61,0x0,0xe1,0x0,0x60,0x0,0xe0,0x0,0x6e,0x0,0xee,0x0,0x6b,0x0,0xeb,0x0,0x66,0x0,0xe6,0x0,0x6d,0x0,0xed,0x0,0x6a,0x0,0xea, + 0x0,0x6c,0x0,0xec,0x0,0x72,0x0,0xf2,0x0,0x78,0x0,0xf8,0x0,0x79,0x0,0x7c,0x0,0xfc,0x0,0x7e,0x0,0xfe,0x0,0x7d,0x0,0xfd,0x0,0x5e,0x0,0xdd, + 0x0,0x63,0x0,0xe3,0x1,0x92,0x1,0x83,0x1,0x82,0x1,0x94,0x1,0x99,0x1,0x98,0x1,0x9a,0x1,0x96,0x0,0x74,0x0,0xf4,0x0,0x71,0x0,0xf1,0x0,0x73, + 0x0,0xf3,0x0,0x7a,0x0,0xfa,0x1,0x40,0x1,0x3f,0x1,0x49,0x1,0x4a,0x1,0x48,0x1,0x7a,0x1,0x7b,0x1,0x25,0x1,0x6d,0x1,0x63,0x1,0x61,0x1,0x5d, + 0x0,0xff,0x1,0x0,0x0,0x0,0x0,0xa,0x0,0xd3,0xfd,0x7d,0x3,0xa0,0x6,0x55,0x0,0x3,0x0,0xf,0x0,0x15,0x0,0x19,0x0,0x23,0x0,0x29,0x0,0x35, + 0x0,0x39,0x0,0x3d,0x0,0x48,0x0,0x19,0x40,0x16,0x42,0x3e,0x3c,0x3a,0x37,0x36,0x33,0x2a,0x27,0x24,0x1f,0x1a,0x18,0x16,0x11,0x10,0x9,0x4,0x2,0x0, + 0xa,0x30,0x2b,0x1,0x21,0x11,0x21,0x5,0x15,0x33,0x15,0x23,0x15,0x21,0x35,0x23,0x35,0x33,0x35,0x1,0x15,0x21,0x35,0x23,0x35,0x7,0x23,0x35,0x33,0x7, + 0x15,0x33,0x15,0x23,0x15,0x33,0x35,0x33,0x35,0x7,0x15,0x21,0x15,0x21,0x35,0x3,0x15,0x33,0x35,0x33,0x15,0x23,0x35,0x23,0x11,0x21,0x11,0x1,0x11,0x21, + 0x11,0x7,0x23,0x35,0x33,0x5,0x15,0x33,0x7,0x15,0x21,0x35,0x23,0x37,0x33,0x35,0x3,0xa0,0xfd,0x33,0x2,0xcd,0xfd,0xdc,0x94,0x96,0x1,0x78,0x96,0x96, + 0xfe,0x88,0x1,0x78,0x96,0x4c,0x4b,0x4b,0x96,0x96,0x96,0xe2,0x96,0x4b,0xfe,0xd3,0x1,0x78,0xe2,0x4c,0x4b,0xe2,0x4b,0x1,0x78,0xfe,0x88,0x1,0x78,0x4b, + 0xe2,0xe2,0xfe,0xd3,0x9f,0x9f,0x1,0x78,0xe7,0x9e,0x49,0xfd,0x7d,0x8,0xd8,0x98,0x4a,0x54,0x4b,0x4b,0x54,0x4a,0xfe,0xdc,0xeb,0x4d,0x9e,0x9e,0x51,0xdb, + 0x4b,0x54,0x4b,0x9f,0x4b,0x88,0x96,0x4d,0xe3,0xfe,0xec,0x7f,0x34,0x6a,0xb5,0xff,0x0,0x1,0x0,0xfe,0x78,0xff,0x0,0x1,0x0,0xb5,0x6a,0xe9,0x4b,0x6a, + 0x4b,0x4b,0x6a,0x4b,0x0,0x0,0x0,0x2,0x0,0x29,0xff,0xf3,0x4,0x2d,0x4,0xb9,0x0,0x1d,0x0,0x21,0x0,0x29,0x40,0x26,0x20,0x1,0x4,0x3,0x1,0x1, + 0x0,0x1,0x2,0x4a,0x0,0x4,0x0,0x1,0x0,0x4,0x1,0x62,0x0,0x3,0x3,0x16,0x4b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x14,0x2a,0x12,0x13,0x25,0x5, + 0x7,0x19,0x2b,0x24,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x21,0x3,0x6,0x23,0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x32, + 0x16,0x17,0x13,0x1,0x21,0x3,0x23,0x4,0x2d,0x1d,0x24,0x14,0x8,0x1d,0x1a,0x5,0x37,0xfe,0x7,0xa4,0x16,0x24,0x12,0x1d,0x18,0x16,0xd,0x2,0x41,0x13, + 0x3a,0x2f,0x2f,0x2e,0x7,0xd3,0xfd,0x86,0x1,0x91,0x64,0x4,0x32,0xa,0x15,0x17,0x4,0x2,0x17,0x1c,0x1,0x21,0xfe,0xd2,0x29,0xd,0xb,0x18,0x10,0x11, + 0x17,0x4,0x1d,0x23,0x1e,0x1e,0x23,0xfb,0xc7,0x1,0x9b,0x2,0x39,0x0,0x0,0x0,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x8a,0x6,0x6c,0x0,0x22,0x0,0x2, + 0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x42,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x9e, + 0x6,0x5c,0x0,0x22,0x0,0x2,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x19,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0x29,0xff,0xf3,0x4,0x54,0x6,0x6e,0x0,0x22,0x0,0x2,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x17,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x68,0x6,0x36,0x0,0x22,0x0,0x2,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x1c,0x1,0xe,0x0,0x9, + 0xb1,0x2,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x2d,0x6,0x6c,0x0,0x22,0x0,0x2,0x0,0x0,0x1,0x7,0x1,0x95, + 0xff,0xf6,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x64,0x5,0xf0,0x0,0x22,0x0,0x2, + 0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x1a,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x29,0xfe,0x28,0x4,0x2d, + 0x4,0xb9,0x0,0x2e,0x0,0x31,0x0,0x6a,0x40,0xb,0x31,0x1,0x6,0x5,0x1e,0x5,0x2,0x4,0x3,0x2,0x4a,0x4b,0xb0,0x31,0x50,0x58,0x40,0x1c,0x0,0x6, + 0x0,0x3,0x4,0x6,0x3,0x62,0x1,0x1,0x0,0x0,0x2,0x0,0x2,0x5f,0x7,0x1,0x5,0x5,0x16,0x4b,0x0,0x4,0x4,0x17,0x4,0x4c,0x1b,0x40,0x23,0x0, + 0x1,0x4,0x0,0x4,0x1,0x0,0x70,0x0,0x6,0x0,0x3,0x4,0x6,0x3,0x62,0x0,0x0,0x0,0x2,0x0,0x2,0x5f,0x7,0x1,0x5,0x5,0x16,0x4b,0x0,0x4, + 0x4,0x17,0x4,0x4c,0x59,0x40,0x10,0x0,0x0,0x30,0x2f,0x0,0x2e,0x0,0x2d,0x12,0x16,0x26,0x21,0x2c,0x8,0x7,0x19,0x2b,0x0,0x16,0x17,0x13,0x16,0x15, + 0x14,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x3,0x21,0x3,0x6,0x23, + 0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x1,0x21,0x3,0x3,0x22,0x2e,0x7,0xd3,0x3,0xe,0x74,0x6e,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12, + 0x13,0x26,0x5e,0x2e,0x4f,0x56,0x7c,0x79,0x3a,0xfe,0x8,0xa4,0x16,0x24,0x12,0x1d,0x18,0x16,0xd,0x2,0x41,0x13,0x3a,0x2f,0xfe,0xbe,0x1,0x90,0x66,0x4, + 0xb9,0x1e,0x23,0xfb,0xc7,0xd,0xb,0x14,0xb,0x5b,0x8b,0x37,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x59,0xa7,0x57,0x1,0x29,0xfe, + 0xd2,0x29,0xd,0xb,0x18,0x10,0x11,0x17,0x4,0x1d,0x23,0x1e,0xfd,0x21,0x2,0x39,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x2d,0x7,0x5,0x0,0x22,0x0,0x2, + 0x0,0x0,0x1,0x7,0x1,0x99,0x0,0x16,0x0,0xf0,0x0,0x8,0xb1,0x2,0x2,0xb0,0xf0,0xb0,0x33,0x2b,0x0,0x0,0xff,0xff,0x0,0x29,0xff,0xf3,0x4,0x5c, + 0x6,0x15,0x0,0x22,0x0,0x2,0x0,0x0,0x1,0x7,0x1,0x9a,0x0,0x10,0x1,0x4,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0x0,0x2, + 0xff,0xd8,0xff,0xf3,0x4,0xff,0x4,0xa3,0x0,0x33,0x0,0x37,0x0,0x88,0x40,0x10,0x2,0x1,0x0,0x7,0xd,0x1,0x2,0x1,0x2c,0x21,0x18,0x3,0x4,0x3, + 0x3,0x4a,0x4b,0xb0,0x26,0x50,0x58,0x40,0x28,0x0,0x1,0x0,0x2,0x9,0x1,0x2,0x61,0x0,0x9,0x0,0x5,0x3,0x9,0x5,0x61,0x8,0x1,0x0,0x0,0x7, + 0x59,0xa,0x1,0x7,0x7,0xe,0x4b,0x0,0x3,0x3,0x4,0x5b,0x6,0x1,0x4,0x4,0xf,0x4,0x4c,0x1b,0x40,0x2c,0x0,0x1,0x0,0x2,0x9,0x1,0x2,0x61, + 0x0,0x9,0x0,0x5,0x3,0x9,0x5,0x61,0x8,0x1,0x0,0x0,0x7,0x59,0xa,0x1,0x7,0x7,0xe,0x4b,0x0,0x3,0x3,0x4,0x59,0x0,0x4,0x4,0xf,0x4b, + 0x0,0x6,0x6,0x17,0x6,0x4c,0x59,0x40,0x14,0x0,0x0,0x37,0x36,0x35,0x34,0x0,0x33,0x0,0x31,0x12,0x15,0x36,0x21,0x26,0x21,0x26,0xb,0x7,0x1b,0x2b, + 0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23, + 0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x3,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x21,0x5,0x23,0x1,0x33,0x4,0xe5,0x1a,0x3, + 0x7,0x23,0x22,0xfe,0x96,0x3f,0x1,0x3d,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0xc3,0x46,0x1,0x7e,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0x2d,0x1d,0x1b,0x2, + 0x35,0xfe,0xf6,0xc1,0x17,0x24,0x12,0x1d,0x2c,0xe,0x2,0x47,0x15,0x2e,0x22,0x2,0x38,0xfd,0xe7,0x14,0xfe,0xe1,0xd5,0x4,0xa3,0x16,0x18,0xb,0xf,0x27, + 0x21,0xfe,0x99,0x15,0x18,0xc,0xf,0x27,0x21,0xfe,0x74,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x19,0xe,0x8,0x1,0x2e,0xfe,0xaa,0x29,0xd,0x15,0x1c,0x11, + 0x19,0x4,0x4,0x25,0x1f,0x90,0xfd,0xef,0x0,0x0,0x0,0x3,0x0,0x90,0x0,0x0,0x4,0x46,0x4,0xa3,0x0,0x17,0x0,0x20,0x0,0x28,0x0,0x47,0x40,0x44, + 0x5,0x1,0x5,0x2,0x10,0x1,0x0,0x4,0x2,0x4a,0x0,0x2,0x8,0x1,0x5,0x4,0x2,0x5,0x61,0x7,0x1,0x3,0x3,0x1,0x59,0x6,0x1,0x1,0x1,0xe, + 0x4b,0x0,0x4,0x4,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x21,0x21,0x18,0x18,0x0,0x0,0x21,0x28,0x21,0x27,0x24,0x22,0x18,0x20,0x18,0x1f,0x1b,0x19, + 0x0,0x17,0x0,0x15,0x3b,0x9,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x36, + 0x36,0x33,0x21,0x5,0x3,0x21,0x32,0x36,0x35,0x34,0x26,0x23,0x1,0x3,0x21,0x32,0x36,0x35,0x34,0x23,0x3,0xa5,0xa1,0x5f,0x5a,0x4c,0x51,0x61,0xc4,0x8f, + 0xfe,0x52,0x1d,0x1b,0x2,0xba,0x7,0x20,0x22,0x1,0x74,0xfe,0xcb,0x40,0x1,0xc,0x7f,0x8e,0x5c,0x66,0xfe,0x8f,0x44,0x1,0x36,0x87,0x9a,0xd0,0x4,0xa3, + 0x93,0x7e,0x6c,0x92,0x30,0x1d,0x80,0x59,0x64,0xa6,0x64,0x15,0x19,0xe,0x8,0x4,0x1b,0x26,0x1e,0x90,0xfe,0x90,0x79,0x65,0x4a,0x48,0xfe,0x0,0xfe,0x7d, + 0x74,0x6c,0xa3,0x0,0x0,0x1,0x0,0xaa,0xff,0xea,0x4,0x97,0x4,0xb9,0x0,0x28,0x0,0x36,0x40,0x33,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x0,0x3, + 0x2,0x1,0x3,0x2,0x6e,0x0,0x1,0x1,0x5,0x5b,0x6,0x1,0x5,0x5,0x16,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x0,0x0,0x0, + 0x28,0x0,0x27,0x26,0x23,0x25,0x24,0x16,0x7,0x7,0x19,0x2b,0x0,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x2,0x15,0x14, + 0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0x3,0xd4,0x9f,0x24,0xe,0x17,0x23, + 0x11,0xe,0x3b,0x95,0x4b,0x8a,0xd4,0x73,0x9a,0x88,0x54,0xa5,0x47,0xe,0x12,0x22,0x17,0xe,0x24,0xbd,0xd1,0x85,0xc4,0x68,0x9d,0x1,0x1f,0xba,0x4,0xb9, + 0x5d,0x15,0x20,0x14,0x1c,0x2d,0xa,0x28,0x29,0xad,0xfe,0xeb,0x96,0x9e,0xb1,0x32,0x2e,0xa,0x2d,0x1c,0x14,0x20,0x15,0x6c,0x75,0xd7,0x8f,0xc4,0x1,0x5c, + 0xd4,0x0,0x0,0x0,0xff,0xff,0x0,0xaa,0xff,0xea,0x4,0x97,0x6,0x6c,0x0,0x22,0x0,0xe,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x3c,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaa,0xff,0xea,0x4,0xa8,0x6,0x72,0x0,0x22,0x0,0xe,0x0,0x0,0x1,0x7,0x1,0x83, + 0x0,0x46,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xaa,0xfe,0x28,0x4,0x97,0x4,0xb9,0x0,0x4b,0x0,0x58, + 0x40,0x55,0x41,0x1,0x4,0x2,0x3e,0x1,0x9,0x5,0x2,0x4a,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x0,0x3,0x2,0x1,0x3,0x2,0x6e,0x0,0x7,0x9, + 0x8,0x9,0x7,0x8,0x70,0x0,0x5,0x0,0x9,0x7,0x5,0x9,0x63,0x0,0x8,0x0,0x6,0x8,0x6,0x5f,0x0,0x1,0x1,0xa,0x5b,0x0,0xa,0xa,0x16,0x4b, + 0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x4a,0x48,0x3d,0x3a,0x23,0x28,0x26,0x11,0x16,0x23,0x25,0x24,0x14,0xb,0x7,0x1d,0x2b,0x0,0x15, + 0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x7,0x7, + 0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x23,0x7,0x22, + 0x35,0x34,0x37,0x37,0x2e,0x2,0x35,0x34,0x12,0x24,0x33,0x32,0x17,0x4,0x97,0xe,0x17,0x23,0x11,0xe,0x3b,0x95,0x4b,0x8a,0xd4,0x73,0x9a,0x88,0x54,0xa5, + 0x47,0xe,0x12,0x22,0x17,0xe,0x24,0xab,0xbf,0x10,0x58,0x5a,0x1c,0x1a,0x45,0x97,0x44,0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64,0x31,0x3a, + 0x3a,0x67,0x23,0x1d,0x1,0x1c,0x69,0x97,0x50,0x9d,0x1,0x1f,0xba,0xb4,0x9f,0x4,0x47,0x20,0x14,0x1c,0x2d,0xa,0x28,0x29,0xad,0xfe,0xeb,0x96,0x9e,0xb1, + 0x32,0x2e,0xa,0x2d,0x1c,0x14,0x20,0x15,0x62,0x9,0x5d,0x2,0x52,0x40,0x22,0x4f,0x1b,0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15,0x2,0xf,0x13,0x2d, + 0x24,0x37,0x1,0x1c,0x9,0x5,0xa2,0x14,0x7d,0xc4,0x7d,0xc4,0x1,0x5c,0xd4,0x5d,0xff,0xff,0x0,0xaa,0xff,0xea,0x4,0x97,0x6,0x6e,0x0,0x22,0x0,0xe, + 0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x5a,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xaa,0xff,0xea,0x4,0x97, + 0x6,0x5f,0x0,0x22,0x0,0xe,0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x46,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x2, + 0x0,0x72,0x0,0x0,0x4,0x7a,0x4,0xa3,0x0,0x14,0x0,0x20,0x0,0x32,0x40,0x2f,0xd,0x1,0x0,0x2,0x1,0x4a,0x5,0x1,0x3,0x3,0x1,0x59,0x4,0x1, + 0x1,0x1,0xe,0x4b,0x0,0x2,0x2,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x15,0x15,0x0,0x0,0x15,0x20,0x15,0x1f,0x18,0x16,0x0,0x14,0x0,0x12,0x38, + 0x6,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21,0x5,0x3,0x33,0x32,0x36, + 0x37,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x45,0xc9,0x6c,0x54,0x56,0x4f,0xe2,0x95,0xfe,0xa0,0x1d,0x1b,0x2,0xba,0x7,0x20,0x22,0x1,0x46,0xfe,0xf9,0x9e, + 0xe6,0x75,0xb0,0x3d,0x41,0x40,0xab,0x9a,0x4,0xa3,0x70,0xd1,0x8e,0x7f,0xfe,0xeb,0x6b,0x63,0x72,0x15,0x19,0xe,0x8,0x4,0x1b,0x26,0x1e,0x90,0xfc,0x7d, + 0x5a,0x4f,0x54,0xda,0x68,0xa0,0xa4,0x0,0x0,0x2,0x0,0x54,0x0,0x0,0x4,0x7a,0x4,0xa3,0x0,0x1f,0x0,0x36,0x0,0x42,0x40,0x3f,0x2b,0x14,0x2,0x1, + 0x2,0xd,0x1,0x0,0x7,0x2,0x4a,0x5,0x1,0x2,0x6,0x1,0x1,0x7,0x2,0x1,0x63,0x0,0x4,0x4,0x3,0x59,0x8,0x1,0x3,0x3,0xe,0x4b,0x0,0x7, + 0x7,0x0,0x59,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x34,0x32,0x31,0x2f,0x29,0x27,0x26,0x24,0x0,0x1f,0x0,0x1d,0x26,0x25,0x38,0x9,0x7,0x17,0x2b, + 0x0,0x16,0x16,0x15,0x14,0x2,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x36,0x36, + 0x33,0x21,0x12,0x36,0x35,0x34,0x26,0x23,0x23,0x3,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x33,0x32,0x36,0x37,0x3,0x45,0xc9,0x6c,0x54, + 0x56,0x4f,0xe2,0x95,0xfe,0xd2,0x1d,0x1b,0x2,0x54,0x71,0x1b,0x1a,0x3,0x7,0x23,0x22,0x70,0x4d,0x7,0x20,0x22,0x1,0x14,0xe4,0x40,0xab,0x9a,0xb4,0x3f, + 0xdc,0x1b,0x1a,0x3,0x7,0x23,0x22,0xdb,0x46,0xb4,0x75,0xb0,0x3d,0x4,0xa3,0x70,0xd1,0x8e,0x7f,0xfe,0xeb,0x6b,0x63,0x72,0x15,0x19,0xe,0x8,0x1,0xd8, + 0x16,0x18,0xb,0xf,0x27,0x21,0x1,0xb3,0x26,0x1e,0xfc,0xea,0xda,0x68,0xa0,0xa4,0xfe,0x99,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0x74,0x5a,0x4f,0x0,0x0, + 0xff,0xff,0x0,0x72,0x0,0x0,0x4,0x7a,0x6,0x68,0x0,0x22,0x0,0x14,0x0,0x0,0x1,0x7,0x1,0x83,0xff,0xec,0x1,0x4,0x0,0x9,0xb1,0x2,0x1,0xb8, + 0x1,0x4,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x72,0x0,0x0,0x4,0x7a,0x5,0xf0,0x0,0x22,0x0,0x14,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x0,0x1,0xe, + 0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xa4,0x0,0x0,0x4,0x7d,0x4,0xa3,0x0,0x28,0x0,0x3e,0x40,0x3b,0x2,0x1, + 0x0,0x5,0xd,0x1,0x2,0x1,0x21,0x18,0x2,0x4,0x3,0x3,0x4a,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x0,0x0,0x0,0x5,0x59,0x6,0x1,0x5,0x5, + 0xe,0x4b,0x0,0x3,0x3,0x4,0x59,0x0,0x4,0x4,0xf,0x4,0x4c,0x0,0x0,0x0,0x28,0x0,0x26,0x36,0x21,0x26,0x21,0x26,0x7,0x7,0x19,0x2b,0x0,0x16, + 0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22, + 0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21,0x4,0x63,0x1a,0x3,0x7,0x23,0x22,0xfd,0xba,0x3f,0x1,0xc9,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0x37,0x46, + 0x2,0x5a,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfd,0x51,0x1d,0x1b,0x2,0xba,0x7,0x20,0x22,0x2,0x9f,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0x99,0x15, + 0x18,0xc,0xf,0x27,0x21,0xfe,0x74,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x19,0xe,0x8,0x4,0x1b,0x26,0x1e,0x0,0x0,0x0,0xff,0xff,0x0,0xa4,0x0,0x0, + 0x4,0x7d,0x6,0x6c,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x6,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0xa4,0x0,0x0,0x4,0xa3,0x6,0x5c,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa4,0x0,0x0,0x4,0x85,0x6,0x68,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x23,0x1,0x4, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa4,0x0,0x0,0x4,0x7d,0x6,0x6e,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7, + 0x1,0x92,0x0,0x30,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa4,0x0,0x0,0x4,0x7d,0x6,0x36,0x0,0x22, + 0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x30,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa4,0x0,0x0, + 0x4,0x7d,0x6,0x5f,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0, + 0xff,0xff,0x0,0xa4,0x0,0x0,0x4,0x7d,0x6,0x6c,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x95,0x0,0x3c,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa4,0x0,0x0,0x4,0x7d,0x5,0xf0,0x0,0x22,0x0,0x18,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x2e,0x1,0xe, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xa4,0xfe,0x28,0x4,0x7d,0x4,0xa3,0x0,0x40,0x0,0x86,0x40,0xf,0x2,0x1, + 0x0,0x9,0xd,0x1,0x2,0x1,0x39,0x18,0x2,0x4,0x3,0x3,0x4a,0x4b,0xb0,0x31,0x50,0x58,0x40,0x27,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x6,0x1, + 0x5,0x0,0x7,0x5,0x7,0x5f,0x0,0x0,0x0,0x9,0x59,0xa,0x1,0x9,0x9,0xe,0x4b,0x0,0x3,0x3,0x4,0x5b,0x8,0x1,0x4,0x4,0xf,0x4,0x4c,0x1b, + 0x40,0x2e,0x0,0x6,0x4,0x5,0x4,0x6,0x5,0x70,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x0,0x5,0x0,0x7,0x5,0x7,0x5f,0x0,0x0,0x0,0x9,0x59, + 0xa,0x1,0x9,0x9,0xe,0x4b,0x0,0x3,0x3,0x4,0x5b,0x8,0x1,0x4,0x4,0xf,0x4,0x4c,0x59,0x40,0x12,0x0,0x0,0x0,0x40,0x0,0x3e,0x25,0x26,0x21, + 0x26,0x16,0x21,0x26,0x21,0x26,0xb,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21, + 0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26, + 0x35,0x34,0x36,0x37,0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21,0x4,0x63,0x1a,0x3,0x7,0x23,0x22,0xfd,0xba,0x3f,0x1,0xc9,0x1b,0x1a,0x3, + 0x7,0x22,0x22,0xfe,0x37,0x46,0x2,0x5a,0x1b,0x1a,0x3,0x7,0x22,0x22,0x4,0x6f,0x69,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56, + 0x66,0x63,0xfe,0x0,0x1d,0x1b,0x2,0xba,0x7,0x20,0x22,0x2,0x9f,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0x99,0x15,0x18,0xc,0xf,0x27,0x21,0xfe, + 0x74,0x16,0x18,0xb,0xf,0x27,0x21,0x58,0x88,0x35,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x50,0x98,0x4e,0x15,0x19,0xe,0x8,0x4, + 0x1b,0x26,0x1e,0x0,0x0,0x0,0x0,0x1,0x0,0xb6,0xff,0xf6,0x4,0x91,0x4,0xa3,0x0,0x22,0x0,0x37,0x40,0x34,0x2,0x1,0x0,0x4,0xd,0x1,0x2,0x1, + 0x1b,0x1,0x3,0x2,0x3,0x4a,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x0,0x0,0x0,0x4,0x59,0x5,0x1,0x4,0x4,0xe,0x4b,0x0,0x3,0x3,0xf,0x3, + 0x4c,0x0,0x0,0x0,0x22,0x0,0x20,0x33,0x26,0x21,0x26,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14, + 0x7,0x6,0x6,0x23,0x21,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21,0x4,0x77,0x1a,0x3,0x7,0x23,0x22,0xfd,0xba,0x46, + 0x1,0xd3,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0x2c,0x4e,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xbc,0x7,0x20,0x22,0x2,0x9f,0x4,0xa3,0x16,0x18,0xb,0xf, + 0x27,0x21,0xfe,0x71,0x15,0x18,0xc,0xf,0x27,0x21,0xfe,0x43,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x28,0x26,0x1e,0x0,0x0,0x0,0x1,0x0,0x83,0xff,0xea, + 0x4,0x8f,0x4,0xb9,0x0,0x35,0x0,0x3f,0x40,0x3c,0x25,0x1c,0x2,0x3,0x4,0x1,0x4a,0x0,0x0,0x1,0x4,0x1,0x0,0x4,0x70,0x0,0x4,0x0,0x3,0x2, + 0x4,0x3,0x61,0x0,0x1,0x1,0x6,0x5b,0x7,0x1,0x6,0x6,0x16,0x4b,0x0,0x2,0x2,0x5,0x5b,0x0,0x5,0x5,0x17,0x5,0x4c,0x0,0x0,0x0,0x35,0x0, + 0x34,0x29,0x36,0x22,0x26,0x24,0x17,0x8,0x7,0x1a,0x2b,0x0,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x2,0x15,0x14, + 0x16,0x16,0x33,0x32,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x7,0x6,0x23,0x22,0x26,0x26, + 0x35,0x34,0x12,0x24,0x33,0x3,0x63,0xb8,0x50,0x24,0xe,0x17,0x22,0xe,0x12,0x41,0x9e,0x50,0x91,0xd7,0x71,0x47,0x86,0x5d,0xaf,0x86,0x2f,0xfe,0xf5,0x1b, + 0x1a,0x3,0x7,0x22,0x22,0x1,0x62,0x1c,0x19,0x2,0x45,0x5,0x18,0x13,0xb2,0xeb,0x86,0xc9,0x6d,0xa3,0x1,0x24,0xba,0x4,0xb9,0x2e,0x2e,0x15,0x20,0x14, + 0x1c,0x2d,0xa,0x27,0x29,0xb0,0xfe,0xed,0x91,0x69,0x99,0x51,0x39,0x1,0xb,0x15,0x18,0xc,0xf,0x27,0x21,0x14,0x18,0xf,0x9,0xfe,0x78,0x18,0x24,0x9, + 0x57,0x77,0xda,0x91,0xc2,0x1,0x59,0xd2,0xff,0xff,0x0,0x83,0xff,0xea,0x4,0xb7,0x6,0x5c,0x0,0x22,0x0,0x23,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x32, + 0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x83,0xff,0xea,0x4,0x8f,0x6,0x6e,0x0,0x22,0x0,0x23,0x0,0x0, + 0x1,0x7,0x1,0x92,0x0,0x3c,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x83,0xfd,0xf3,0x4,0x8f,0x4,0xb9, + 0x0,0x22,0x0,0x23,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xf4,0x0,0x0,0xff,0xff,0x0,0x83,0xff,0xea,0x4,0x8f,0x6,0x5f,0x0,0x22,0x0,0x23,0x0,0x0, + 0x1,0x7,0x1,0x94,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x70,0xff,0xf6,0x4,0xa0,0x4,0xad, + 0x0,0x2b,0x0,0x33,0x40,0x30,0x22,0x2,0x2,0x4,0x3,0x18,0xc,0x2,0x0,0x1,0x2,0x4a,0x0,0x4,0x0,0x1,0x0,0x4,0x1,0x62,0x6,0x5,0x2,0x3, + 0x3,0xe,0x4b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x2b,0x0,0x29,0x15,0x37,0x33,0x15,0x37,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7, + 0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15, + 0x14,0x7,0x3,0x21,0x13,0x36,0x36,0x33,0x33,0x4,0x82,0x1e,0x2,0xbe,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x56,0xfd,0xbe,0x56,0x6,0x27,0x28,0x2,0x23, + 0x1e,0x2,0xbe,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x4f,0x2,0x42,0x4f,0x6,0x27,0x28,0x2,0x4,0xad,0x15,0x18,0x4,0x10,0xfb,0xcb,0x23,0x1e,0x15,0x18, + 0x4,0x10,0x1,0xe5,0xfe,0x1b,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x35,0x23,0x1e,0x15,0x18,0x4,0x10,0xfe,0x40,0x1,0xc0,0x23,0x1e,0x0,0x0,0x0,0x2, + 0x0,0x70,0xff,0xf6,0x5,0xa,0x4,0xad,0x0,0x41,0x0,0x45,0x0,0x7d,0x40,0x11,0x3d,0x31,0x2,0x5,0x6,0x23,0x2,0x2,0x0,0x5,0x1c,0x10,0x2,0x1, + 0x2,0x3,0x4a,0x4b,0xb0,0x24,0x50,0x58,0x40,0x24,0x0,0xb,0x0,0x2,0x1,0xb,0x2,0x61,0x8,0x1,0x6,0x6,0xe,0x4b,0xa,0x4,0x2,0x0,0x0,0x5, + 0x5b,0xc,0x9,0x7,0x3,0x5,0x5,0x19,0x4b,0x3,0x1,0x1,0x1,0xf,0x1,0x4c,0x1b,0x40,0x22,0xc,0x9,0x7,0x3,0x5,0xa,0x4,0x2,0x0,0xb,0x5, + 0x0,0x64,0x0,0xb,0x0,0x2,0x1,0xb,0x2,0x61,0x8,0x1,0x6,0x6,0xe,0x4b,0x3,0x1,0x1,0x1,0xf,0x1,0x4c,0x59,0x40,0x16,0x0,0x0,0x45,0x44, + 0x43,0x42,0x0,0x41,0x0,0x40,0x33,0x15,0x33,0x26,0x25,0x33,0x15,0x33,0x26,0xd,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6, + 0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33, + 0x33,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x21,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x33,0x5,0x21,0x7,0x21,0x4, + 0xf0,0x1a,0x3,0x7,0x23,0x22,0x52,0x89,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x56,0xfd,0xbe,0x56,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x89,0x52,0x1b,0x1a, + 0x3,0x7,0x23,0x22,0x51,0x1c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x1c,0x2,0x42,0x1c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x1c,0x53,0xfe,0xfe,0xfd,0xbe, + 0x1a,0x2,0x42,0x3,0xce,0x16,0x18,0xb,0xf,0x27,0x21,0xfc,0xf9,0x23,0x1e,0x15,0x18,0x4,0x10,0x1,0xe5,0xfe,0x1b,0x23,0x1e,0x15,0x18,0x4,0x10,0x3, + 0x7,0x16,0x18,0xb,0xf,0x27,0x21,0x9e,0x23,0x1e,0x15,0x18,0x4,0x10,0x9e,0x9e,0x23,0x1e,0x15,0x18,0x4,0x10,0x9e,0x90,0x92,0x0,0xff,0xff,0x0,0x70, + 0xff,0xf6,0x4,0xa0,0x6,0x6e,0x0,0x22,0x0,0x28,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33, + 0x2b,0x0,0x0,0x1,0x0,0x96,0x0,0x0,0x4,0x67,0x4,0xa3,0x0,0x27,0x0,0x35,0x40,0x32,0x21,0x2,0x2,0x0,0x5,0x16,0xd,0x2,0x2,0x1,0x2,0x4a, + 0x4,0x1,0x0,0x0,0x5,0x59,0x6,0x1,0x5,0x5,0xe,0x4b,0x3,0x1,0x1,0x1,0x2,0x59,0x0,0x2,0x2,0xf,0x2,0x4c,0x0,0x0,0x0,0x27,0x0,0x25, + 0x21,0x26,0x36,0x21,0x26,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22, + 0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x4d,0x1a,0x3,0x7,0x23,0x22,0xf6,0x9e,0x1,0x1e, + 0x1b,0x1a,0x3,0x7,0x22,0x22,0xfd,0x42,0x1c,0x19,0x2,0x7,0x23,0x22,0x1,0xa,0x9e,0xfe,0xf6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0x96,0x4,0xa3,0x16, + 0x18,0xb,0xf,0x27,0x21,0xfc,0x7d,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x19,0xf,0xa,0x27,0x21,0x3,0x83,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x2, + 0x0,0x74,0xff,0xea,0x4,0xa1,0x4,0xad,0x0,0x13,0x0,0x31,0x0,0x6d,0x40,0xb,0x16,0x2,0x2,0x3,0x1,0xc,0x1,0x0,0x4,0x2,0x4a,0x4b,0xb0,0x28, + 0x50,0x58,0x40,0x1c,0x0,0x3,0x1,0x4,0x1,0x3,0x4,0x70,0x7,0x5,0x6,0x3,0x1,0x1,0xe,0x4b,0x0,0x4,0x4,0x0,0x5b,0x2,0x1,0x0,0x0,0xf, + 0x0,0x4c,0x1b,0x40,0x20,0x0,0x3,0x1,0x4,0x1,0x3,0x4,0x70,0x7,0x5,0x6,0x3,0x1,0x1,0xe,0x4b,0x0,0x0,0x0,0xf,0x4b,0x0,0x4,0x4,0x2, + 0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x59,0x40,0x16,0x14,0x14,0x0,0x0,0x14,0x31,0x14,0x2f,0x2a,0x28,0x24,0x23,0x1c,0x1a,0x0,0x13,0x0,0x11,0x37,0x8, + 0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x20,0x16,0x15,0x14,0x7,0x3,0x2, + 0x21,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x1,0xae,0x1e,0x2,0xbe,0x6,0x27, + 0x28,0x2,0x23,0x1e,0x2,0xbe,0x6,0x27,0x28,0x2,0x2,0xf8,0x1e,0x2,0x9b,0x31,0xfe,0xfe,0x37,0x7c,0x2c,0x21,0xc,0x16,0x20,0xc,0xe,0x26,0x5e,0x2d, + 0x3f,0x47,0xf,0x96,0x6,0x27,0x28,0x2,0x4,0xad,0x15,0x18,0x4,0x10,0xfb,0xcb,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x35,0x23,0x1e,0x15,0x18,0x4,0x10, + 0xfc,0x91,0xfe,0xed,0x1a,0x18,0x12,0x1f,0x14,0x1c,0x31,0x7,0x13,0x16,0x4a,0x53,0x3,0x51,0x23,0x1e,0x0,0x0,0xff,0xff,0x0,0x96,0x0,0x0,0x4,0x67, + 0x6,0x6c,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x10,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0x96,0x0,0x0,0x4,0x99,0x6,0x5c,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x14,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x96,0x0,0x0,0x4,0x67,0x6,0x6e,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x1c,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x96,0x0,0x0,0x4,0x68,0x6,0x36,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x93, + 0x0,0x1c,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x96,0x0,0x0,0x4,0x67,0x6,0x5f,0x0,0x22,0x0,0x2b, + 0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x96,0x0,0x0,0x4,0x67, + 0x6,0x6c,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x95,0x0,0x32,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0x96,0x0,0x0,0x4,0x67,0x5,0xf0,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x19,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x96,0xfe,0x28,0x4,0x67,0x4,0xa3,0x0,0x3f,0x0,0x77,0x40,0xc,0x39,0x2,0x2,0x0,0x9,0x2e,0xd,0x2,0x2,0x1, + 0x2,0x4a,0x4b,0xb0,0x31,0x50,0x58,0x40,0x21,0x4,0x1,0x3,0x0,0x5,0x3,0x5,0x5f,0x8,0x1,0x0,0x0,0x9,0x59,0xa,0x1,0x9,0x9,0xe,0x4b,0x7, + 0x1,0x1,0x1,0x2,0x59,0x6,0x1,0x2,0x2,0xf,0x2,0x4c,0x1b,0x40,0x28,0x0,0x4,0x2,0x3,0x2,0x4,0x3,0x70,0x0,0x3,0x0,0x5,0x3,0x5,0x5f, + 0x8,0x1,0x0,0x0,0x9,0x59,0xa,0x1,0x9,0x9,0xe,0x4b,0x7,0x1,0x1,0x1,0x2,0x59,0x6,0x1,0x2,0x2,0xf,0x2,0x4c,0x59,0x40,0x12,0x0,0x0, + 0x0,0x3f,0x0,0x3d,0x21,0x26,0x25,0x26,0x21,0x25,0x26,0x21,0x26,0xb,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x21,0x32,0x16, + 0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37, + 0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x4d,0x1a,0x3,0x7,0x23,0x22,0xf6,0x9e, + 0x1,0x1e,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0xe8,0x6f,0x69,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56,0x66,0x63,0xfb,0x1c,0x19, + 0x2,0x7,0x23,0x22,0x1,0xa,0x9e,0xfe,0xf6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0x96,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfc,0x7d,0x16,0x18,0xb, + 0xf,0x27,0x21,0x58,0x88,0x35,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x50,0x98,0x4e,0x16,0x19,0xf,0xa,0x27,0x21,0x3,0x83,0x16, + 0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0x96,0x0,0x0,0x4,0x67,0x6,0x15,0x0,0x22,0x0,0x2b,0x0,0x0,0x1,0x7,0x1,0x9a,0x0,0x14, + 0x1,0x4,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x90,0xff,0xea,0x4,0x3b,0x4,0xa3,0x0,0x24,0x0,0x35,0x40,0x32, + 0x1e,0x2,0x2,0x3,0x4,0x1,0x4a,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70,0x0,0x3,0x3,0x4,0x59,0x5,0x1,0x4,0x4,0xe,0x4b,0x0,0x2,0x2,0x0, + 0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x24,0x0,0x22,0x23,0x24,0x17,0x27,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23, + 0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x21, + 0x1a,0x3,0x8a,0x1e,0xda,0xb1,0x65,0xb6,0x40,0x1a,0x15,0x1b,0x1c,0xf,0x12,0x37,0x8b,0x4d,0x73,0x8b,0x14,0x77,0xfe,0x97,0x1b,0x1a,0x3,0x7,0x23,0x22, + 0x1,0xc0,0x4,0xa3,0x16,0x18,0xb,0xf,0xfc,0xf2,0xac,0xb7,0x3b,0x37,0x15,0x1a,0x19,0x1f,0x29,0xe,0x2e,0x32,0x79,0x74,0x2,0xa8,0x16,0x18,0xb,0xf, + 0x27,0x21,0xff,0xff,0x0,0x90,0xff,0xea,0x4,0xf1,0x6,0x6e,0x0,0x22,0x0,0x36,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0xb4,0x1,0xe,0x0,0x9,0xb1,0x1, + 0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x98,0xff,0xef,0x4,0xb1,0x4,0xb9,0x0,0x2a,0x0,0x3e,0x40,0xa,0x25,0x22,0x18,0xf,0x4,0x5, + 0x0,0x2,0x1,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0xd,0x3,0x1,0x2,0x2,0xe,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x11,0x0,0x3,0x3, + 0x16,0x4b,0x0,0x2,0x2,0xe,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x59,0xb6,0x27,0x37,0x36,0x2b,0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x1,0x1, + 0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x27,0x1,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14, + 0x7,0x3,0x1,0x36,0x33,0x32,0x17,0x4,0xb1,0x1a,0xfe,0x1b,0x1,0x4e,0xa,0x17,0x18,0x1d,0x17,0x1c,0xd,0xfe,0xbe,0xd5,0x37,0x6,0x27,0x28,0x2,0x23, + 0x1e,0x2,0xbe,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x5f,0x2,0x9b,0x14,0x18,0x1c,0x1d,0x4,0x8a,0x18,0x15,0x17,0xfe,0x4f,0xfd,0xc7,0x11,0x10,0x10,0x1d, + 0xe,0x11,0x17,0x2,0x25,0xbf,0xfe,0xcb,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x35,0x23,0x1e,0x15,0x18,0x4,0x10,0xfd,0xe7,0x2,0x54,0x12,0x16,0xff,0xff, + 0x0,0x98,0xfd,0xf3,0x4,0xb1,0x4,0xb9,0x0,0x22,0x0,0x38,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xee,0x0,0x0,0x0,0x1,0x0,0xb8,0x0,0x0,0x3,0xd9, + 0x4,0xad,0x0,0x19,0x0,0x2a,0x40,0x27,0x2,0x1,0x0,0x2,0x12,0x9,0x2,0x1,0x0,0x2,0x4a,0x3,0x1,0x2,0x2,0xe,0x4b,0x0,0x0,0x0,0x1,0x5a, + 0x0,0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x0,0x19,0x0,0x17,0x36,0x25,0x4,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x21,0x32,0x16,0x15,0x14,0x7, + 0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x1,0xf0,0x1e,0x2,0xae,0x2,0x46,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfd,0x65,0x1d, + 0x1b,0x2,0xbc,0x6,0x27,0x28,0x2,0x4,0xad,0x15,0x18,0x4,0x10,0xfc,0x24,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x19,0xe,0x8,0x4,0x28,0x23,0x1e,0x0, + 0xff,0xff,0x0,0xb8,0x0,0x0,0x3,0xd9,0x6,0x6c,0x0,0x22,0x0,0x3a,0x0,0x0,0x1,0x7,0x1,0x80,0xff,0x6a,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xb8,0x0,0x0,0x4,0x70,0x4,0xad,0x0,0x22,0x0,0x3a,0x0,0x0,0x1,0x7,0x1,0x81,0x1,0xb1,0xff,0x83, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0xff,0x83,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xb8,0xfd,0xf3,0x3,0xd9,0x4,0xad,0x0,0x22,0x0,0x3a,0x0,0x0,0x0,0x3, + 0x1,0x7e,0x4,0xe0,0x0,0x0,0xff,0xff,0x0,0xb8,0x0,0x0,0x3,0xd9,0x4,0xad,0x0,0x22,0x0,0x3a,0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x29,0xfe,0x2, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0xfe,0x2,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x4e,0x0,0x0,0x3,0xd9,0x4,0xad,0x0,0x2f,0x0,0x40,0x40,0x3d,0x20,0x1, + 0x3,0x2,0x23,0xe,0x2,0x1,0x3,0xb,0x2,0x2,0x0,0x4,0x3,0x4a,0x0,0x3,0x2,0x1,0x2,0x3,0x1,0x70,0x0,0x1,0x4,0x2,0x1,0x4,0x6e,0x0, + 0x2,0x2,0xe,0x4b,0x5,0x1,0x4,0x4,0x0,0x5a,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x2f,0x0,0x2e,0x27,0x39,0x27,0x36,0x6,0x7,0x18,0x2b, + 0x24,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x13,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x13,0x36,0x36,0x33,0x33, + 0x32,0x16,0x15,0x14,0x7,0x3,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x5,0x3,0x21,0x3,0xbf,0x1a,0x3,0x7,0x22,0x22,0xfd,0xa1,0x1d,0x1b,0x2, + 0x42,0x7d,0x18,0x10,0x1a,0x19,0x12,0x20,0xeb,0x59,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x44,0xa3,0x18,0x10,0x1a,0x19,0x12,0x20,0xfe,0xef,0x49,0x2,0xa, + 0x90,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x19,0xe,0x8,0x1,0x75,0x55,0x10,0x25,0x1b,0x12,0x19,0x15,0xa0,0x1,0xf8,0x23,0x1e,0x15,0x18,0x4,0x10,0xfe, + 0x7c,0x6f,0x10,0x25,0x1b,0x12,0x19,0x15,0xba,0xfe,0x63,0x0,0x0,0x0,0x0,0x1,0x0,0x52,0xff,0xf6,0x4,0x9f,0x4,0xad,0x0,0x2f,0x0,0x34,0x40,0x31, + 0x2a,0x17,0xf,0x2,0x4,0x1,0x3,0x1f,0xc,0x2,0x0,0x1,0x2,0x4a,0x0,0x1,0x3,0x0,0x3,0x1,0x0,0x70,0x5,0x4,0x2,0x3,0x3,0xe,0x4b,0x2, + 0x1,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x2f,0x0,0x2d,0x37,0x36,0x28,0x37,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23, + 0x22,0x26,0x35,0x34,0x37,0x13,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32, + 0x16,0x17,0x13,0x1,0x36,0x36,0x33,0x33,0x4,0x7b,0x24,0x1,0xa0,0x5,0x25,0x28,0x2,0x24,0x1f,0x2,0x7b,0xfe,0xe2,0x17,0x2c,0x22,0x22,0x27,0xa,0x80, + 0xa5,0x7,0x23,0x29,0x2,0x22,0x20,0x2,0xdc,0x7,0x28,0x25,0x2,0x23,0x24,0xa,0xa5,0x1,0x6d,0x16,0x35,0x23,0x2,0x4,0xad,0x17,0x1b,0xa,0x5,0xfb, + 0xcb,0x23,0x1e,0x16,0x19,0x4,0xe,0x3,0x2d,0xfe,0x42,0x23,0x1d,0x1d,0x23,0x1,0xbe,0xfc,0xd3,0x24,0x1d,0x16,0x18,0x5,0xe,0x4,0x35,0x24,0x1d,0x1e, + 0x23,0xfd,0xc6,0x2,0x3a,0x22,0x1f,0x0,0x0,0x1,0x0,0x70,0xff,0xea,0x4,0xa0,0x4,0xad,0x0,0x25,0x0,0x57,0x4b,0xb0,0x28,0x50,0x58,0x40,0x9,0x1f, + 0x15,0xc,0x2,0x4,0x0,0x2,0x1,0x4a,0x1b,0x40,0x9,0x1f,0x15,0xc,0x2,0x4,0x1,0x2,0x1,0x4a,0x59,0x4b,0xb0,0x28,0x50,0x58,0x40,0xe,0x4,0x3, + 0x2,0x2,0x2,0xe,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x12,0x4,0x3,0x2,0x2,0x2,0xe,0x4b,0x0,0x1,0x1,0xf,0x4b,0x0,0x0,0x0, + 0x17,0x0,0x4c,0x59,0x40,0xc,0x0,0x0,0x0,0x25,0x0,0x23,0x37,0x37,0x27,0x5,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26, + 0x27,0x1,0x23,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x17,0x1,0x33,0x13,0x36,0x36,0x33,0x33,0x4,0x83,0x1d, + 0x2,0xc1,0x5,0x2a,0x26,0x1b,0x23,0xd,0xfe,0x66,0x4,0x9b,0x6,0x27,0x26,0x2,0x22,0x1d,0x2,0xbe,0x6,0x27,0x2a,0x1b,0x2d,0xc,0x1,0x97,0x4,0x96, + 0x6,0x27,0x26,0x2,0x4,0xad,0x15,0x17,0x5,0x10,0xfb,0xb9,0x1b,0x20,0x1c,0x1b,0x3,0x82,0xfc,0x94,0x23,0x1e,0x15,0x17,0x5,0x10,0x4,0x35,0x23,0x1e, + 0x1c,0xfc,0x84,0x3,0x57,0x23,0x1e,0x0,0x0,0x0,0xff,0xff,0x0,0x70,0xff,0xea,0x4,0xa0,0x6,0x6c,0x0,0x22,0x0,0x41,0x0,0x0,0x1,0x7,0x1,0x80, + 0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x70,0xff,0xea,0x4,0xa0,0x6,0x68,0x0,0x22,0x0,0x41, + 0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x1e,0x1,0x4,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x70,0xfd,0xf3,0x4,0xa0, + 0x4,0xad,0x0,0x22,0x0,0x41,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xda,0x0,0x0,0x0,0x1,0x0,0x70,0xfe,0x66,0x4,0xa0,0x4,0xad,0x0,0x33,0x0,0x3a, + 0x40,0x37,0x2d,0x23,0x1a,0x19,0x2,0x5,0x3,0x4,0x1,0x4a,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70,0x6,0x5,0x2,0x4,0x4,0xe,0x4b,0x0,0x3,0x3, + 0xf,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x0,0x0,0x0,0x33,0x0,0x31,0x37,0x38,0x23,0x17,0x27,0x7,0x7,0x19,0x2b,0x0,0x16, + 0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x33,0x32,0x36,0x37,0x37,0x1,0x23,0x3,0x6,0x6,0x23, + 0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x17,0x1,0x33,0x13,0x36,0x36,0x33,0x33,0x4,0x83,0x1d,0x2,0xdf,0x18,0x9d,0x83,0x3a,0x73, + 0x31,0x21,0xd,0x16,0x26,0xb,0xc,0x59,0x51,0x40,0x4d,0xf,0x16,0xfe,0x5f,0x4,0x9b,0x6,0x27,0x26,0x2,0x22,0x1d,0x2,0xbe,0x6,0x27,0x2a,0x1b,0x2d, + 0xc,0x1,0x97,0x4,0x96,0x6,0x27,0x26,0x2,0x4,0xad,0x15,0x17,0x5,0x10,0xfb,0xd,0x87,0x8c,0x1b,0x17,0x10,0x1e,0x15,0x1b,0x2f,0x5,0x28,0x4b,0x52, + 0x7d,0x3,0x91,0xfc,0x94,0x23,0x1e,0x15,0x17,0x5,0x10,0x4,0x35,0x23,0x1e,0x1c,0xfc,0x84,0x3,0x57,0x23,0x1e,0xff,0xff,0x0,0x70,0xff,0xea,0x4,0xa0, + 0x6,0x15,0x0,0x22,0x0,0x41,0x0,0x0,0x1,0x7,0x1,0x9a,0x0,0x20,0x1,0x4,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0x0,0x2, + 0x0,0x72,0xff,0xea,0x4,0x9f,0x4,0xb9,0x0,0x13,0x0,0x27,0x0,0x2c,0x40,0x29,0x5,0x1,0x3,0x3,0x1,0x5b,0x4,0x1,0x1,0x1,0x16,0x4b,0x0,0x2, + 0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x14,0x14,0x0,0x0,0x14,0x27,0x14,0x26,0x1e,0x1c,0x0,0x13,0x0,0x12,0x28,0x6,0x7,0x15,0x2b,0x0,0x16, + 0x16,0x15,0x14,0x2,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x37,0x36,0x36,0x33,0x6,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36, + 0x37,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0x6c,0xc8,0x6b,0x4f,0x4c,0x53,0xf0,0x96,0x86,0xc8,0x6b,0x4f,0x4c,0x53,0xf0,0x96,0x74,0xaa,0x3d,0x3e,0x42, + 0x48,0x86,0x5d,0x69,0xaa,0x3d,0x3e,0x42,0x48,0x86,0x5d,0x4,0xb9,0x77,0xda,0x90,0x87,0xfe,0xfa,0x69,0x74,0x84,0x77,0xda,0x90,0x87,0x1,0x6,0x69,0x74, + 0x84,0x94,0x62,0x55,0x56,0xda,0x6d,0x69,0x99,0x51,0x62,0x55,0x56,0xda,0x6d,0x69,0x99,0x51,0x0,0x0,0xff,0xff,0x0,0x72,0xff,0xea,0x4,0x9f,0x6,0x6c, + 0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x6,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x72, + 0xff,0xea,0x4,0xa3,0x6,0x5c,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33, + 0x2b,0x0,0xff,0xff,0x0,0x72,0xff,0xea,0x4,0x9f,0x6,0x6e,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x1c,0x1,0xe,0x0,0x9,0xb1,0x2, + 0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x72,0xff,0xea,0x4,0x9f,0x6,0x36,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x26, + 0x1,0xe,0x0,0x9,0xb1,0x2,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x72,0xff,0xea,0x4,0x9f,0x6,0x6c,0x0,0x22,0x0,0x47,0x0,0x0, + 0x1,0x7,0x1,0x95,0x0,0x3c,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x72,0xff,0xea,0x4,0xfa,0x6,0x77, + 0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x96,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x2,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x72, + 0xff,0xea,0x4,0x9f,0x5,0xf0,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33, + 0x2b,0x0,0x0,0x3,0x0,0x3e,0xff,0xc2,0x4,0xd3,0x4,0xe3,0x0,0x28,0x0,0x33,0x0,0x3e,0x0,0x72,0x40,0x13,0x23,0x1,0x2,0x4,0x2,0x3e,0x31,0x30, + 0x18,0x4,0x5,0x5,0x4,0xe,0x1,0x0,0x5,0x3,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x20,0x0,0x3,0x3,0x16,0x4b,0x6,0x1,0x4,0x4,0x2,0x5b,0x0, + 0x2,0x2,0x16,0x4b,0x0,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x4b,0x0,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x20,0x0,0x3,0x2,0x3,0x72,0x0,0x1, + 0x0,0x1,0x73,0x6,0x1,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x16,0x4b,0x0,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x40,0xf,0x29,0x29, + 0x37,0x35,0x29,0x33,0x29,0x32,0x24,0x2d,0x23,0x2b,0x7,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x7,0x16,0x15,0x14,0x2,0x7,0x6,0x6,0x23,0x22,0x27,0x7, + 0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x35,0x34,0x12,0x37,0x36,0x36,0x33,0x32,0x16,0x17,0x37,0x36,0x33,0x32,0x17,0x4,0x6,0x7,0x6,0x6, + 0x15,0x14,0x17,0x1,0x26,0x23,0x1,0x16,0x33,0x32,0x36,0x37,0x36,0x36,0x35,0x34,0x27,0x4,0xd3,0x15,0x69,0x4a,0x4f,0x4c,0x53,0xf0,0x96,0xa3,0x70,0x53, + 0x1d,0x1c,0x16,0x18,0x20,0x14,0x69,0x49,0x4f,0x4c,0x53,0xf0,0x96,0x51,0x8a,0x36,0x54,0x1d,0x1d,0x17,0x18,0xfd,0xbe,0xaa,0x3d,0x3e,0x42,0x1e,0x2,0x68, + 0x49,0x6d,0xfe,0xa3,0x4a,0x6e,0x69,0xaa,0x3d,0x3e,0x42,0x1f,0x4,0xb7,0x18,0x12,0x1a,0x79,0x78,0xaa,0x87,0xfe,0xfa,0x69,0x74,0x84,0x57,0x5f,0x20,0x13, + 0x18,0x1a,0x14,0x17,0x79,0x78,0xa8,0x87,0x1,0x6,0x69,0x74,0x84,0x2c,0x2a,0x60,0x20,0x13,0xab,0x62,0x55,0x56,0xda,0x6d,0x60,0x48,0x2,0xc4,0x38,0xfc, + 0x92,0x39,0x62,0x55,0x56,0xda,0x6d,0x60,0x4a,0x0,0xff,0xff,0x0,0x72,0xff,0xea,0x4,0x9f,0x6,0x15,0x0,0x22,0x0,0x47,0x0,0x0,0x1,0x7,0x1,0x9a, + 0x0,0x1a,0x1,0x4,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x6b,0x0,0x0,0x4,0xe2,0x4,0xa3,0x0,0x29,0x0,0x33, + 0x0,0x43,0x40,0x40,0x2,0x1,0x0,0x5,0xd,0x1,0x2,0x1,0x18,0x1,0x4,0x3,0x3,0x4a,0x0,0x1,0x0,0x2,0x3,0x1,0x2,0x61,0x6,0x1,0x0,0x0, + 0x5,0x59,0x8,0x1,0x5,0x5,0xe,0x4b,0x7,0x1,0x3,0x3,0x4,0x59,0x0,0x4,0x4,0xf,0x4,0x4c,0x0,0x0,0x33,0x32,0x2b,0x2a,0x0,0x29,0x0,0x27, + 0x36,0x21,0x26,0x21,0x26,0x9,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3, + 0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x26,0x35,0x34,0x36,0x37,0x36,0x36,0x33,0x21,0x5,0x6,0x6,0x7,0x6,0x6,0x15,0x14,0x16, + 0x17,0x4,0xc8,0x1a,0x3,0x7,0x23,0x22,0xfe,0xbe,0x3f,0xf7,0x1b,0x1a,0x3,0x7,0x22,0x22,0xf7,0x46,0x1,0x56,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0x26, + 0x84,0xc0,0x67,0x42,0x42,0x4f,0xf2,0xa3,0x1,0xda,0xfe,0x10,0x6a,0xa5,0x39,0x38,0x39,0x93,0x84,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0x99,0x15, + 0x18,0xc,0xf,0x27,0x21,0xfe,0x74,0x16,0x18,0xb,0xf,0x27,0x21,0x6d,0xcc,0x8d,0x76,0xf7,0x66,0x7b,0x8f,0x89,0x3,0x64,0x56,0x54,0xd4,0x68,0x98,0xa8, + 0x5,0x0,0x0,0x0,0x0,0x2,0x0,0xac,0xff,0xf6,0x4,0xa3,0x4,0xa3,0x0,0x17,0x0,0x21,0x0,0x36,0x40,0x33,0x10,0x1,0x1,0x0,0x1,0x4a,0x0,0x3, + 0x0,0x0,0x1,0x3,0x0,0x61,0x6,0x1,0x4,0x4,0x2,0x59,0x5,0x1,0x2,0x2,0xe,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x18,0x18,0x0,0x0,0x18,0x21, + 0x18,0x20,0x1b,0x19,0x0,0x17,0x0,0x15,0x33,0x26,0x7,0x7,0x16,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x21,0x3,0x6,0x6,0x23,0x23,0x22,0x26, + 0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21,0x5,0x3,0x21,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x9b,0xae,0x5a,0x6a,0xe4,0xac,0xfe,0xd7,0x3c,0x6,0x27, + 0x28,0x2,0x23,0x1e,0x2,0xbc,0x7,0x20,0x22,0x1,0x6d,0xfe,0xd2,0x59,0x1,0xf,0x7b,0x9e,0x48,0x85,0x85,0x4,0xa3,0x52,0x94,0x62,0x77,0xd4,0x87,0xfe, + 0xae,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x28,0x26,0x1e,0x90,0xfe,0x6,0x57,0x8b,0x51,0x61,0x66,0x0,0x0,0x0,0x0,0x2,0x0,0xac,0xff,0xf6,0x4,0x4a, + 0x4,0xad,0x0,0x1e,0x0,0x28,0x0,0x6a,0x40,0xa,0x1a,0x1,0x3,0x2,0x10,0x1,0x1,0x0,0x2,0x4a,0x4b,0xb0,0x2f,0x50,0x58,0x40,0x1f,0x7,0x1,0x5, + 0x0,0x0,0x1,0x5,0x0,0x61,0x0,0x2,0x2,0xe,0x4b,0x0,0x4,0x4,0x3,0x59,0x6,0x1,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x1b,0x40, + 0x1d,0x6,0x1,0x3,0x0,0x4,0x5,0x3,0x4,0x62,0x7,0x1,0x5,0x0,0x0,0x1,0x5,0x0,0x61,0x0,0x2,0x2,0xe,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c, + 0x59,0x40,0x14,0x1f,0x1f,0x0,0x0,0x1f,0x28,0x1f,0x27,0x26,0x24,0x0,0x1e,0x0,0x1d,0x37,0x33,0x26,0x8,0x7,0x17,0x2b,0x0,0x16,0x16,0x15,0x14,0x6, + 0x6,0x23,0x21,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x21,0x2,0x36,0x36,0x35,0x34, + 0x26,0x23,0x21,0x3,0x21,0x3,0x72,0x90,0x48,0x51,0xba,0x92,0xfe,0xba,0x23,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xbe,0x6,0x27,0x28,0x2,0x23,0x1e,0x2, + 0x21,0x1,0x2b,0x8,0x75,0x33,0x61,0x62,0xfe,0xdf,0x47,0x1,0x25,0x3,0xb2,0x4c,0x84,0x54,0x5d,0xb7,0x7c,0xc7,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x35, + 0x23,0x1e,0x15,0x18,0x4,0x10,0xba,0xfd,0xdc,0x49,0x6e,0x3c,0x4a,0x57,0xfe,0x6c,0x0,0x0,0x0,0x2,0x0,0x72,0xff,0x58,0x4,0x9f,0x4,0xb9,0x0,0x20, + 0x0,0x40,0x0,0x43,0x40,0x40,0x3e,0x33,0x2,0x4,0x5,0x14,0x8,0x2,0x1,0x4,0x2,0x4a,0x0,0x5,0x3,0x4,0x3,0x5,0x4,0x70,0x0,0x0,0x1,0x0, + 0x73,0x0,0x3,0x3,0x2,0x5b,0x6,0x1,0x2,0x2,0x16,0x4b,0x0,0x4,0x4,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x0,0x0,0x3c,0x3a,0x32,0x30,0x28, + 0x26,0x0,0x20,0x0,0x1f,0x24,0x2f,0x7,0x7,0x16,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x7,0x6,0x7,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26, + 0x27,0x27,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x37,0x36,0x36,0x33,0x12,0x36,0x35,0x34,0x26,0x26,0x23,0x22,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x16, + 0x33,0x32,0x37,0x27,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x17,0x17,0x36,0x37,0x3,0x6c,0xc8,0x6b,0x4f,0x4c,0x48,0x61,0x3b,0x9,0x18,0x1a,0x1b,0x12, + 0x11,0x18,0x9,0x3b,0x4e,0x5a,0x86,0xc8,0x6b,0x4f,0x4c,0x53,0xf0,0x96,0xde,0x42,0x48,0x86,0x5d,0x69,0xaa,0x3d,0x3e,0x42,0x48,0x86,0x5d,0x30,0x2f,0x50, + 0x9,0x18,0x1a,0x1d,0x10,0x1f,0x13,0x4f,0x3a,0x30,0x4,0xb9,0x77,0xda,0x90,0x87,0xfe,0xfa,0x69,0x64,0x3e,0x82,0x14,0x10,0x10,0x1a,0xc,0xc,0x13,0x15, + 0x82,0x18,0x77,0xda,0x90,0x87,0x1,0x6,0x69,0x74,0x84,0xfc,0xd2,0xda,0x6d,0x69,0x99,0x51,0x62,0x55,0x56,0xda,0x6d,0x69,0x99,0x51,0xb,0xae,0x14,0xf, + 0x11,0x1b,0xc,0xd,0x2a,0xac,0x29,0x43,0x0,0x2,0x0,0xac,0xff,0xf1,0x4,0x5a,0x4,0xa3,0x0,0x21,0x0,0x2a,0x0,0x35,0x40,0x32,0x2,0x1,0x1,0x5, + 0x16,0x1,0x0,0x1,0x2,0x4a,0x6,0x1,0x5,0x0,0x1,0x0,0x5,0x1,0x61,0x0,0x4,0x4,0x3,0x59,0x0,0x3,0x3,0xe,0x4b,0x2,0x1,0x0,0x0,0x17, + 0x0,0x4c,0x22,0x22,0x22,0x2a,0x22,0x29,0x28,0x37,0x33,0x12,0x29,0x7,0x7,0x19,0x2b,0x0,0x6,0x7,0x13,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x27, + 0x3,0x23,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21,0x32,0x16,0x16,0x15,0x0,0x36,0x35,0x34,0x26,0x23,0x23,0x3,0x33, + 0x4,0x5a,0xa6,0xa5,0xc3,0xa,0x17,0x1a,0x21,0x13,0x19,0xe,0xda,0xe8,0x4a,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xbc,0x7,0x20,0x22,0x1,0x31,0x76,0xa9, + 0x57,0xfe,0xbe,0xa8,0x7d,0x76,0xdb,0x4b,0xd0,0x2,0xe5,0xcb,0x2e,0xfe,0x6a,0x16,0xd,0xf,0x19,0xb,0xf,0x1d,0x1,0xcb,0xfe,0x5e,0x23,0x1e,0x15,0x18, + 0x4,0x10,0x4,0x28,0x26,0x1e,0x4b,0x87,0x59,0xfe,0xf1,0x87,0x78,0x53,0x58,0xfe,0x56,0x0,0x0,0x0,0xff,0xff,0x0,0xac,0xff,0xf1,0x4,0x5a,0x6,0x6c, + 0x0,0x22,0x0,0x55,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0xa,0x1,0xe,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xac, + 0xff,0xf1,0x4,0x7b,0x6,0x68,0x0,0x22,0x0,0x55,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x19,0x1,0x4,0x0,0x9,0xb1,0x2,0x1,0xb8,0x1,0x4,0xb0,0x33, + 0x2b,0x0,0xff,0xff,0x0,0xac,0xfd,0xf3,0x4,0x5a,0x4,0xa3,0x0,0x22,0x0,0x55,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xea,0x0,0x0,0x0,0x1,0x0,0x7f, + 0xff,0xea,0x4,0x70,0x4,0xb9,0x0,0x40,0x0,0x39,0x40,0x36,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x0,0x3,0x4,0x1,0x3,0x4,0x6e,0x0,0x1,0x1, + 0x5,0x5b,0x6,0x1,0x5,0x5,0x16,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x0,0x0,0x0,0x40,0x0,0x3f,0x2f,0x2d,0x29,0x28,0x21, + 0x1f,0x24,0x16,0x7,0x7,0x16,0x2b,0x0,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17, + 0x16,0x16,0x17,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x27, + 0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x35,0x34,0x36,0x36,0x33,0x3,0xa4,0xab,0x21,0x11,0x1a,0x1f,0x10,0xd,0x46,0xb7,0x5f,0x59,0x7d,0x3f,0x30,0x33,0x1e, + 0x53,0x29,0x55,0x6e,0x32,0x47,0x50,0x61,0xdb,0xad,0x73,0xd9,0x4f,0x1e,0x12,0x1b,0x1e,0xf,0xd,0x46,0xba,0x62,0x66,0x8d,0x46,0x5c,0x23,0x56,0x49,0x43, + 0x65,0x2b,0x98,0x64,0xcd,0x97,0x4,0xb9,0x64,0x14,0x1d,0x14,0x20,0x30,0x9,0x2a,0x32,0x3d,0x62,0x37,0x2c,0x35,0x12,0xa,0x13,0x9,0x12,0x1d,0x17,0x20, + 0x7e,0x56,0x66,0xb6,0x76,0x3d,0x37,0x15,0x1d,0x16,0x1f,0x2d,0xa,0x32,0x38,0x3f,0x6b,0x41,0x5c,0x2a,0x10,0x17,0x10,0xe,0x1b,0x12,0x41,0x9f,0x5b,0xad, + 0x70,0x0,0x0,0x0,0xff,0xff,0x0,0x7f,0xff,0xea,0x4,0x70,0x6,0x6c,0x0,0x22,0x0,0x59,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0xa,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x7f,0xff,0xea,0x4,0x71,0x6,0x72,0x0,0x22,0x0,0x59,0x0,0x0,0x1,0x7,0x1,0x83, + 0x0,0xf,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x7f,0xfe,0x28,0x4,0x70,0x4,0xb9,0x0,0x63,0x0,0x5f, + 0x40,0x5c,0x41,0x1,0x2,0x9,0x3e,0x1,0x7,0x3,0x2,0x4a,0x0,0x0,0x1,0x8,0x1,0x0,0x8,0x70,0x0,0x8,0x9,0x1,0x8,0x9,0x6e,0x0,0x5,0x7, + 0x6,0x7,0x5,0x6,0x70,0x0,0x3,0x0,0x7,0x5,0x3,0x7,0x63,0x0,0x6,0x0,0x4,0x6,0x4,0x5f,0x0,0x1,0x1,0xa,0x5b,0x0,0xa,0xa,0x16,0x4b, + 0x0,0x9,0x9,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x62,0x60,0x50,0x4e,0x4a,0x49,0x3d,0x3a,0x37,0x35,0x32,0x30,0x28,0x26,0x20,0x1f,0x1e,0x1d,0x24, + 0x14,0xb,0x7,0x16,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x17,0x16, + 0x16,0x15,0x14,0x6,0x6,0x7,0x7,0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x33, + 0x32,0x36,0x35,0x34,0x23,0x7,0x22,0x35,0x34,0x37,0x37,0x26,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34, + 0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x4,0x70,0x11,0x1a,0x1f,0x10,0xd,0x46,0xb7,0x5f,0x59,0x7d,0x3f,0x30,0x33, + 0x1e,0x53,0x29,0x55,0x6e,0x32,0x47,0x50,0x5b,0xcd,0xa2,0x10,0x58,0x5a,0x1c,0x1a,0x45,0x97,0x44,0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64, + 0x31,0x3a,0x3a,0x67,0x23,0x1d,0x1,0x1b,0x58,0xa0,0x3c,0x1e,0x12,0x1b,0x1e,0xf,0xd,0x46,0xba,0x62,0x66,0x8d,0x46,0x5c,0x23,0x56,0x49,0x43,0x65,0x2b, + 0x98,0x64,0xcd,0x97,0xe4,0xab,0x4,0x41,0x1d,0x14,0x20,0x30,0x9,0x2a,0x32,0x3d,0x62,0x37,0x2c,0x35,0x12,0xa,0x13,0x9,0x12,0x1d,0x17,0x20,0x7e,0x56, + 0x62,0xb2,0x77,0x6,0x5d,0x2,0x52,0x40,0x22,0x4f,0x1b,0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15,0x2,0xf,0x13,0x2d,0x24,0x37,0x1,0x1c,0x9,0x5, + 0x9f,0xb,0x39,0x2a,0x15,0x1d,0x16,0x1f,0x2d,0xa,0x32,0x38,0x3f,0x6b,0x41,0x5c,0x2a,0x10,0x17,0x10,0xe,0x1b,0x12,0x41,0x9f,0x5b,0xad,0x70,0x64,0x0, + 0x0,0x0,0xff,0xff,0x0,0x7f,0xff,0xea,0x4,0x70,0x6,0x6e,0x0,0x22,0x0,0x59,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x24,0x1,0xe,0x0,0x9,0xb1,0x1, + 0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x7f,0xfd,0xf3,0x4,0x70,0x4,0xb9,0x0,0x22,0x0,0x59,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xd6, + 0x0,0x0,0x0,0x1,0x0,0xeb,0xff,0xf6,0x4,0xc9,0x4,0xa3,0x0,0x1d,0x0,0x2c,0x40,0x29,0x17,0x2,0x2,0x0,0x3,0x10,0x1,0x1,0x0,0x2,0x4a,0x2, + 0x1,0x0,0x0,0x3,0x59,0x4,0x1,0x3,0x3,0xe,0x4b,0x0,0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x0,0x1d,0x0,0x1b,0x25,0x33,0x26,0x5,0x7,0x17,0x2b, + 0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21, + 0x4,0xaf,0x1a,0x3,0x7,0x23,0x22,0xfe,0xa8,0xae,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xae,0xfe,0x94,0x1b,0x1a,0x3,0x7,0x23,0x22,0x3,0x5a,0x4,0xa3, + 0x16,0x18,0xb,0xf,0x27,0x21,0xfc,0x24,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0xdc,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x1,0x0,0xeb,0xff,0xf6,0x4,0xc9, + 0x4,0xa3,0x0,0x33,0x0,0x3f,0x40,0x3c,0x2d,0x2,0x2,0x0,0x7,0x22,0xd,0x2,0x2,0x1,0x1b,0x1,0x3,0x2,0x3,0x4a,0x5,0x1,0x1,0x4,0x1,0x2, + 0x3,0x1,0x2,0x61,0x6,0x1,0x0,0x0,0x7,0x59,0x8,0x1,0x7,0x7,0xe,0x4b,0x0,0x3,0x3,0xf,0x3,0x4c,0x0,0x0,0x0,0x33,0x0,0x31,0x21,0x26, + 0x25,0x33,0x26,0x21,0x26,0x9,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3, + 0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33, + 0x21,0x4,0xaf,0x1a,0x3,0x7,0x23,0x22,0xfe,0xa8,0x50,0xd1,0x1b,0x1a,0x3,0x7,0x23,0x22,0xd0,0x45,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x45,0xcc,0x1b, + 0x1a,0x3,0x7,0x23,0x22,0xcb,0x50,0xfe,0x94,0x1b,0x1a,0x3,0x7,0x23,0x22,0x3,0x5a,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0x3b,0x16,0x18,0xb, + 0xf,0x27,0x21,0xfe,0x79,0x23,0x1e,0x15,0x18,0x4,0x10,0x1,0x87,0x16,0x18,0xb,0xf,0x27,0x21,0x1,0xc5,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0xff,0xff, + 0x0,0xeb,0xff,0xf6,0x4,0xc9,0x6,0x68,0x0,0x22,0x0,0x5f,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x14,0x1,0x4,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4, + 0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xeb,0xfe,0x28,0x4,0xc9,0x4,0xa3,0x0,0x3d,0x0,0x42,0x40,0x3f,0x37,0x2,0x2,0x0,0x7,0x2b,0x1,0x5,0x1,0x2, + 0x4a,0x0,0x3,0x5,0x4,0x5,0x3,0x4,0x70,0x0,0x1,0x0,0x5,0x3,0x1,0x5,0x63,0x0,0x4,0x0,0x2,0x4,0x2,0x5f,0x6,0x1,0x0,0x0,0x7,0x59, + 0x8,0x1,0x7,0x7,0xe,0x0,0x4c,0x0,0x0,0x0,0x3d,0x0,0x3b,0x29,0x33,0x23,0x28,0x26,0x14,0x26,0x9,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14,0x7,0x6, + 0x6,0x23,0x21,0x3,0x6,0x7,0x7,0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x33, + 0x32,0x36,0x35,0x34,0x23,0x7,0x22,0x35,0x34,0x37,0x37,0x26,0x35,0x34,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0xaf,0x1a,0x3, + 0x7,0x23,0x22,0xfe,0xa8,0xae,0x4,0xb,0x17,0x58,0x5a,0x1c,0x1a,0x45,0x97,0x44,0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64,0x31,0x3a,0x3a, + 0x67,0x23,0x1d,0x1,0x21,0x2,0x2,0xae,0xfe,0x94,0x1b,0x1a,0x3,0x7,0x23,0x22,0x3,0x5a,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfc,0x24,0x18,0xf, + 0x82,0x2,0x52,0x40,0x22,0x4f,0x1b,0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15,0x2,0xf,0x13,0x2d,0x24,0x37,0x1,0x1c,0x9,0x5,0xc1,0xa,0x7,0x6, + 0xe,0x3,0xdc,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0xeb,0xfd,0xf3,0x4,0xc9,0x4,0xa3,0x0,0x22,0x0,0x5f,0x0,0x0,0x0,0x3, + 0x1,0x7e,0x4,0xcc,0x0,0x0,0x0,0x1,0x0,0xa8,0xff,0xea,0x4,0xa0,0x4,0xad,0x0,0x25,0x0,0x28,0x40,0x25,0x15,0x2,0x2,0x2,0x1,0x1,0x4a,0x4, + 0x3,0x2,0x1,0x1,0xe,0x4b,0x0,0x2,0x2,0x0,0x5c,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x25,0x0,0x23,0x29,0x37,0x27,0x5,0x7,0x17,0x2b, + 0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33, + 0x32,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x4,0x82,0x1e,0x2,0x81,0x27,0xfa,0xd1,0xb6,0xcd,0xb,0x7d,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x7b,0xa,0x7b, + 0x7b,0x93,0xa6,0x1d,0x7b,0x6,0x27,0x28,0x2,0x4,0xad,0x15,0x18,0x4,0x10,0xfd,0x28,0xdc,0xce,0xac,0xa6,0x30,0x3d,0x2,0xc3,0x23,0x1e,0x15,0x18,0x4, + 0x10,0xfd,0x47,0x3c,0x24,0x70,0x65,0x8f,0xa4,0x2,0xbb,0x23,0x1e,0x0,0x0,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa0,0x6,0x6c,0x0,0x22,0x0,0x64, + 0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x24,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa3, + 0x6,0x5c,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x82,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0xa8,0xff,0xea,0x4,0xa0,0x6,0x6e,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x24,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa0,0x6,0x36,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x1c,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa0,0x6,0x6c,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x95, + 0x0,0x32,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xf0,0x6,0x77,0x0,0x22,0x0,0x64, + 0x0,0x0,0x1,0x7,0x1,0x96,0x0,0x14,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa0, + 0x5,0xf0,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x97,0x0,0x1e,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1, + 0x0,0xa8,0xfe,0x28,0x4,0xa0,0x4,0xad,0x0,0x3d,0x0,0x60,0xb6,0x2d,0x2,0x2,0x5,0x4,0x1,0x4a,0x4b,0xb0,0x31,0x50,0x58,0x40,0x1a,0x1,0x1,0x0, + 0x0,0x2,0x0,0x2,0x5f,0x7,0x6,0x2,0x4,0x4,0xe,0x4b,0x0,0x5,0x5,0x3,0x5c,0x0,0x3,0x3,0x17,0x3,0x4c,0x1b,0x40,0x21,0x0,0x1,0x3,0x0, + 0x3,0x1,0x0,0x70,0x0,0x0,0x0,0x2,0x0,0x2,0x5f,0x7,0x6,0x2,0x4,0x4,0xe,0x4b,0x0,0x5,0x5,0x3,0x5c,0x0,0x3,0x3,0x17,0x3,0x4c,0x59, + 0x40,0xf,0x0,0x0,0x0,0x3d,0x0,0x3b,0x29,0x37,0x25,0x26,0x21,0x2d,0x8,0x7,0x1a,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x7,0x6,0x6,0x15, + 0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33, + 0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x4,0x82,0x1e,0x2,0x81,0x1b,0x8e,0x71,0x77,0x71, + 0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56,0x58,0x56,0x2,0xb6,0xcd,0xb,0x7d,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x7b,0xa,0x7b, + 0x7b,0x93,0xa6,0x1d,0x7b,0x6,0x27,0x28,0x2,0x4,0xad,0x15,0x18,0x4,0x10,0xfd,0x28,0x9c,0xc0,0x2b,0x5d,0x8d,0x38,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19, + 0x7,0xd,0x10,0x58,0x4a,0x4a,0x8e,0x48,0xac,0xa6,0x30,0x3d,0x2,0xc3,0x23,0x1e,0x15,0x18,0x4,0x10,0xfd,0x47,0x3c,0x24,0x70,0x65,0x8f,0xa4,0x2,0xbb, + 0x23,0x1e,0x0,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa0,0x7,0x5,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x99,0x0,0x14,0x0,0xf0,0x0,0x8, + 0xb1,0x1,0x2,0xb0,0xf0,0xb0,0x33,0x2b,0x0,0x0,0xff,0xff,0x0,0xa8,0xff,0xea,0x4,0xa0,0x6,0x15,0x0,0x22,0x0,0x64,0x0,0x0,0x1,0x7,0x1,0x9a, + 0x0,0x28,0x1,0x4,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xdf,0xff,0xea,0x4,0xe3,0x4,0xb0,0x0,0x1c,0x0,0x1c, + 0x40,0x19,0x19,0x5,0x2,0x2,0x0,0x1,0x4a,0x1,0x1,0x0,0x0,0xe,0x4b,0x0,0x2,0x2,0x17,0x2,0x4c,0x2a,0x15,0x20,0x3,0x7,0x17,0x2b,0x0,0x33, + 0x32,0x16,0x17,0x13,0x1,0x36,0x33,0x32,0x17,0x16,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x26,0x35,0x34,0x36,0x37,0x1,0x35,0x8, + 0x1c,0x1b,0x5,0xbe,0x2,0x17,0x16,0x23,0x12,0x1d,0x17,0x16,0xd,0xfd,0xba,0x13,0x38,0x2b,0x2b,0x2e,0x7,0xd8,0x3,0x1e,0x24,0x4,0xad,0x17,0x1c,0xfc, + 0x3c,0x3,0xd1,0x29,0xd,0xb,0x18,0xf,0x12,0x17,0xfb,0xe3,0x23,0x1e,0x1e,0x23,0x4,0x39,0xc,0xb,0x15,0x17,0x4,0x0,0x0,0x1,0x0,0x99,0xff,0xea, + 0x5,0x3,0x4,0xae,0x0,0x27,0x0,0x4d,0xb7,0x1c,0xa,0x3,0x3,0x2,0x0,0x1,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x13,0x5,0x4,0x2,0x1,0x1,0xe, + 0x4b,0x0,0x0,0x0,0x11,0x4b,0x3,0x1,0x2,0x2,0x17,0x2,0x4c,0x1b,0x40,0x16,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x5,0x4,0x2,0x1,0x1,0xe, + 0x4b,0x3,0x1,0x2,0x2,0x17,0x2,0x4c,0x59,0x40,0xd,0x0,0x0,0x0,0x27,0x0,0x26,0x25,0x2a,0x15,0x26,0x6,0x7,0x18,0x2b,0x0,0x16,0x7,0x3,0x1, + 0x36,0x36,0x33,0x32,0x17,0x13,0x1,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x27,0x3,0x1,0x6,0x6,0x23,0x22,0x26, + 0x37,0x13,0x36,0x36,0x33,0x1,0x3a,0x1f,0x2,0x2b,0x1,0x36,0xb,0x24,0x20,0x3f,0x6,0x68,0x1,0xc,0x9,0x1e,0x1b,0xe,0x10,0x1e,0x1b,0x8,0xfe,0xb1, + 0xb,0x2c,0x27,0x50,0xc,0x68,0xfe,0xca,0x12,0x34,0x26,0x28,0x27,0x1,0x2a,0x2,0x1d,0x2b,0x4,0xac,0x1b,0x24,0xfc,0x95,0x2,0x4b,0x14,0x14,0x28,0xfd, + 0xb5,0x3,0x73,0x1e,0x1b,0x3,0x5,0x16,0x13,0xf,0x18,0xfb,0xd5,0x24,0x1d,0x41,0x2,0x4a,0xfd,0xb6,0x22,0x1f,0x1e,0x23,0x4,0x45,0x22,0x1a,0x0,0x0, + 0xff,0xff,0x0,0x99,0xff,0xea,0x5,0x3,0x6,0x6c,0x0,0x22,0x0,0x70,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0x14,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8, + 0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x99,0xff,0xea,0x5,0x3,0x6,0x6e,0x0,0x22,0x0,0x70,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x14,0x1,0xe, + 0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x99,0xff,0xea,0x5,0x3,0x6,0x36,0x0,0x22,0x0,0x70,0x0,0x0,0x1,0x7, + 0x1,0x93,0x0,0x17,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x99,0xff,0xea,0x5,0x3,0x6,0x6c,0x0,0x22, + 0x0,0x70,0x0,0x0,0x1,0x7,0x1,0x95,0x0,0xa,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x5d,0xff,0xeb, + 0x4,0xa8,0x4,0xb8,0x0,0x2b,0x0,0x20,0x40,0x1d,0x26,0x1a,0x10,0x4,0x4,0x0,0x2,0x1,0x4a,0x3,0x1,0x2,0x2,0x16,0x4b,0x1,0x1,0x0,0x0,0x17, + 0x0,0x4c,0x25,0x2d,0x25,0x2b,0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x1,0x1,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x1,0x6,0x23, + 0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x3,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x33,0x32,0x17,0x4,0xa8,0x17,0xfe,0x5b,0x1, + 0xc,0x9,0x19,0x1b,0x22,0x13,0xe,0x14,0x9,0xec,0xfe,0x6f,0x18,0x1f,0x18,0x22,0x22,0x17,0x1,0xc1,0xfa,0x9,0x19,0x1b,0x22,0x13,0xe,0x14,0x9,0xdb, + 0x1,0x74,0x18,0x1f,0x18,0x22,0x4,0x8e,0x1b,0x15,0x1c,0xfe,0x12,0xfe,0x1,0x12,0xd,0x10,0x19,0xd,0x11,0x10,0x12,0x1,0xd9,0xfe,0x1f,0x1e,0x15,0x15, + 0x1b,0x15,0x1c,0x2,0x7,0x1,0xe6,0x12,0xd,0x10,0x19,0xd,0x11,0x10,0x12,0xfe,0x44,0x1,0xc4,0x1e,0x15,0x0,0x0,0x0,0x0,0x1,0x1,0x5,0xff,0xf6, + 0x4,0xcb,0x4,0xb2,0x0,0x20,0x0,0x1d,0x40,0x1a,0x1b,0xf,0xc,0x3,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x1,0xe,0x4b,0x0,0x0,0x0,0xf,0x0,0x4c, + 0x26,0x1c,0x37,0x3,0x7,0x17,0x2b,0x0,0x15,0x14,0x7,0x1,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x1,0x26,0x35,0x34,0x36,0x37,0x36, + 0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x33,0x32,0x17,0x4,0xcb,0x15,0xfe,0xa,0x4c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x4e,0xfe,0xe3,0xa,0x19,0x1c,0x1a, + 0x14,0x10,0x14,0x8,0xf5,0x1,0xb2,0x18,0x20,0x17,0x19,0x4,0x8b,0x1b,0x14,0x1a,0xfd,0xa4,0xfe,0x51,0x23,0x1e,0x15,0x18,0x4,0x10,0x1,0xbc,0x2,0x5a, + 0x16,0xc,0x10,0x19,0xb,0xb,0x10,0x11,0xfd,0xf5,0x2,0x12,0x1e,0xf,0xff,0xff,0x1,0x5,0xff,0xf6,0x4,0xcb,0x6,0x6c,0x0,0x22,0x0,0x76,0x0,0x0, + 0x1,0x7,0x1,0x80,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x1,0x5,0xff,0xf6,0x4,0xcb,0x6,0x6e, + 0x0,0x22,0x0,0x76,0x0,0x0,0x1,0x7,0x1,0x92,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff,0x1,0x5, + 0xff,0xf6,0x4,0xcb,0x6,0x36,0x0,0x22,0x0,0x76,0x0,0x0,0x1,0x7,0x1,0x93,0x0,0x1c,0x1,0xe,0x0,0x9,0xb1,0x1,0x2,0xb8,0x1,0xe,0xb0,0x33, + 0x2b,0x0,0xff,0xff,0x1,0x5,0xff,0xf6,0x4,0xcb,0x6,0x6c,0x0,0x22,0x0,0x76,0x0,0x0,0x1,0x7,0x1,0x95,0x0,0x14,0x1,0xe,0x0,0x9,0xb1,0x1, + 0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0x74,0x0,0x0,0x4,0x88,0x4,0xa3,0x0,0x23,0x0,0x31,0x40,0x2e,0x14,0xb,0x2,0x0,0x1,0x1d, + 0x2,0x2,0x3,0x2,0x2,0x4a,0x0,0x0,0x0,0x1,0x59,0x0,0x1,0x1,0xe,0x4b,0x0,0x2,0x2,0x3,0x59,0x4,0x1,0x3,0x3,0xf,0x3,0x4c,0x0,0x0, + 0x0,0x23,0x0,0x21,0x27,0x36,0x27,0x5,0x7,0x17,0x2b,0x32,0x26,0x35,0x34,0x37,0x36,0x37,0x1,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x32, + 0x16,0x15,0x14,0x7,0x6,0x7,0x1,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x8e,0x1a,0x2,0x4,0x12,0x3,0x9,0xfd,0xd2,0x1b,0x1a,0x3,0x7, + 0x23,0x22,0x2,0xd0,0x1c,0x1b,0x2,0x4,0xd,0xfc,0xf2,0x2,0x5a,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfd,0x2,0x14,0x18,0xf,0x9,0x15,0x16,0x3,0xa4,0x16, + 0x18,0xb,0xf,0x27,0x21,0x15,0x18,0xe,0x9,0x17,0x10,0xfc,0x58,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0x74,0x0,0x0,0x4,0x88, + 0x6,0x6c,0x0,0x22,0x0,0x7b,0x0,0x0,0x1,0x7,0x1,0x80,0x0,0xa,0x1,0xe,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0xff,0xff, + 0x0,0x74,0x0,0x0,0x4,0x88,0x6,0x68,0x0,0x22,0x0,0x7b,0x0,0x0,0x1,0x7,0x1,0x83,0x0,0x1e,0x1,0x4,0x0,0x9,0xb1,0x1,0x1,0xb8,0x1,0x4, + 0xb0,0x33,0x2b,0x0,0xff,0xff,0x0,0x74,0x0,0x0,0x4,0x88,0x6,0x5f,0x0,0x22,0x0,0x7b,0x0,0x0,0x1,0x7,0x1,0x94,0x0,0x1e,0x1,0xe,0x0,0x9, + 0xb1,0x1,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0x8f,0xff,0xea,0x4,0x6b,0x3,0xb2,0x0,0x2a,0x0,0x38,0x0,0xfe,0x4b,0xb0,0x1b,0x50, + 0x58,0x40,0xf,0x21,0x1,0x5,0x2,0x19,0xb,0x2,0x4,0x5,0x2,0x1,0x0,0x4,0x3,0x4a,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0xf,0x21,0x1,0x5,0x2, + 0x19,0xb,0x2,0x4,0x5,0x2,0x1,0x0,0x6,0x3,0x4a,0x1b,0x40,0xf,0x21,0x1,0x5,0x3,0x19,0xb,0x2,0x4,0x5,0x2,0x1,0x0,0x6,0x3,0x4a,0x59, + 0x59,0x4b,0xb0,0x17,0x50,0x58,0x40,0x1a,0x0,0x5,0x5,0x2,0x5b,0x3,0x1,0x2,0x2,0x19,0x4b,0x8,0x6,0x7,0x3,0x4,0x4,0x0,0x5c,0x1,0x1,0x0, + 0x0,0xf,0x0,0x4c,0x1b,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x26,0x0,0x5,0x5,0x2,0x5b,0x3,0x1,0x2,0x2,0x19,0x4b,0x8,0x6,0x7,0x3,0x4,0x4,0x0, + 0x5c,0x0,0x0,0x0,0xf,0x4b,0x8,0x6,0x7,0x3,0x4,0x4,0x1,0x5c,0x0,0x1,0x1,0x17,0x1,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x22,0x0,0x5, + 0x5,0x2,0x5b,0x3,0x1,0x2,0x2,0x19,0x4b,0x7,0x1,0x4,0x4,0x0,0x5c,0x0,0x0,0x0,0xf,0x4b,0x8,0x1,0x6,0x6,0x1,0x5b,0x0,0x1,0x1,0x17, + 0x1,0x4c,0x1b,0x40,0x26,0x0,0x3,0x3,0x11,0x4b,0x0,0x5,0x5,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x7,0x1,0x4,0x4,0x0,0x5c,0x0,0x0,0x0,0xf, + 0x4b,0x8,0x1,0x6,0x6,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x59,0x59,0x40,0x15,0x2b,0x2b,0x0,0x0,0x2b,0x38,0x2b,0x37,0x32,0x30,0x0,0x2a, + 0x0,0x28,0x35,0x26,0x24,0x36,0x9,0x7,0x18,0x2b,0x24,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x27,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34, + 0x12,0x36,0x33,0x32,0x16,0x17,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x33,0x4,0x36,0x36,0x35,0x34,0x26,0x23, + 0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x4,0x52,0x19,0x2,0x8,0x22,0x22,0xb,0x50,0x62,0x4,0x48,0xb0,0x6e,0x68,0xa3,0x5c,0x73,0xe6,0xa3,0x5d,0x92,0x2e, + 0x13,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x68,0x4,0x2e,0x28,0x5,0xfe,0x3a,0xa3,0x5d,0x7f,0x6c,0x69,0x9f,0x55,0x78,0x6c,0x90,0x16,0x19,0xf,0xa,0x27, + 0x21,0x5d,0x55,0x63,0x65,0x5f,0xb0,0x75,0x8a,0x1,0xb,0xaf,0x60,0x54,0x67,0x24,0x1d,0x15,0x17,0x5,0x10,0xfd,0xb2,0x13,0x15,0x2f,0x30,0x12,0x79,0xc0, + 0x66,0x79,0x88,0x7a,0xc4,0x69,0x72,0x87,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b,0x5,0x5e,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x80, + 0xcc,0x0,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b,0x5,0x4e,0x0,0x22,0x1,0x82,0xe2,0x0,0x0,0x2,0x0,0x7f,0x0,0x0,0x0,0x0,0xff,0xff, + 0x0,0x8f,0xff,0xea,0x4,0x6b,0x5,0x60,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x92,0xec,0x0,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b, + 0x5,0x28,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x93,0xe2,0x0,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b,0x5,0x5e,0x0,0x22,0x0,0x7f, + 0x0,0x0,0x0,0x2,0x1,0x95,0xc,0x0,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b,0x4,0xe2,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2,0x1,0x97, + 0xe9,0x0,0x0,0x0,0x0,0x2,0x0,0x8f,0xfe,0x28,0x4,0x6b,0x3,0xb2,0x0,0x3f,0x0,0x4d,0x1,0x23,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x10,0x36,0x1,0x7, + 0x4,0x2e,0x20,0x2,0x6,0x7,0x1e,0x2,0x2,0x3,0x6,0x3,0x4a,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x10,0x36,0x1,0x7,0x4,0x2e,0x20,0x2,0x6,0x7, + 0x1e,0x2,0x2,0x3,0x8,0x3,0x4a,0x1b,0x40,0x10,0x36,0x1,0x7,0x5,0x2e,0x20,0x2,0x6,0x7,0x1e,0x2,0x2,0x3,0x8,0x3,0x4a,0x59,0x59,0x4b,0xb0, + 0x1b,0x50,0x58,0x40,0x21,0x1,0x1,0x0,0x0,0x2,0x0,0x2,0x5f,0x0,0x7,0x7,0x4,0x5b,0x5,0x1,0x4,0x4,0x19,0x4b,0xa,0x8,0x9,0x3,0x6,0x6, + 0x3,0x5b,0x0,0x3,0x3,0x17,0x3,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x28,0x9,0x1,0x6,0x7,0x8,0x7,0x6,0x8,0x70,0x1,0x1,0x0,0x0,0x2, + 0x0,0x2,0x5f,0x0,0x7,0x7,0x4,0x5b,0x5,0x1,0x4,0x4,0x19,0x4b,0xa,0x1,0x8,0x8,0x3,0x5b,0x0,0x3,0x3,0x17,0x3,0x4c,0x1b,0x4b,0xb0,0x31, + 0x50,0x58,0x40,0x2c,0x9,0x1,0x6,0x7,0x8,0x7,0x6,0x8,0x70,0x1,0x1,0x0,0x0,0x2,0x0,0x2,0x5f,0x0,0x5,0x5,0x11,0x4b,0x0,0x7,0x7,0x4, + 0x5b,0x0,0x4,0x4,0x19,0x4b,0xa,0x1,0x8,0x8,0x3,0x5b,0x0,0x3,0x3,0x17,0x3,0x4c,0x1b,0x40,0x33,0x9,0x1,0x6,0x7,0x8,0x7,0x6,0x8,0x70, + 0x0,0x1,0x3,0x0,0x3,0x1,0x0,0x70,0x0,0x0,0x0,0x2,0x0,0x2,0x5f,0x0,0x5,0x5,0x11,0x4b,0x0,0x7,0x7,0x4,0x5b,0x0,0x4,0x4,0x19,0x4b, + 0xa,0x1,0x8,0x8,0x3,0x5b,0x0,0x3,0x3,0x17,0x3,0x4c,0x59,0x59,0x59,0x40,0x17,0x40,0x40,0x0,0x0,0x40,0x4d,0x40,0x4c,0x47,0x45,0x0,0x3f,0x0, + 0x3d,0x35,0x26,0x29,0x26,0x21,0x2c,0xb,0x7,0x1a,0x2b,0x24,0x16,0x15,0x14,0x7,0x6,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15, + 0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x26,0x27,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x36,0x33,0x32,0x16,0x17,0x37,0x36, + 0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x33,0x4,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x4, + 0x52,0x19,0x2,0x6,0x19,0x16,0x70,0x6b,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56,0x78,0x75,0x48,0x6,0x48,0xb0,0x6e,0x68,0xa3, + 0x5c,0x73,0xe6,0xa3,0x5d,0x92,0x2e,0x13,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x68,0x4,0x2e,0x28,0x5,0xfe,0x3a,0xa3,0x5d,0x7f,0x6c,0x69,0x9f,0x55,0x78, + 0x6c,0x90,0x16,0x19,0xf,0xa,0x1f,0x22,0x5,0x59,0x88,0x36,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x57,0xa5,0x55,0x2d,0x6a,0x63, + 0x65,0x5f,0xb0,0x75,0x8a,0x1,0xb,0xaf,0x60,0x54,0x67,0x24,0x1d,0x15,0x17,0x5,0x10,0xfd,0xb2,0x13,0x15,0x2f,0x30,0x12,0x79,0xc0,0x66,0x79,0x88,0x7a, + 0xc4,0x69,0x72,0x87,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b,0x5,0xf8,0x0,0x22,0x0,0x7f,0x0,0x0,0x1,0x6,0x1,0x99,0xe4,0xe3,0x0,0x9, + 0xb1,0x2,0x2,0xb8,0xff,0xe3,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x0,0x8f,0xff,0xea,0x4,0x6b,0x5,0x11,0x0,0x22,0x0,0x7f,0x0,0x0,0x0,0x2, + 0x1,0x9a,0xe2,0x0,0x0,0x0,0x0,0x3,0x0,0x2c,0xff,0xea,0x4,0x9d,0x3,0xb2,0x0,0x41,0x0,0x4a,0x0,0x57,0x0,0x65,0x40,0x62,0x3e,0x1,0x6,0x8, + 0x1d,0x1,0x3,0x1,0x2,0x4a,0x0,0x7,0x6,0x5,0x6,0x7,0x5,0x70,0x0,0x2,0x0,0x1,0x0,0x2,0x1,0x70,0xa,0x1,0x5,0x10,0xd,0x2,0x0,0x2, + 0x5,0x0,0x63,0xf,0xb,0x2,0x6,0x6,0x8,0x5b,0xe,0x9,0x2,0x8,0x8,0x19,0x4b,0xc,0x1,0x1,0x1,0x3,0x5b,0x4,0x1,0x3,0x3,0x17,0x3,0x4c, + 0x4b,0x4b,0x42,0x42,0x0,0x0,0x4b,0x57,0x4b,0x57,0x53,0x51,0x42,0x4a,0x42,0x49,0x45,0x44,0x0,0x41,0x0,0x40,0x27,0x22,0x25,0x17,0x23,0x29,0x13,0x23, + 0x26,0x11,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x6,0x15,0x14,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7, + 0x6,0x6,0x23,0x22,0x27,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x37,0x36,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26, + 0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x36,0x36,0x33,0x6,0x6,0x7,0x21,0x36,0x35,0x34,0x26,0x23,0x0,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36, + 0x36,0x37,0x37,0x4,0x27,0x76,0xc,0x5,0x23,0x22,0xfe,0x71,0xc,0x78,0x30,0x56,0x32,0x14,0x16,0xe,0x1b,0x9,0xd,0x25,0x41,0x84,0x46,0xa3,0x38,0x3c, + 0x9f,0x50,0x44,0x67,0x38,0x65,0x5b,0x84,0xcb,0x4,0x9,0x31,0x38,0x57,0x6a,0x13,0x13,0x1d,0x17,0x10,0x1f,0x47,0x8b,0x49,0x99,0x30,0x31,0x7c,0x47,0x54, + 0x61,0x20,0x1,0x2c,0x5,0x32,0x37,0xfd,0xf1,0x53,0x39,0x3e,0x31,0x2b,0x38,0x66,0x46,0xb,0x12,0x3,0xb2,0x9c,0x8f,0x43,0x4e,0x21,0x1d,0x4c,0x38,0xb9, + 0x25,0x29,0x11,0x10,0xf,0x14,0x14,0x22,0x1d,0x35,0x35,0x90,0x43,0x4d,0x36,0x62,0x41,0x62,0xa9,0x30,0x46,0x16,0x32,0x25,0x38,0x38,0x48,0xd,0x20,0x18, + 0x14,0x1d,0x17,0x35,0x31,0x74,0x39,0x3b,0x91,0x68,0x75,0x2a,0x1b,0x4a,0x4e,0xfe,0x97,0x2a,0x1d,0x64,0x3c,0x2b,0x2f,0x39,0x65,0x3f,0x64,0x0,0x0,0x2, + 0x0,0x81,0xff,0xea,0x4,0x53,0x5,0x2a,0x0,0x22,0x0,0x30,0x0,0x8f,0x4b,0xb0,0x28,0x50,0x58,0x40,0x12,0x2,0x1,0x0,0x3,0x5,0x1,0x5,0x0,0x13, + 0x1,0x4,0x5,0x1b,0x1,0x1,0x4,0x4,0x4a,0x1b,0x40,0x12,0x2,0x1,0x0,0x3,0x5,0x1,0x5,0x0,0x13,0x1,0x4,0x5,0x1b,0x1,0x2,0x4,0x4,0x4a, + 0x59,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1d,0x6,0x1,0x3,0x3,0x10,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x0,0x4,0x4,0x1,0x5b, + 0x2,0x1,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x21,0x6,0x1,0x3,0x3,0x10,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x0,0x2,0x2, + 0xf,0x4b,0x0,0x4,0x4,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x14,0x23,0x23,0x0,0x0,0x23,0x30,0x23,0x2f,0x2a,0x28,0x0,0x22,0x0,0x20, + 0x35,0x26,0x27,0x8,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x2,0x6,0x23,0x22,0x26,0x27,0x7,0x6,0x6, + 0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x12,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x1,0xd1,0x1e,0x2, + 0x50,0x47,0xa7,0x5e,0x6b,0xa4,0x5b,0x72,0xe8,0xa6,0x65,0x9b,0x31,0x13,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xd4,0x6,0x27,0x28,0x2,0xaf,0xa9,0x5a,0x8a, + 0x75,0x6c,0xa0,0x55,0x7a,0x71,0x5,0x2a,0x15,0x18,0x4,0x10,0xfe,0x39,0x46,0x4a,0x5f,0xaf,0x76,0x8a,0xfe,0xf4,0xae,0x5d,0x57,0x67,0x24,0x1d,0x15,0x17, + 0x5,0x10,0x4,0xb2,0x23,0x1e,0xfd,0xf4,0x76,0xbf,0x6a,0x79,0x88,0x7a,0xc3,0x6a,0x72,0x87,0x0,0x0,0x0,0x1,0x0,0x9a,0xff,0xea,0x4,0x5a,0x3,0xb2, + 0x0,0x2b,0x0,0x36,0x40,0x33,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x0,0x3,0x2,0x1,0x3,0x2,0x6e,0x0,0x1,0x1,0x5,0x5b,0x6,0x1,0x5,0x5, + 0x19,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x0,0x0,0x0,0x2b,0x0,0x2a,0x27,0x23,0x26,0x24,0x17,0x7,0x7,0x19,0x2b,0x0,0x16, + 0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14, + 0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0x3,0x2f,0xba,0x4b,0x26,0xd,0x17,0x21,0x11,0x14,0x40,0x9c,0x4f,0x70,0xb7,0x69,0x41,0x7b, + 0x54,0x58,0xb1,0x4a,0x13,0x11,0x23,0x15,0xc,0x29,0x55,0xe0,0x6d,0x7e,0xba,0x63,0x8f,0x1,0x2,0xa5,0x3,0xb2,0x39,0x36,0x1b,0x23,0x15,0x17,0x28,0xd, + 0x2f,0x31,0x70,0xbc,0x6b,0x4e,0x78,0x43,0x2f,0x2b,0xb,0x2c,0x18,0x13,0x25,0x16,0x30,0x37,0x68,0xb7,0x73,0x94,0x1,0x4,0x9e,0x0,0x0,0x0,0xff,0xff, + 0x0,0x9a,0xff,0xea,0x4,0x5a,0x5,0x5e,0x0,0x22,0x1,0x80,0xf6,0x0,0x0,0x2,0x0,0x8b,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x62, + 0x5,0x6e,0x0,0x26,0x1,0x83,0x0,0xa,0x1,0x2,0x0,0x8b,0x0,0x0,0x0,0x8,0xb1,0x0,0x1,0xb0,0xa,0xb0,0x33,0x2b,0x0,0x1,0x0,0x9a,0xfe,0x28, + 0x4,0x5a,0x3,0xb2,0x0,0x4e,0x0,0x58,0x40,0x55,0x43,0x1,0x4,0x2,0x40,0x1,0x9,0x5,0x2,0x4a,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x0,0x3, + 0x2,0x1,0x3,0x2,0x6e,0x0,0x7,0x9,0x8,0x9,0x7,0x8,0x70,0x0,0x5,0x0,0x9,0x7,0x5,0x9,0x63,0x0,0x8,0x0,0x6,0x8,0x6,0x5f,0x0,0x1, + 0x1,0xa,0x5b,0x0,0xa,0xa,0x19,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x4c,0x4a,0x3f,0x3c,0x23,0x28,0x26,0x11,0x17,0x23,0x26, + 0x24,0x14,0xb,0x7,0x1d,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33, + 0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x7,0x7,0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17, + 0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x23,0x7,0x22,0x35,0x34,0x37,0x37,0x2e,0x2,0x35,0x34,0x12,0x24,0x33,0x32,0x16,0x17,0x4,0x5a,0xd,0x17,0x21,0x11, + 0x14,0x40,0x9c,0x4f,0x70,0xb7,0x69,0x41,0x7b,0x54,0x58,0xb1,0x4a,0x13,0x11,0x23,0x15,0xc,0x29,0x4b,0xbf,0x61,0x11,0x58,0x5a,0x1c,0x1a,0x45,0x97,0x44, + 0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64,0x31,0x3a,0x3a,0x67,0x23,0x1d,0x1,0x1b,0x66,0x96,0x4f,0x8f,0x1,0x2,0xa5,0x5f,0xba,0x4b,0x3, + 0x28,0x23,0x15,0x17,0x28,0xd,0x2f,0x31,0x70,0xbc,0x6b,0x4e,0x78,0x43,0x2f,0x2b,0xb,0x2c,0x18,0x13,0x25,0x16,0x2a,0x35,0x6,0x5e,0x2,0x52,0x40,0x22, + 0x4f,0x1b,0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15,0x2,0xf,0x13,0x2d,0x24,0x37,0x1,0x1c,0x9,0x5,0x9f,0x10,0x6d,0xa8,0x67,0x94,0x1,0x4,0x9e, + 0x39,0x36,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x5a,0x5,0x60,0x0,0x22,0x0,0x8b,0x0,0x0,0x0,0x2,0x1,0x92,0xa,0x0,0x0,0x0,0xff,0xff,0x0,0x9a, + 0xff,0xea,0x4,0x5a,0x5,0x51,0x0,0x22,0x0,0x8b,0x0,0x0,0x0,0x2,0x1,0x94,0xf6,0x0,0x0,0x0,0x0,0x2,0x0,0x8f,0xff,0xea,0x4,0xa5,0x5,0x2a, + 0x0,0x21,0x0,0x2f,0x0,0x71,0x40,0xf,0x2,0x1,0x2,0x3,0x1c,0xf,0x2,0x5,0x4,0xc,0x1,0x0,0x5,0x3,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1d, + 0x6,0x1,0x3,0x3,0x10,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x1,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b, + 0x40,0x21,0x6,0x1,0x3,0x3,0x10,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x0,0x0,0xf,0x4b,0x7,0x1,0x5,0x5,0x1,0x5b,0x0, + 0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x14,0x22,0x22,0x0,0x0,0x22,0x2f,0x22,0x2e,0x29,0x27,0x0,0x21,0x0,0x1f,0x26,0x26,0x37,0x8,0x7,0x17,0x2b,0x0, + 0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x36,0x33,0x32,0x16,0x17,0x13,0x36, + 0x36,0x33,0x33,0x0,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x4,0x87,0x1e,0x2,0xd4,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xe, + 0x97,0xc1,0x6b,0xa4,0x5b,0x72,0xe8,0xa6,0x63,0x98,0x2f,0x54,0x6,0x27,0x28,0x2,0xfe,0x21,0xa9,0x5a,0x8a,0x75,0x6c,0xa0,0x55,0x7a,0x71,0x5,0x2a,0x15, + 0x18,0x4,0x10,0xfb,0x4e,0x24,0x1d,0x15,0x17,0x5,0x10,0x4f,0x9c,0x5f,0xaf,0x76,0x8a,0x1,0xc,0xae,0x58,0x51,0x1,0xe0,0x23,0x1e,0xfb,0x54,0x76,0xbf, + 0x6a,0x79,0x88,0x7a,0xc3,0x6a,0x72,0x87,0x0,0x0,0x0,0x2,0x0,0x8e,0xff,0xea,0x4,0x7c,0x5,0x35,0x0,0x35,0x0,0x43,0x0,0xab,0x40,0xd,0x2f,0x23, + 0x19,0x4,0x4,0x2,0x4,0x17,0x1,0x5,0x1,0x2,0x4a,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x28,0x0,0x2,0x4,0x1,0x4,0x2,0x1,0x70,0x0,0x3,0x3,0x10, + 0x4b,0x0,0x4,0x4,0x10,0x4b,0x0,0x5,0x5,0x1,0x5b,0x0,0x1,0x1,0x11,0x4b,0x7,0x1,0x6,0x6,0x0,0x5c,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x4b, + 0xb0,0x20,0x50,0x58,0x40,0x26,0x0,0x2,0x4,0x1,0x4,0x2,0x1,0x70,0x0,0x1,0x0,0x5,0x6,0x1,0x5,0x63,0x0,0x3,0x3,0x10,0x4b,0x0,0x4,0x4, + 0x10,0x4b,0x7,0x1,0x6,0x6,0x0,0x5c,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x28,0x0,0x4,0x3,0x2,0x3,0x4,0x2,0x70,0x0,0x2,0x1,0x3,0x2, + 0x1,0x6e,0x0,0x1,0x0,0x5,0x6,0x1,0x5,0x63,0x0,0x3,0x3,0x10,0x4b,0x7,0x1,0x6,0x6,0x0,0x5c,0x0,0x0,0x0,0x17,0x0,0x4c,0x59,0x59,0x40, + 0xf,0x36,0x36,0x36,0x43,0x36,0x42,0x28,0x26,0x1d,0x26,0x26,0x2b,0x8,0x7,0x1a,0x2b,0x0,0x15,0x14,0x7,0x7,0x16,0x11,0x14,0x7,0xe,0x2,0x23,0x22, + 0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x26,0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33, + 0x32,0x17,0x16,0x17,0x37,0x36,0x33,0x32,0x16,0x17,0x0,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x4,0x7c,0x2e,0xb9,0xbd,0x10, + 0x18,0x97,0xe5,0x88,0x77,0xba,0x67,0x86,0xfa,0xa4,0x43,0x7a,0x32,0x33,0x72,0xfe,0x12,0xd,0x27,0xf,0x7,0x2f,0xab,0x30,0x37,0x23,0xf,0x1a,0x20,0x12, + 0x11,0x72,0x56,0xfb,0x15,0xc,0x13,0x19,0x8,0xfe,0x30,0xab,0x5d,0x8f,0x7d,0x6d,0xab,0x60,0x8f,0x7d,0x4,0xc6,0xf,0x25,0x10,0x41,0xd5,0xfe,0xdf,0x56, + 0x59,0x86,0xc4,0x68,0x62,0xaf,0x70,0x8c,0xef,0x90,0x2c,0x27,0x81,0x67,0x59,0x6,0x30,0x17,0xb,0x24,0x10,0x3c,0x20,0x1d,0x12,0x1e,0x14,0x19,0x2d,0xa, + 0x3c,0x45,0x58,0x7,0x18,0x19,0xfb,0xa6,0x68,0xaa,0x60,0x70,0x82,0x64,0xaa,0x65,0x6f,0x82,0x0,0x3,0x0,0x85,0xff,0xea,0x5,0xe6,0x5,0x2a,0x0,0x22, + 0x0,0x34,0x0,0x42,0x0,0xd6,0x4b,0xb0,0x31,0x50,0x58,0x40,0xf,0x2,0x1,0x2,0x3,0x1d,0x1,0x7,0x6,0xf,0xc,0x2,0x0,0x7,0x3,0x4a,0x1b,0x40, + 0xf,0x2,0x1,0x2,0x5,0x1d,0x1,0x7,0x6,0xf,0xc,0x2,0x0,0x7,0x3,0x4a,0x59,0x4b,0xb0,0x28,0x50,0x58,0x40,0x26,0x0,0x4,0x2,0x6,0x2,0x4, + 0x6,0x70,0x5,0x8,0x2,0x3,0x3,0x10,0x4b,0x0,0x6,0x6,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x9,0x1,0x7,0x7,0x0,0x5b,0x1,0x1,0x0,0x0,0xf, + 0x0,0x4c,0x1b,0x4b,0xb0,0x31,0x50,0x58,0x40,0x2a,0x0,0x4,0x2,0x6,0x2,0x4,0x6,0x70,0x5,0x8,0x2,0x3,0x3,0x10,0x4b,0x0,0x6,0x6,0x2,0x5b, + 0x0,0x2,0x2,0x19,0x4b,0x0,0x0,0x0,0xf,0x4b,0x9,0x1,0x7,0x7,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x2e,0x0,0x4,0x2,0x6,0x2, + 0x4,0x6,0x70,0x8,0x1,0x3,0x3,0x10,0x4b,0x0,0x5,0x5,0x10,0x4b,0x0,0x6,0x6,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x0,0x0,0xf,0x4b,0x9, + 0x1,0x7,0x7,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x59,0x40,0x18,0x35,0x35,0x0,0x0,0x35,0x42,0x35,0x41,0x3c,0x3a,0x34,0x32,0x2b,0x29,0x0, + 0x22,0x0,0x20,0x26,0x27,0x37,0xa,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x6,0x6,0x23,0x22, + 0x26,0x26,0x35,0x34,0x12,0x36,0x33,0x32,0x16,0x17,0x13,0x36,0x36,0x33,0x33,0x4,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36, + 0x36,0x33,0x33,0x0,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x4,0x19,0x1e,0x2,0xd4,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xa, + 0x3c,0x90,0x4c,0x5f,0x92,0x51,0x69,0xd6,0x99,0x4d,0x80,0x24,0x51,0x6,0x27,0x28,0x2,0x1,0xe0,0x10,0x8,0xf4,0x14,0x25,0x19,0x1e,0x4,0x93,0x6,0x12, + 0x12,0x8e,0xfc,0x78,0x8e,0x4b,0x69,0x5a,0x60,0x8e,0x4b,0x66,0x5d,0x5,0x2a,0x15,0x18,0x4,0x10,0xfb,0x4e,0x24,0x1d,0x15,0x17,0x5,0x10,0x3a,0x42,0x45, + 0x5f,0xaf,0x76,0x8a,0x1,0xc,0xae,0x51,0x44,0x1,0xcc,0x23,0x1e,0xa,0x11,0xd,0xc,0xe,0xfe,0x94,0x1e,0x18,0x13,0x6,0xc,0x1,0x6a,0xf,0xc,0xfb, + 0x5e,0x76,0xbf,0x6a,0x79,0x88,0x7a,0xc3,0x6a,0x72,0x87,0x0,0x0,0x0,0x0,0x2,0x0,0x9f,0xff,0xea,0x5,0x3d,0x5,0x2a,0x0,0x38,0x0,0x46,0x0,0xbc, + 0x40,0x14,0x34,0x1,0x5,0x6,0x26,0x2,0x2,0x0,0x5,0x21,0x13,0x2,0x9,0x8,0x10,0x1,0x1,0x9,0x4,0x4a,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x29,0x0, + 0x6,0x6,0x10,0x4b,0x4,0x1,0x0,0x0,0x5,0x5b,0xa,0x7,0x2,0x5,0x5,0xe,0x4b,0x0,0x8,0x8,0x3,0x5b,0x0,0x3,0x3,0x11,0x4b,0xb,0x1,0x9, + 0x9,0x1,0x5b,0x2,0x1,0x1,0x1,0xf,0x1,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x25,0xa,0x7,0x2,0x5,0x4,0x1,0x0,0x3,0x5,0x0,0x64,0x0, + 0x3,0x0,0x8,0x9,0x3,0x8,0x63,0x0,0x6,0x6,0x10,0x4b,0xb,0x1,0x9,0x9,0x1,0x5b,0x2,0x1,0x1,0x1,0xf,0x1,0x4c,0x1b,0x40,0x29,0xa,0x7, + 0x2,0x5,0x4,0x1,0x0,0x3,0x5,0x0,0x64,0x0,0x3,0x0,0x8,0x9,0x3,0x8,0x63,0x0,0x6,0x6,0x10,0x4b,0x0,0x1,0x1,0xf,0x4b,0xb,0x1,0x9, + 0x9,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x59,0x59,0x40,0x18,0x39,0x39,0x0,0x0,0x39,0x46,0x39,0x45,0x40,0x3e,0x0,0x38,0x0,0x37,0x33,0x26,0x23, + 0x26,0x27,0x33,0x26,0xc,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x6,0x6, + 0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x36,0x36,0x33,0x33,0x32,0x16, + 0x15,0x14,0x7,0x7,0x33,0x0,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x5,0x23,0x1a,0x3,0x7,0x23,0x22,0x8a,0xa8,0x6,0x24, + 0x27,0x2,0x20,0x1b,0x2,0xc,0x44,0xa0,0x59,0x68,0x9f,0x59,0x79,0xdc,0x8d,0x5d,0x91,0x2f,0x30,0xfe,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfd,0x13,0x6,0x26, + 0x29,0x2,0x23,0x1e,0x2,0x13,0x8b,0xfd,0x78,0x9e,0x51,0x82,0x6e,0x67,0x94,0x4c,0x71,0x6a,0x4,0x7e,0x16,0x18,0xb,0xf,0x27,0x21,0xfc,0x49,0x23,0x1e, + 0x14,0x16,0x7,0x10,0x48,0x47,0x4e,0x58,0xa7,0x72,0x93,0xf7,0x91,0x50,0x47,0x1,0xf,0x16,0x18,0xb,0xf,0x27,0x21,0x6b,0x23,0x1e,0x15,0x18,0x4,0x10, + 0x6b,0xfc,0x0,0x6f,0xae,0x5c,0x6f,0x7c,0x71,0xb1,0x5c,0x69,0x7d,0x0,0x0,0x0,0x0,0x2,0x0,0x9a,0xff,0xea,0x4,0x39,0x3,0xb2,0x0,0x20,0x0,0x2c, + 0x0,0x35,0x40,0x32,0x24,0x1a,0x2,0x0,0x4,0x1,0x4a,0x0,0x0,0x4,0x3,0x4,0x0,0x3,0x70,0x5,0x1,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b, + 0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x17,0x1,0x4c,0x21,0x21,0x21,0x2c,0x21,0x2b,0x28,0x26,0x28,0x20,0x6,0x7,0x18,0x2b,0x24,0x33,0x32,0x17,0x16, + 0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0x32,0x16,0x16,0x15,0x14,0x7,0x5,0x16,0x16,0x33,0x32,0x36,0x37,0x0,0x6, + 0x6,0x7,0x25,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0xb5,0x9,0x26,0x12,0x6,0x17,0x18,0x59,0xe5,0x70,0x7c,0xaf,0x5a,0x90,0x1,0x3,0xa6,0x6d,0xa2, + 0x57,0xe0,0xfd,0xd9,0x2,0x83,0x77,0x60,0xc6,0x51,0xfe,0xba,0x9f,0x68,0x16,0x1,0xf8,0x38,0x2d,0x32,0x63,0x46,0xde,0x38,0x15,0xf,0x17,0x1e,0xb,0x27, + 0x31,0x5b,0xa9,0x74,0xa4,0x1,0xf,0x9d,0x4b,0x85,0x53,0xdc,0x18,0x39,0x76,0x71,0x33,0x29,0x2,0x4a,0x4f,0x8c,0x5a,0x3a,0x6,0x30,0x2e,0x2b,0x44,0x28, + 0x0,0x0,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x39,0x5,0x5e,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x80,0xcc,0x0,0x0,0x0,0xff,0xff,0x0,0x9a, + 0xff,0xea,0x4,0x71,0x5,0x4e,0x0,0x22,0x1,0x82,0xec,0x0,0x0,0x2,0x0,0x95,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x4e,0x5,0x6e, + 0x0,0x26,0x1,0x83,0xec,0xa,0x1,0x2,0x0,0x95,0x0,0x0,0x0,0x8,0xb1,0x0,0x1,0xb0,0xa,0xb0,0x33,0x2b,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x39, + 0x5,0x60,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x92,0xf6,0x0,0x0,0x0,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x39,0x5,0x28,0x0,0x22,0x0,0x95, + 0x0,0x0,0x0,0x2,0x1,0x93,0xec,0x0,0x0,0x0,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x39,0x5,0x51,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x94, + 0xec,0x0,0x0,0x0,0xff,0xff,0x0,0x9a,0xff,0xea,0x4,0x39,0x5,0x5e,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x95,0xc,0x0,0x0,0x0,0xff,0xff, + 0x0,0x9a,0xff,0xea,0x4,0x40,0x4,0xe2,0x0,0x22,0x0,0x95,0x0,0x0,0x0,0x2,0x1,0x97,0xf6,0x0,0x0,0x0,0x0,0x2,0x0,0x9a,0xfe,0x28,0x4,0x39, + 0x3,0xb2,0x0,0x35,0x0,0x41,0x0,0x85,0x40,0xb,0x39,0x6,0x2,0x1,0x7,0x2b,0x1,0x5,0x0,0x2,0x4a,0x4b,0xb0,0x31,0x50,0x58,0x40,0x27,0x0,0x1, + 0x7,0x0,0x7,0x1,0x0,0x70,0x3,0x1,0x2,0x0,0x4,0x2,0x4,0x5f,0x9,0x1,0x7,0x7,0x6,0x5b,0x8,0x1,0x6,0x6,0x19,0x4b,0x0,0x0,0x0,0x5, + 0x5b,0x0,0x5,0x5,0x17,0x5,0x4c,0x1b,0x40,0x2e,0x0,0x1,0x7,0x0,0x7,0x1,0x0,0x70,0x0,0x3,0x5,0x2,0x5,0x3,0x2,0x70,0x0,0x2,0x0,0x4, + 0x2,0x4,0x5f,0x9,0x1,0x7,0x7,0x6,0x5b,0x8,0x1,0x6,0x6,0x19,0x4b,0x0,0x0,0x0,0x5,0x5b,0x0,0x5,0x5,0x17,0x5,0x4c,0x59,0x40,0x15,0x36, + 0x36,0x0,0x0,0x36,0x41,0x36,0x40,0x0,0x35,0x0,0x34,0x26,0x26,0x21,0x2a,0x23,0x28,0xa,0x7,0x1a,0x2b,0x0,0x16,0x16,0x15,0x14,0x7,0x5,0x16,0x16, + 0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22, + 0x26,0x35,0x34,0x36,0x37,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0xe,0x2,0x7,0x25,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0x40,0xa2,0x57, + 0xe0,0xfd,0xd9,0x2,0x83,0x77,0x60,0xc6,0x51,0x10,0x9,0x26,0x12,0x6,0x18,0xad,0x9b,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56, + 0x60,0x5d,0x4e,0x50,0x7c,0xaf,0x5a,0x90,0x1,0x3,0xa6,0x74,0x9f,0x68,0x16,0x1,0xf8,0x38,0x2d,0x32,0x63,0x46,0x3,0xb2,0x4b,0x85,0x53,0xdc,0x18,0x39, + 0x76,0x71,0x33,0x29,0x7,0x38,0x13,0xf,0x1c,0x12,0x7b,0xb0,0x40,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x4d,0x94,0x4b,0xc,0x5b, + 0xa9,0x74,0xa4,0x1,0xf,0x9d,0x91,0x4f,0x8c,0x5a,0x3a,0x6,0x30,0x2e,0x2b,0x44,0x28,0x0,0x0,0x0,0x0,0x1,0x0,0xfb,0xfe,0x72,0x4,0xe5,0x5,0x25, + 0x0,0x31,0x0,0x3f,0x40,0x3c,0x1,0x1,0x1,0x7,0x25,0x10,0x2,0x3,0x2,0x1e,0x1,0x4,0x3,0x3,0x4a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x6, + 0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0x0,0x1,0x1,0x7,0x5b,0x0,0x7,0x7,0x10,0x4b,0x0,0x4,0x4,0x13,0x4,0x4c,0x23,0x26,0x25,0x33,0x26, + 0x22,0x23,0x14,0x8,0x7,0x1c,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x7,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21, + 0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x36,0x36,0x33,0x32,0x17,0x4,0xe5,0x6, + 0x13,0x26,0xa,0xf,0x75,0x6f,0xca,0x26,0x13,0x1,0x59,0x1c,0x19,0x2,0x8,0x22,0x22,0xfe,0xa6,0xb6,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xb6,0xc6,0x1b, + 0x1a,0x3,0x7,0x22,0x22,0xc6,0x16,0x1e,0xd0,0xa6,0x86,0x7b,0x4,0xdf,0x27,0xe,0x14,0x37,0x5,0x2f,0xd9,0x6e,0x16,0x19,0xf,0xa,0x27,0x21,0xfb,0xf7, + 0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x9,0x15,0x18,0xc,0xf,0x27,0x21,0x7b,0xa6,0xb8,0x33,0x0,0x2,0x0,0x4c,0xfe,0x66,0x4,0x61,0x3,0xb2,0x0,0x2c, + 0x0,0x3a,0x0,0xbf,0x40,0x12,0xa,0x1,0x7,0x0,0x2,0x1,0x6,0x7,0x21,0x1,0x4,0x6,0x14,0x1,0x1,0x3,0x4,0x4a,0x4b,0xb0,0x24,0x50,0x58,0x40, + 0x2a,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x9,0x1,0x7,0x7,0x0,0x5b,0x8,0x5,0x2,0x0,0x0,0x11,0x4b,0x0,0x6,0x6,0x4,0x5b,0x0,0x4,0x4, + 0xf,0x4b,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x13,0x1,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x28,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0, + 0x6,0x0,0x4,0x2,0x6,0x4,0x63,0x9,0x1,0x7,0x7,0x0,0x5b,0x8,0x5,0x2,0x0,0x0,0x11,0x4b,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x13,0x1, + 0x4c,0x1b,0x40,0x2c,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x6,0x0,0x4,0x2,0x6,0x4,0x63,0x0,0x0,0x0,0x11,0x4b,0x9,0x1,0x7,0x7,0x5, + 0x5b,0x8,0x1,0x5,0x5,0x19,0x4b,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x1,0x13,0x1,0x4c,0x59,0x59,0x40,0x16,0x2d,0x2d,0x0,0x0,0x2d,0x3a,0x2d,0x39, + 0x34,0x32,0x0,0x2c,0x0,0x2b,0x25,0x24,0x16,0x27,0x35,0xa,0x7,0x19,0x2b,0x0,0x16,0x17,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6, + 0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x37,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33, + 0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x2,0xfc,0x96,0x2e,0x13,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xa1,0x20,0xf5,0xc9,0xc9, + 0xa7,0x24,0x9,0x15,0x25,0xe,0xa,0x49,0xac,0x54,0x87,0xa3,0x13,0x20,0x49,0xa2,0x61,0x6b,0xa6,0x5b,0x7c,0xea,0x9e,0x7b,0x9e,0x52,0x7c,0x72,0x76,0xa6, + 0x54,0x8d,0x76,0x3,0xb2,0x5e,0x56,0x67,0x24,0x1d,0x15,0x17,0x5,0x10,0xfc,0x73,0xb3,0xbf,0x46,0xe,0x25,0x13,0x18,0x37,0x5,0x20,0x22,0x84,0x71,0xb9, + 0x47,0x45,0x5b,0xa9,0x70,0x91,0xfa,0x97,0x94,0x6f,0xb1,0x62,0x6c,0x80,0x71,0xb0,0x5b,0x72,0x80,0x0,0x0,0x0,0xff,0xff,0x0,0x4c,0xfe,0x66,0x4,0x67, + 0x5,0x4e,0x0,0x22,0x1,0x82,0xe2,0x0,0x0,0x2,0x0,0xa0,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x4c,0xfe,0x66,0x4,0x61,0x5,0x60,0x0,0x22,0x1,0x92, + 0xec,0x0,0x0,0x2,0x0,0xa0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x4c,0xfe,0x66,0x4,0x61,0x5,0xa3,0x0,0x11,0x0,0x3e,0x0,0x4c,0x0,0xe3,0x40,0x16, + 0xe,0x1,0x1,0x0,0x1c,0x1,0x9,0x2,0x14,0x1,0x8,0x9,0x33,0x1,0x6,0x8,0x26,0x1,0x3,0x5,0x5,0x4a,0x4b,0xb0,0x24,0x50,0x58,0x40,0x34,0x0, + 0x0,0x1,0x0,0x72,0x0,0x1,0x2,0x1,0x72,0x0,0x4,0x6,0x5,0x6,0x4,0x5,0x70,0xb,0x1,0x9,0x9,0x2,0x5b,0xa,0x7,0x2,0x2,0x2,0x11,0x4b, + 0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0xf,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x13,0x3,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x32,0x0, + 0x0,0x1,0x0,0x72,0x0,0x1,0x2,0x1,0x72,0x0,0x4,0x6,0x5,0x6,0x4,0x5,0x70,0x0,0x8,0x0,0x6,0x4,0x8,0x6,0x63,0xb,0x1,0x9,0x9,0x2, + 0x5b,0xa,0x7,0x2,0x2,0x2,0x11,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x13,0x3,0x4c,0x1b,0x40,0x36,0x0,0x0,0x1,0x0,0x72,0x0,0x1,0x7, + 0x1,0x72,0x0,0x4,0x6,0x5,0x6,0x4,0x5,0x70,0x0,0x8,0x0,0x6,0x4,0x8,0x6,0x63,0x0,0x2,0x2,0x11,0x4b,0xb,0x1,0x9,0x9,0x7,0x5b,0xa, + 0x1,0x7,0x7,0x19,0x4b,0x0,0x5,0x5,0x3,0x5b,0x0,0x3,0x3,0x13,0x3,0x4c,0x59,0x59,0x40,0x18,0x3f,0x3f,0x12,0x12,0x3f,0x4c,0x3f,0x4b,0x46,0x44, + 0x12,0x3e,0x12,0x3d,0x25,0x24,0x16,0x27,0x3a,0x37,0x21,0xc,0x7,0x1b,0x2b,0x0,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x35, + 0x34,0x37,0x13,0x2,0x16,0x17,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17, + 0x16,0x16,0x33,0x32,0x36,0x37,0x37,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26, + 0x23,0x3,0x25,0x28,0x17,0x16,0x17,0x4,0x6e,0x6,0x19,0x11,0x8e,0x18,0xb,0xc6,0x1e,0x96,0x2e,0x13,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xa1,0x20,0xf5, + 0xc9,0xc9,0xa7,0x24,0x9,0x15,0x25,0xe,0xa,0x49,0xac,0x54,0x87,0xa3,0x13,0x20,0x49,0xa2,0x61,0x6b,0xa6,0x5b,0x7c,0xea,0x9e,0x7b,0x9e,0x52,0x7c,0x72, + 0x76,0xa6,0x54,0x8d,0x76,0x5,0x8f,0x14,0x12,0x11,0xa,0xb,0xfe,0xdd,0x10,0x10,0x15,0xf,0xf,0x1,0x23,0xfe,0x34,0x5e,0x56,0x67,0x24,0x1d,0x15,0x17, + 0x5,0x10,0xfc,0x73,0xb3,0xbf,0x46,0xe,0x25,0x13,0x18,0x37,0x5,0x20,0x22,0x84,0x71,0xb9,0x47,0x45,0x5b,0xa9,0x70,0x91,0xfa,0x97,0x94,0x6f,0xb1,0x62, + 0x6c,0x80,0x71,0xb0,0x5b,0x72,0x80,0x0,0xff,0xff,0x0,0x4c,0xfe,0x66,0x4,0x61,0x5,0x51,0x0,0x22,0x0,0xa0,0x0,0x0,0x0,0x2,0x1,0x94,0xe2,0x0, + 0x0,0x0,0x0,0x1,0x0,0x8b,0xff,0xf6,0x4,0x40,0x5,0x2a,0x0,0x31,0x0,0x33,0x40,0x30,0x2,0x1,0x0,0x4,0x2a,0x16,0x5,0x3,0x1,0x2,0x2,0x4a, + 0x5,0x1,0x4,0x4,0x10,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x19,0x4b,0x3,0x1,0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x0,0x31,0x0,0x2f,0x36, + 0x29,0x38,0x27,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35, + 0x34,0x37,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x1,0xdb,0x1e, + 0x2,0x5d,0x54,0xd8,0x67,0x55,0x7c,0x42,0x7,0x62,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x61,0x5,0x4c,0x4d,0x56,0xba,0x8c,0x13,0x3c,0x6,0x27,0x28,0x2, + 0x23,0x1e,0x2,0xd4,0x6,0x27,0x28,0x2,0x5,0x2a,0x15,0x18,0x4,0x10,0xfd,0xf2,0x61,0x76,0x40,0x75,0x4f,0x26,0x26,0xfd,0xd5,0x23,0x1e,0x15,0x18,0x4, + 0x10,0x2,0x26,0x20,0x16,0x42,0x49,0x6d,0xbb,0x6e,0xfe,0xaf,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0xb2,0x23,0x1e,0x0,0x1,0x0,0x88,0xff,0xf6,0x4,0x21, + 0x5,0x2a,0x0,0x46,0x0,0x74,0x40,0x11,0x35,0x1,0x4,0x5,0x3c,0x27,0x2,0x3,0x4,0x43,0x20,0xc,0x3,0x0,0x1,0x3,0x4a,0x4b,0xb0,0x1b,0x50,0x58, + 0x40,0x23,0x0,0x5,0x5,0x10,0x4b,0x7,0x1,0x3,0x3,0x4,0x5b,0x6,0x1,0x4,0x4,0xe,0x4b,0x0,0x1,0x1,0x8,0x5b,0x9,0x1,0x8,0x8,0x11,0x4b, + 0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40,0x1f,0x6,0x1,0x4,0x7,0x1,0x3,0x8,0x4,0x3,0x64,0x9,0x1,0x8,0x0,0x1,0x0,0x8,0x1,0x63,0x0, + 0x5,0x5,0x10,0x4b,0x2,0x1,0x0,0x0,0xf,0x0,0x4c,0x59,0x40,0x11,0x0,0x0,0x0,0x46,0x0,0x45,0x26,0x25,0x33,0x26,0x25,0x36,0x29,0x37,0xa,0x7, + 0x1c,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x7,0x3,0x6,0x6, + 0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x33, + 0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x36,0x36,0x33,0x3,0x96,0x8b,0x7,0x57,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x56,0x5,0x46,0x49,0x4e, + 0xac,0x82,0x12,0x34,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xa8,0x8c,0x1b,0x1a,0x3,0x7,0x23,0x22,0x8b,0x13,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x13,0xfd, + 0x1b,0x1a,0x3,0x7,0x23,0x22,0xfc,0x38,0x53,0xc2,0x5c,0x3,0x76,0x8b,0x78,0x27,0x27,0xfe,0x12,0x23,0x1e,0x15,0x18,0x4,0x10,0x1,0xea,0x1c,0x1b,0x42, + 0x48,0x68,0xb2,0x68,0xfe,0xd7,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0xb7,0x16,0x18,0xb,0xf,0x27,0x21,0x6b,0x23,0x1e,0x15,0x18,0x4,0x10,0x6b,0x16,0x18, + 0xb,0xf,0x27,0x21,0xfe,0xc8,0x59,0x67,0xff,0xff,0x0,0x8b,0xff,0xf6,0x4,0x65,0x6,0xd2,0x0,0x27,0x1,0x92,0x0,0x28,0x1,0x72,0x1,0x2,0x0,0xa5, + 0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0x72,0xb0,0x33,0x2b,0x0,0x0,0x2,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x53,0x0,0x11,0x0,0x39,0x0,0x88, + 0x40,0x10,0xb,0x2,0x2,0x0,0x1,0x33,0x14,0x2,0x5,0x6,0x24,0x1,0x4,0x2,0x3,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x29,0x0,0x3,0x5,0x2,0x5, + 0x3,0x2,0x70,0x0,0x0,0x0,0x1,0x5b,0x7,0x1,0x1,0x1,0x10,0x4b,0x0,0x5,0x5,0x6,0x59,0x8,0x1,0x6,0x6,0x11,0x4b,0x0,0x2,0x2,0x4,0x5b, + 0x0,0x4,0x4,0x17,0x4,0x4c,0x1b,0x40,0x27,0x0,0x3,0x5,0x2,0x5,0x3,0x2,0x70,0x7,0x1,0x1,0x0,0x0,0x6,0x1,0x0,0x63,0x0,0x5,0x5,0x6, + 0x59,0x8,0x1,0x6,0x6,0x11,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x59,0x40,0x18,0x12,0x12,0x0,0x0,0x12,0x39,0x12,0x37,0x31, + 0x2f,0x2a,0x28,0x21,0x1f,0x1d,0x1b,0x0,0x11,0x0,0x10,0x27,0x9,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37, + 0x37,0x36,0x36,0x33,0x2,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26, + 0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x2,0xf3,0x26,0x2,0x17,0x6,0x2d,0x37,0x30,0x26,0x2,0x17,0x6,0x2e,0x37,0x14, + 0x1b,0x2,0x60,0x7,0x40,0x46,0x6a,0x70,0x10,0x6,0x29,0xc,0x3,0x18,0x1a,0x87,0x7e,0x81,0x8c,0x7,0x53,0xfd,0x1b,0x1a,0x3,0x7,0x22,0x22,0x1,0x52, + 0x5,0x53,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0xfe,0x49,0x15,0x18,0xe,0x9,0xfd,0xde,0x2a,0x18,0x3f,0x39,0x22,0x4, + 0x39,0xf,0xd,0x19,0x1d,0x8,0x25,0x85,0x76,0x28,0x26,0x1,0xd9,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xf4,0xff,0xea,0x4,0x10, + 0x3,0x9c,0x0,0x27,0x0,0x39,0x40,0x36,0x21,0x2,0x2,0x3,0x4,0x12,0x1,0x2,0x0,0x2,0x4a,0x0,0x1,0x3,0x0,0x3,0x1,0x0,0x70,0x0,0x3,0x3, + 0x4,0x59,0x5,0x1,0x4,0x4,0x11,0x4b,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x0,0x0,0x0,0x27,0x0,0x25,0x25,0x27,0x22,0x29,0x6, + 0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35, + 0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x2,0xb0,0x1b,0x2,0x60,0x7,0x40,0x46,0x6a,0x70,0x10,0x6,0x29,0xc,0x3,0x18,0x1a, + 0x87,0x7e,0x81,0x8c,0x7,0x53,0xfd,0x1b,0x1a,0x3,0x7,0x22,0x22,0x1,0x52,0x3,0x9c,0x15,0x18,0xe,0x9,0xfd,0xde,0x2a,0x18,0x3f,0x39,0x22,0x4,0x39, + 0xf,0xd,0x19,0x1d,0x8,0x25,0x85,0x76,0x28,0x26,0x1,0xd9,0x16,0x18,0xb,0xf,0x27,0x21,0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x5e,0x0,0x22, + 0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x80,0x86,0x0,0x0,0x0,0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x4e,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x3, + 0x1,0x82,0xff,0x74,0x0,0x0,0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x60,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x92,0x88,0x0,0x0,0x0, + 0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x28,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x93,0x9c,0x0,0x0,0x0,0xff,0xff,0x0,0xf4,0xff,0xea, + 0x4,0x10,0x5,0x51,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x2,0x1,0x94,0xc4,0x0,0x0,0x0,0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x5e,0x0,0x22, + 0x0,0xa9,0x0,0x0,0x0,0x3,0x1,0x95,0xff,0x6c,0x0,0x0,0x0,0x4,0x0,0xb3,0xfe,0x66,0x4,0x84,0x5,0x53,0x0,0x11,0x0,0x23,0x0,0x37,0x0,0x56, + 0x0,0xa3,0x40,0x13,0x1d,0x14,0xb,0x2,0x4,0x0,0x1,0x3a,0x30,0x26,0x3,0x4,0x5,0x45,0x1,0x6,0x8,0x3,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x2e, + 0x0,0x7,0x4,0x8,0x4,0x7,0x8,0x70,0x2,0x1,0x0,0x0,0x1,0x5b,0xb,0x3,0xa,0x3,0x1,0x1,0x10,0x4b,0xd,0x9,0xc,0x3,0x5,0x5,0x11,0x4b, + 0x0,0x4,0x4,0xf,0x4b,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0x13,0x6,0x4c,0x1b,0x40,0x2c,0x0,0x7,0x4,0x8,0x4,0x7,0x8,0x70,0xb,0x3,0xa, + 0x3,0x1,0x2,0x1,0x0,0x5,0x1,0x0,0x63,0xd,0x9,0xc,0x3,0x5,0x5,0x11,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6, + 0x13,0x6,0x4c,0x59,0x40,0x26,0x38,0x38,0x24,0x24,0x12,0x12,0x0,0x0,0x38,0x56,0x38,0x54,0x4f,0x4d,0x49,0x48,0x41,0x3f,0x24,0x37,0x24,0x35,0x2e,0x2b, + 0x12,0x23,0x12,0x22,0x1b,0x19,0x0,0x11,0x0,0x10,0x27,0xe,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37, + 0x36,0x36,0x33,0x20,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23, + 0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x20,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32, + 0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x2,0xc,0x26,0x2,0x17,0x6,0x2d,0x37,0x30,0x26,0x2,0x17,0x6,0x2e,0x37,0x2,0x81,0x26, + 0x2,0x17,0x6,0x2d,0x37,0x30,0x26,0x2,0x17,0x6,0x2e,0x37,0xfd,0x90,0x1e,0x2,0x90,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x90,0x6,0x27,0x28,0x2,0x2, + 0x75,0x1e,0x2,0xa3,0x1f,0xb4,0xa9,0x4a,0x92,0x3e,0x21,0xc,0x17,0x22,0xd,0xe,0x3a,0x79,0x38,0x62,0x62,0x14,0xa1,0x6,0x27,0x28,0x2,0x5,0x53,0x15, + 0x19,0x5,0xe,0x82,0x24,0x1d,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0xfe,0x53,0x15, + 0x18,0x4,0x10,0xfc,0xd2,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x2e,0x23,0x1e,0x15,0x18,0x4,0x10,0xfc,0x62,0xb1,0xb0,0x26,0x23,0x13,0x1e,0x13,0x1b,0x33, + 0x8,0x1f,0x22,0x6a,0x72,0x3,0x91,0x23,0x1e,0x0,0x0,0x0,0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x4,0xe2,0x0,0x22,0x0,0xa9,0x0,0x0,0x0,0x3, + 0x1,0x97,0xff,0x7e,0x0,0x0,0x0,0x2,0x0,0xf4,0xfe,0x28,0x4,0x10,0x5,0x53,0x0,0x11,0x0,0x50,0x0,0xd7,0x40,0x11,0xb,0x2,0x2,0x1,0x0,0x42, + 0x39,0x2,0x6,0x7,0x2f,0x13,0x2,0x2,0x8,0x3,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x30,0x0,0x9,0x6,0x8,0x6,0x9,0x8,0x70,0x4,0x1,0x3,0x0, + 0x5,0x3,0x5,0x5f,0xa,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x10,0x4b,0x0,0x6,0x6,0x7,0x59,0x0,0x7,0x7,0x11,0x4b,0x0,0x8,0x8,0x2,0x5b, + 0x0,0x2,0x2,0x17,0x2,0x4c,0x1b,0x4b,0xb0,0x31,0x50,0x58,0x40,0x2e,0x0,0x9,0x6,0x8,0x6,0x9,0x8,0x70,0x0,0x0,0xa,0x1,0x1,0x7,0x0,0x1, + 0x63,0x4,0x1,0x3,0x0,0x5,0x3,0x5,0x5f,0x0,0x6,0x6,0x7,0x59,0x0,0x7,0x7,0x11,0x4b,0x0,0x8,0x8,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c, + 0x1b,0x40,0x35,0x0,0x9,0x6,0x8,0x6,0x9,0x8,0x70,0x0,0x4,0x2,0x3,0x2,0x4,0x3,0x70,0x0,0x0,0xa,0x1,0x1,0x7,0x0,0x1,0x63,0x0,0x3, + 0x0,0x5,0x3,0x5,0x5f,0x0,0x6,0x6,0x7,0x59,0x0,0x7,0x7,0x11,0x4b,0x0,0x8,0x8,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x59,0x59,0x40,0x1a, + 0x0,0x0,0x4f,0x4d,0x4b,0x49,0x40,0x3d,0x37,0x35,0x2a,0x28,0x22,0x20,0x1f,0x1d,0x18,0x17,0x0,0x11,0x0,0x10,0x27,0xb,0x7,0x15,0x2b,0x0,0x26,0x35, + 0x34,0x37,0x37,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x0,0x15,0x14,0x6,0x7,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x37, + 0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x26,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33, + 0x21,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x2,0x66,0x26,0x2,0x17,0x6,0x2e,0x37,0x2f,0x26,0x2,0x17, + 0x6,0x2d,0x37,0x1,0x7a,0x18,0x1a,0x6a,0x68,0x62,0x5d,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56,0x60,0x5f,0x4f,0x55,0x7,0x53, + 0xfd,0x1b,0x1a,0x3,0x7,0x22,0x22,0x1,0x52,0x1c,0x1b,0x2,0x60,0x7,0x40,0x46,0x6a,0x70,0x10,0x6,0x29,0xc,0x4,0x4f,0x15,0x19,0x5,0xe,0x82,0x24, + 0x1d,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0xfc,0xb,0xd,0x19,0x1d,0x8,0x1d,0x6,0x51,0x7e,0x32,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58, + 0x4a,0x4e,0x94,0x4c,0x18,0x7a,0x5b,0x28,0x26,0x1,0xd9,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x18,0xe,0x9,0xfd,0xde,0x2a,0x18,0x3f,0x39,0x22,0x4,0x39, + 0xff,0xff,0x0,0xf4,0xff,0xea,0x4,0x10,0x5,0x11,0x0,0x22,0x1,0x9a,0x9c,0x0,0x0,0x2,0x0,0xa9,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x53,0xfe,0x66, + 0x4,0x27,0x5,0x53,0x0,0x11,0x0,0x36,0x0,0x84,0x40,0xc,0xb,0x2,0x2,0x0,0x1,0x30,0x14,0x2,0x5,0x6,0x2,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40, + 0x29,0x0,0x3,0x5,0x4,0x5,0x3,0x4,0x70,0x0,0x0,0x0,0x1,0x5b,0x7,0x1,0x1,0x1,0x10,0x4b,0x0,0x5,0x5,0x6,0x59,0x8,0x1,0x6,0x6,0x11, + 0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x13,0x2,0x4c,0x1b,0x40,0x27,0x0,0x3,0x5,0x4,0x5,0x3,0x4,0x70,0x7,0x1,0x1,0x0,0x0,0x6,0x1, + 0x0,0x63,0x0,0x5,0x5,0x6,0x59,0x8,0x1,0x6,0x6,0x11,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x13,0x2,0x4c,0x59,0x40,0x18,0x12,0x12,0x0, + 0x0,0x12,0x36,0x12,0x34,0x2e,0x2c,0x29,0x27,0x23,0x22,0x1b,0x19,0x0,0x11,0x0,0x10,0x27,0x9,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6, + 0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x2,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17, + 0x16,0x16,0x33,0x32,0x36,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x1,0x26,0x2,0x17,0x6,0x2d,0x37,0x30,0x26,0x2,0x17,0x6, + 0x2e,0x37,0x12,0x19,0x2,0xa0,0x1f,0xb4,0xa9,0x53,0xb3,0x46,0x1c,0x11,0x1a,0x20,0x12,0xf,0x3e,0x8b,0x43,0x62,0x62,0x14,0x91,0xfe,0x59,0x1b,0x1a,0x3, + 0x7,0x22,0x22,0x1,0xfe,0x5,0x53,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0x15,0x19,0x5,0xe,0x82,0x24,0x1d,0xfe,0x49,0x14,0x18,0xf,0x9,0xfc,0x6f,0xb1, + 0xb0,0x3f,0x32,0x14,0x1b,0x15,0x1e,0x2c,0xc,0x2c,0x35,0x6a,0x72,0x3,0x38,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0x53,0xfe,0x66, + 0x3,0xd9,0x3,0x9c,0x0,0x24,0x0,0x35,0x40,0x32,0x1e,0x2,0x2,0x3,0x4,0x1,0x4a,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70,0x0,0x3,0x3,0x4,0x59, + 0x5,0x1,0x4,0x4,0x11,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x0,0x0,0x0,0x24,0x0,0x22,0x23,0x24,0x17,0x27,0x6,0x7,0x18, + 0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x13,0x21,0x22, + 0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x3,0xc0,0x19,0x2,0xa0,0x1f,0xb4,0xa9,0x53,0xb3,0x46,0x1c,0x11,0x1a,0x20,0x12,0xf,0x3e,0x8b,0x43,0x62,0x62, + 0x14,0x91,0xfe,0x59,0x1b,0x1a,0x3,0x7,0x22,0x22,0x1,0xfe,0x3,0x9c,0x14,0x18,0xf,0x9,0xfc,0x6f,0xb1,0xb0,0x3f,0x32,0x14,0x1b,0x15,0x1e,0x2c,0xc, + 0x2c,0x35,0x6a,0x72,0x3,0x38,0x16,0x18,0xb,0xf,0x27,0x21,0xff,0xff,0x0,0x53,0xfe,0x66,0x4,0xa1,0x5,0x60,0x0,0x22,0x0,0xb5,0x0,0x0,0x0,0x2, + 0x1,0x92,0x64,0x0,0x0,0x0,0x0,0x1,0x0,0xa9,0xff,0xf3,0x4,0x70,0x5,0x2a,0x0,0x29,0x0,0x28,0x40,0x25,0x21,0x1,0x3,0x2,0x24,0x17,0xe,0x4, + 0x4,0x0,0x3,0x2,0x4a,0x0,0x2,0x2,0x10,0x4b,0x0,0x3,0x3,0x19,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x27,0x37,0x36,0x2a,0x4,0x7,0x18,0x2b, + 0x0,0x15,0x14,0x7,0x1,0x1,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x7,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33, + 0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x1,0x36,0x33,0x32,0x17,0x4,0x70,0x19,0xfe,0x60,0x1,0x3a,0xe,0x2f,0x20,0x17,0x19,0x12,0xfe,0xd2,0xdb,0x24,0x6, + 0x27,0x28,0x2,0x23,0x1e,0x2,0xd4,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x8c,0x2,0x56,0x17,0x1c,0x1c,0x1a,0x3,0x81,0x19,0x14,0x13,0xfe,0xc3,0xfe,0x57, + 0x13,0xe,0x1c,0x19,0x12,0x18,0x1,0x9e,0xa7,0xcb,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0xb2,0x23,0x1e,0x15,0x18,0x4,0x10,0xfc,0xe5,0x1,0xce,0x12,0x12, + 0x0,0x0,0xff,0xff,0x0,0xa9,0xfd,0xf3,0x4,0x70,0x5,0x2a,0x0,0x22,0x0,0xb7,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xea,0x0,0x0,0x0,0x1,0x1,0x10, + 0xff,0xea,0x3,0xfc,0x5,0x20,0x0,0x27,0x0,0x39,0x40,0x36,0x21,0x2,0x2,0x3,0x4,0x12,0x1,0x2,0x0,0x2,0x4a,0x0,0x1,0x3,0x0,0x3,0x1,0x0, + 0x70,0x0,0x3,0x3,0x4,0x59,0x5,0x1,0x4,0x4,0x10,0x4b,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x0,0x0,0x0,0x27,0x0,0x25,0x25, + 0x27,0x22,0x29,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x6,0x7,0x6, + 0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x2,0xe1,0x1b,0x2,0xa5,0x7,0x41,0x45,0x6a,0x70,0x10,0x6,0x29, + 0xc,0x3,0x18,0x1a,0x87,0x7e,0x81,0x8c,0x7,0x97,0xfe,0xef,0x1b,0x1a,0x3,0x7,0x23,0x22,0x1,0x66,0x5,0x20,0x15,0x18,0xe,0x9,0xfc,0x5a,0x2c,0x17, + 0x3e,0x39,0x22,0x4,0x39,0xf,0xd,0x19,0x1d,0x8,0x25,0x85,0x76,0x28,0x26,0x3,0x5d,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x1,0x10, + 0xff,0xea,0x4,0xc,0x6,0xd0,0x0,0x27,0x1,0x80,0xff,0xc4,0x1,0x72,0x1,0x2,0x0,0xb9,0x0,0x0,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0x72,0xb0,0x33, + 0x2b,0x0,0xff,0xff,0x0,0xf2,0xff,0xea,0x4,0xe2,0x5,0x20,0x0,0x22,0x0,0xb9,0xe2,0x0,0x0,0x3,0x1,0x81,0x2,0x23,0x0,0x0,0xff,0xff,0x1,0x10, + 0xfd,0xf3,0x3,0xfc,0x5,0x20,0x0,0x22,0x0,0xb9,0x0,0x0,0x0,0x3,0x1,0x7e,0x5,0x30,0x0,0x0,0xff,0xff,0x0,0xf2,0xff,0xea,0x4,0x4f,0x5,0x20, + 0x0,0x22,0x0,0xb9,0xe2,0x0,0x1,0x7,0x1,0x94,0x0,0xca,0xfe,0xc,0x0,0x9,0xb1,0x1,0x1,0xb8,0xfe,0xc,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xf3, + 0xff,0xea,0x3,0xfc,0x5,0x20,0x0,0x3d,0x0,0x46,0x40,0x43,0x24,0x1b,0x2,0x2,0x3,0x27,0xc,0x2,0x1,0x4,0x1,0x1,0x0,0x5,0x3,0x4a,0x0,0x1, + 0x4,0x6,0x4,0x1,0x6,0x70,0x0,0x6,0x5,0x4,0x6,0x5,0x6e,0x0,0x2,0x2,0x3,0x59,0x0,0x3,0x3,0x10,0x4b,0x0,0x4,0x4,0x19,0x4b,0x0,0x5, + 0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x22,0x2b,0x27,0x36,0x27,0x27,0x25,0x7,0x7,0x1b,0x2b,0x24,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x35, + 0x34,0x37,0x37,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x32,0x16,0x15,0x14,0x7,0x3, + 0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x5,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x3,0xfc,0x18,0x1a,0x87,0x7e,0x81,0x8c, + 0x7,0x27,0x86,0x18,0x10,0x1a,0x19,0x12,0x20,0xf4,0x4f,0xfe,0xef,0x1b,0x1a,0x3,0x7,0x23,0x22,0x1,0x66,0x1c,0x1b,0x2,0x49,0x9b,0x18,0x10,0x1a,0x19, + 0x12,0x20,0xfe,0xf7,0x3b,0x7,0x41,0x45,0x6a,0x70,0x10,0x6,0x29,0xc,0x5a,0xd,0x19,0x1d,0x8,0x25,0x85,0x76,0x28,0x26,0xde,0x5b,0x10,0x25,0x1b,0x12, + 0x19,0x15,0xa6,0x1,0xc4,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x18,0xe,0x9,0xfe,0x64,0x69,0x10,0x25,0x1b,0x12,0x19,0x15,0xb4,0xfe,0xb1,0x2c,0x17,0x3e, + 0x39,0x22,0x4,0x39,0x0,0x1,0x0,0x3a,0xff,0xf6,0x4,0x8b,0x3,0xb2,0x0,0x49,0x0,0x5e,0x40,0xe,0x3d,0x1,0x1,0x5,0x46,0x40,0x33,0x20,0xd,0x5, + 0x0,0x1,0x2,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x16,0x3,0x1,0x1,0x1,0x5,0x5b,0x8,0x7,0x6,0x3,0x5,0x5,0x11,0x4b,0x4,0x2,0x2,0x0,0x0, + 0xf,0x0,0x4c,0x1b,0x40,0x1a,0x0,0x5,0x5,0x11,0x4b,0x3,0x1,0x1,0x1,0x6,0x5b,0x8,0x7,0x2,0x6,0x6,0x19,0x4b,0x4,0x2,0x2,0x0,0x0,0xf, + 0x0,0x4c,0x59,0x40,0x10,0x0,0x0,0x0,0x49,0x0,0x48,0x27,0x37,0x36,0x28,0x36,0x28,0x38,0x9,0x7,0x1b,0x2b,0x0,0x16,0x16,0x15,0x14,0x7,0x3,0x6, + 0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x35,0x34,0x23,0x22,0x6,0x6,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x35, + 0x34,0x23,0x22,0x6,0x6,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x36,0x36,0x33, + 0x32,0x16,0x17,0x36,0x36,0x33,0x4,0xb,0x51,0x2f,0x7,0x6c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x6b,0x5,0x4c,0x2f,0x61,0x4d,0x11,0x43,0x6,0x27,0x28, + 0x2,0x23,0x1e,0x2,0x6b,0x5,0x4c,0x2f,0x61,0x4d,0x11,0x43,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x90,0x6,0x1f,0x24,0x2,0x1f,0x1a,0x2,0x14,0x37,0x87, + 0x40,0x43,0x57,0x4,0x37,0x89,0x43,0x3,0xb2,0x30,0x5d,0x41,0x24,0x24,0xfd,0x9b,0x23,0x1e,0x15,0x18,0x4,0x10,0x2,0x5d,0x20,0x14,0x56,0x60,0xa6,0x63, + 0xfe,0x82,0x23,0x1e,0x15,0x18,0x4,0x10,0x2,0x5d,0x20,0x14,0x56,0x60,0xa6,0x63,0xfe,0x82,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x2e,0x24,0x1d,0x14,0x17, + 0x6,0x10,0x70,0x5d,0x60,0x5e,0x57,0x5a,0x5b,0x0,0x0,0x0,0x0,0x1,0x0,0x8b,0xff,0xf6,0x4,0x40,0x3,0xb2,0x0,0x31,0x0,0x53,0x40,0xc,0x2b,0x1, + 0x1,0x3,0x2e,0x21,0xd,0x3,0x0,0x1,0x2,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x13,0x0,0x1,0x1,0x3,0x5b,0x5,0x4,0x2,0x3,0x3,0x11,0x4b,0x2, + 0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40,0x17,0x0,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0x4,0x5b,0x5,0x1,0x4,0x4,0x19,0x4b,0x2,0x1,0x0,0x0,0xf, + 0x0,0x4c,0x59,0x40,0xd,0x0,0x0,0x0,0x31,0x0,0x30,0x37,0x36,0x29,0x38,0x6,0x7,0x18,0x2b,0x0,0x16,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23, + 0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33, + 0x32,0x16,0x15,0x14,0x7,0x7,0x36,0x36,0x33,0x3,0x82,0x7c,0x42,0x7,0x62,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x61,0x5,0x4c,0x4d,0x56,0xba,0x8c,0x13, + 0x3c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x90,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x1b,0x54,0xe0,0x6b,0x3,0xb2,0x40,0x75,0x4f,0x26,0x26,0xfd,0xd5,0x23, + 0x1e,0x15,0x18,0x4,0x10,0x2,0x26,0x20,0x16,0x42,0x49,0x6d,0xbb,0x6e,0xfe,0xaf,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x2e,0x24,0x1d,0x15,0x17,0x5,0x10, + 0x99,0x67,0x7f,0x0,0xff,0xff,0x0,0x8b,0xff,0xf6,0x4,0x40,0x5,0x5e,0x0,0x22,0x1,0x80,0xf6,0x0,0x0,0x2,0x0,0xc0,0x0,0x0,0x0,0x0,0xff,0xff, + 0x0,0x8b,0xff,0xf6,0x4,0x62,0x5,0x6e,0x0,0x26,0x1,0x83,0x0,0xa,0x1,0x2,0x0,0xc0,0x0,0x0,0x0,0x8,0xb1,0x0,0x1,0xb0,0xa,0xb0,0x33,0x2b, + 0xff,0xff,0x0,0x8b,0xfd,0xf3,0x4,0x40,0x3,0xb2,0x0,0x22,0x0,0xc0,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xd6,0x0,0x0,0x0,0x1,0x0,0x8b,0xfe,0x66, + 0x4,0x40,0x3,0xb2,0x0,0x3b,0x0,0x76,0x40,0xb,0x35,0x1,0x3,0x5,0x38,0x2b,0x2,0x4,0x3,0x2,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x24,0x0,0x1, + 0x4,0x2,0x4,0x1,0x2,0x70,0x0,0x3,0x3,0x5,0x5b,0x7,0x6,0x2,0x5,0x5,0x11,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0, + 0x0,0x13,0x0,0x4c,0x1b,0x40,0x28,0x0,0x1,0x4,0x2,0x4,0x1,0x2,0x70,0x0,0x5,0x5,0x11,0x4b,0x0,0x3,0x3,0x6,0x5b,0x7,0x1,0x6,0x6,0x19, + 0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x13,0x0,0x4c,0x59,0x40,0xf,0x0,0x0,0x0,0x3b,0x0,0x3a,0x37,0x36,0x27,0x23, + 0x17,0x28,0x8,0x7,0x1a,0x2b,0x0,0x16,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x33,0x32, + 0x36,0x37,0x13,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15, + 0x14,0x7,0x7,0x36,0x36,0x33,0x3,0x82,0x7c,0x42,0x7,0x84,0x18,0x9d,0x83,0x3a,0x73,0x31,0x21,0xd,0x16,0x26,0xb,0xc,0x59,0x51,0x40,0x4d,0xf,0x7e, + 0x5,0x4c,0x4d,0x56,0xba,0x8c,0x13,0x3c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x90,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x1b,0x54,0xe0,0x6b,0x3,0xb2,0x40, + 0x75,0x4f,0x26,0x26,0xfd,0x17,0x87,0x8c,0x1b,0x17,0x10,0x1e,0x15,0x1b,0x2f,0x5,0x28,0x4b,0x52,0x2,0xc8,0x20,0x16,0x42,0x49,0x6d,0xbb,0x6e,0xfe,0xaf, + 0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x2e,0x24,0x1d,0x15,0x17,0x5,0x10,0x99,0x67,0x7f,0x0,0x0,0x0,0xff,0xff,0x0,0x8b,0xff,0xf6,0x4,0x4c,0x5,0x11, + 0x0,0x22,0x0,0xc0,0x0,0x0,0x0,0x2,0x1,0x9a,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x8c,0xff,0xea,0x4,0x56,0x3,0xb2,0x0,0xf,0x0,0x1f,0x0,0x2c, + 0x40,0x29,0x5,0x1,0x3,0x3,0x1,0x5b,0x4,0x1,0x1,0x1,0x19,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x10,0x10,0x0,0x0,0x10, + 0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0x6,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x36,0x33, + 0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x26,0x23,0x3,0x2d,0xbf,0x6a,0x8b,0xfb,0xa0,0x7b,0xbf,0x6a,0x8b,0xfb,0xa0,0x7c,0xaf, + 0x62,0x43,0x80,0x58,0x6c,0xaf,0x62,0x43,0x80,0x58,0x3,0xb2,0x69,0xba,0x75,0x93,0xfe,0xfe,0x9b,0x69,0xba,0x75,0x93,0x1,0x2,0x9b,0x94,0x70,0xba,0x6a, + 0x50,0x79,0x43,0x70,0xba,0x6a,0x50,0x79,0x43,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0x56,0x5,0x5e,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2, + 0x1,0x80,0xd6,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0x71,0x5,0x4e,0x0,0x22,0x1,0x82,0xec,0x0,0x0,0x2,0x0,0xc6,0x0,0x0,0x0,0x0, + 0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0x56,0x5,0x60,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x92,0xec,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea, + 0x4,0x56,0x5,0x28,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x93,0xec,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0x56,0x5,0x5e,0x0,0x22, + 0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x95,0x2,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0xc8,0x5,0x69,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2, + 0x1,0x96,0xec,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0x56,0x4,0xe2,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x97,0xec,0x0,0x0,0x0, + 0x0,0x3,0x0,0x1a,0xff,0xd7,0x4,0xc7,0x3,0xc5,0x0,0x25,0x0,0x2e,0x0,0x37,0x0,0x62,0x40,0x13,0x20,0x1,0x4,0x2,0x31,0x30,0x28,0x27,0x17,0x4, + 0x6,0x5,0x4,0xd,0x1,0x0,0x5,0x3,0x4a,0x4b,0xb0,0x1b,0x50,0x58,0x40,0x17,0x0,0x4,0x4,0x2,0x5b,0x3,0x1,0x2,0x2,0x19,0x4b,0x0,0x5,0x5, + 0x0,0x5b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x1f,0x0,0x3,0x3,0x19,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x19,0x4b,0x0,0x5,0x5, + 0x0,0x5b,0x0,0x0,0x0,0x17,0x4b,0x0,0x1,0x1,0x17,0x1,0x4c,0x59,0x40,0x9,0x27,0x25,0x24,0x2b,0x24,0x29,0x6,0x7,0x1a,0x2b,0x0,0x15,0x14,0x7, + 0x7,0x16,0x15,0x14,0x2,0x6,0x23,0x22,0x26,0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x35,0x34,0x12,0x36,0x33,0x32,0x16,0x17,0x37, + 0x36,0x33,0x32,0x17,0x0,0x17,0x1,0x26,0x23,0x22,0x6,0x6,0x15,0x24,0x27,0x1,0x16,0x33,0x32,0x36,0x36,0x35,0x4,0xc7,0x1e,0x81,0x2e,0x8b,0xfb,0xa0, + 0x56,0x94,0x37,0x78,0x1a,0x19,0x1a,0x19,0x17,0x1d,0x83,0x2e,0x8b,0xfb,0xa0,0x56,0x93,0x38,0x77,0x1a,0x19,0x1b,0x19,0xfc,0x74,0x11,0x2,0x24,0x48,0x70, + 0x6c,0xaf,0x62,0x2,0x98,0x11,0xfd,0xdb,0x49,0x70,0x6c,0xaf,0x62,0x3,0x8e,0x13,0x17,0x1a,0x6b,0x57,0x6e,0x93,0xfe,0xfe,0x9b,0x35,0x31,0x63,0x16,0x1c, + 0x1a,0x15,0x18,0x17,0x6c,0x57,0x6e,0x93,0x1,0x2,0x9b,0x34,0x31,0x62,0x16,0x1c,0xfd,0xaa,0x30,0x1,0xc6,0x35,0x70,0xba,0x6a,0xbf,0x30,0xfe,0x3b,0x36, + 0x70,0xba,0x6a,0x0,0x0,0x0,0xff,0xff,0x0,0x8c,0xff,0xea,0x4,0x56,0x5,0x11,0x0,0x22,0x0,0xc6,0x0,0x0,0x0,0x2,0x1,0x9a,0xe7,0x0,0x0,0x0, + 0x0,0x3,0x0,0x42,0xff,0xea,0x4,0x9d,0x3,0xb2,0x0,0x2c,0x0,0x35,0x0,0x46,0x0,0x58,0x40,0x55,0x29,0x1,0x8,0x5,0x1d,0x1,0x3,0x1,0x2,0x4a, + 0x0,0x2,0x0,0x1,0x0,0x2,0x1,0x70,0x0,0x7,0x0,0x0,0x2,0x7,0x0,0x61,0xd,0xa,0xc,0x3,0x8,0x8,0x5,0x5b,0xb,0x6,0x2,0x5,0x5,0x19, + 0x4b,0x9,0x1,0x1,0x1,0x3,0x5b,0x4,0x1,0x3,0x3,0x17,0x3,0x4c,0x36,0x36,0x2d,0x2d,0x0,0x0,0x36,0x46,0x36,0x45,0x3e,0x3c,0x2d,0x35,0x2d,0x34, + 0x30,0x2f,0x0,0x2c,0x0,0x2b,0x26,0x22,0x29,0x13,0x23,0x26,0xe,0x7,0x1a,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x6,0x15,0x14,0x33,0x32, + 0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x27,0x6,0x23,0x22,0x26,0x35,0x34,0x12,0x37,0x36,0x33,0x32,0x17,0x36,0x36, + 0x33,0x6,0x6,0x7,0x21,0x36,0x35,0x34,0x26,0x23,0x4,0x7,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x36,0x35,0x34,0x26,0x23,0x4,0x27,0x76, + 0xc,0x5,0x23,0x22,0xfe,0x71,0xc,0x78,0x30,0x56,0x32,0x14,0x16,0xe,0x1b,0x9,0xd,0x25,0x41,0x84,0x46,0x9f,0x39,0x64,0x9b,0x7c,0x80,0x3a,0x31,0x69, + 0xbe,0x9c,0x33,0x37,0x87,0x4a,0x54,0x61,0x20,0x1,0x2c,0x5,0x32,0x37,0xfd,0xbd,0x3a,0x1c,0x28,0x38,0x39,0x34,0x50,0x1e,0x1c,0x28,0x37,0x39,0x3,0xb2, + 0x9c,0x8f,0x43,0x4e,0x21,0x1d,0x4c,0x38,0xb9,0x25,0x29,0x11,0x10,0xf,0x14,0x14,0x22,0x1d,0x35,0x35,0x8a,0x8a,0xa6,0x9b,0x69,0x1,0x2,0x5b,0xc1,0x8c, + 0x47,0x45,0x91,0x68,0x75,0x2a,0x1b,0x4a,0x4e,0x3,0x8e,0x43,0xd7,0x50,0x56,0x52,0x45,0x49,0x43,0xd7,0x50,0x56,0x52,0x0,0x0,0x0,0x0,0x2,0x0,0x3d, + 0xfe,0x72,0x4,0x53,0x3,0xb2,0x0,0x21,0x0,0x2f,0x0,0x71,0x40,0xf,0x1c,0x1,0x4,0x2,0x1f,0xa,0x2,0x5,0x4,0x12,0x1,0x1,0x0,0x3,0x4a,0x4b, + 0xb0,0x28,0x50,0x58,0x40,0x1d,0x0,0x4,0x4,0x2,0x5b,0x6,0x3,0x2,0x2,0x2,0x11,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x4b,0x0, + 0x1,0x1,0x13,0x1,0x4c,0x1b,0x40,0x21,0x0,0x2,0x2,0x11,0x4b,0x0,0x4,0x4,0x3,0x5b,0x6,0x1,0x3,0x3,0x19,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b, + 0x0,0x0,0x0,0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x59,0x40,0x14,0x22,0x22,0x0,0x0,0x22,0x2f,0x22,0x2e,0x29,0x27,0x0,0x21,0x0,0x20,0x37,0x35, + 0x26,0x8,0x7,0x17,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x6,0x23,0x22,0x26,0x27,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33, + 0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x36,0x33,0x2,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x3,0x54,0xa4,0x5b,0x72,0xe8,0xa6, + 0x62,0x98,0x2f,0x55,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xd4,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xe,0x97,0xc1,0x24,0xa0,0x55,0x7a,0x71,0x72,0xa9,0x5a, + 0x8a,0x75,0x3,0xb2,0x5f,0xaf,0x76,0x8a,0xfe,0xf4,0xae,0x57,0x51,0xfe,0x21,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0xb2,0x24,0x1d,0x15,0x17,0x5,0x10,0x4f, + 0x9c,0xfc,0xcc,0x7a,0xc3,0x6a,0x72,0x87,0x76,0xbf,0x6a,0x79,0x88,0x0,0x0,0x0,0x0,0x2,0x0,0x3d,0xfe,0x72,0x4,0x53,0x5,0x2a,0x0,0x21,0x0,0x2f, + 0x0,0x4a,0x40,0x47,0x1c,0x1,0x3,0x2,0x1f,0x1,0x4,0x3,0xa,0x1,0x5,0x4,0x12,0x1,0x1,0x0,0x4,0x4a,0x0,0x2,0x2,0x10,0x4b,0x0,0x4,0x4, + 0x3,0x5b,0x6,0x1,0x3,0x3,0x19,0x4b,0x7,0x1,0x5,0x5,0x0,0x5b,0x0,0x0,0x0,0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x22,0x22,0x0,0x0,0x22, + 0x2f,0x22,0x2e,0x29,0x27,0x0,0x21,0x0,0x20,0x37,0x35,0x26,0x8,0x7,0x17,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x6,0x23,0x22,0x26,0x27,0x3,0x6,0x6, + 0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x36,0x33,0x2,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6, + 0x15,0x14,0x16,0x33,0x3,0x54,0xa4,0x5b,0x72,0xe8,0xa6,0x62,0x98,0x2f,0x55,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x1,0x18,0x6,0x27,0x28,0x2,0x23,0x1e, + 0x2,0x51,0x94,0xb9,0x24,0xa0,0x55,0x7a,0x71,0x72,0xa9,0x5a,0x8a,0x75,0x3,0xb2,0x5f,0xaf,0x76,0x8a,0xfe,0xf4,0xae,0x57,0x51,0xfe,0x21,0x23,0x1e,0x15, + 0x18,0x4,0x10,0x6,0x36,0x23,0x1e,0x15,0x18,0x4,0x10,0xfe,0x38,0x91,0xfc,0xcc,0x7a,0xc3,0x6a,0x72,0x87,0x76,0xbf,0x6a,0x79,0x88,0x0,0x2,0x0,0x8f, + 0xfe,0x72,0x4,0x61,0x3,0xb2,0x0,0x22,0x0,0x30,0x0,0x74,0x40,0x12,0xa,0x1,0x5,0x0,0x2,0x1,0x4,0x5,0x17,0x1,0x2,0x4,0x14,0x1,0x1,0x2, + 0x4,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1d,0x7,0x1,0x5,0x5,0x0,0x5b,0x6,0x3,0x2,0x0,0x0,0x11,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2, + 0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x1b,0x40,0x21,0x0,0x0,0x0,0x11,0x4b,0x7,0x1,0x5,0x5,0x3,0x5b,0x6,0x1,0x3,0x3,0x19,0x4b,0x0,0x4, + 0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x4b,0x0,0x1,0x1,0x13,0x1,0x4c,0x59,0x40,0x14,0x23,0x23,0x0,0x0,0x23,0x30,0x23,0x2f,0x2a,0x28,0x0,0x22,0x0, + 0x21,0x27,0x37,0x35,0x8,0x7,0x17,0x2b,0x0,0x16,0x17,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34, + 0x37,0x13,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x2,0xf4,0x9b,0x31, + 0x13,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0xd4,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x50,0x47,0xa7,0x5e,0x6b,0xa4,0x5b,0x72,0xe8,0xa6,0x72,0xa0,0x55,0x7a, + 0x71,0x72,0xa9,0x5a,0x8a,0x75,0x3,0xb2,0x5d,0x57,0x67,0x24,0x1d,0x15,0x17,0x5,0x10,0xfb,0x4e,0x23,0x1e,0x15,0x18,0x4,0x10,0x1,0xc7,0x46,0x4a,0x5f, + 0xaf,0x76,0x8a,0x1,0xc,0xae,0x94,0x7a,0xc3,0x6a,0x72,0x87,0x76,0xbf,0x6a,0x79,0x88,0x0,0x0,0x0,0x0,0x1,0x0,0xf4,0xff,0xf6,0x4,0x87,0x3,0xb2, + 0x0,0x27,0x0,0x92,0x4b,0xb0,0x17,0x50,0x58,0x40,0xc,0x21,0x3,0x2,0x0,0x3,0x24,0x17,0x2,0x2,0x0,0x2,0x4a,0x1b,0x40,0xc,0x21,0x3,0x2,0x1, + 0x3,0x24,0x17,0x2,0x2,0x0,0x2,0x4a,0x59,0x4b,0xb0,0x17,0x50,0x58,0x40,0x13,0x1,0x1,0x0,0x0,0x3,0x5b,0x5,0x4,0x2,0x3,0x3,0x11,0x4b,0x0, + 0x2,0x2,0xf,0x2,0x4c,0x1b,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x0,0x1,0x1,0x3,0x5b,0x5,0x4,0x2,0x3, + 0x3,0x11,0x4b,0x0,0x2,0x2,0xf,0x2,0x4c,0x1b,0x40,0x1e,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x0,0x3,0x3,0x11,0x4b,0x0,0x1,0x1,0x4,0x5b, + 0x5,0x1,0x4,0x4,0x19,0x4b,0x0,0x2,0x2,0xf,0x2,0x4c,0x59,0x59,0x40,0xd,0x0,0x0,0x0,0x27,0x0,0x26,0x37,0x36,0x23,0x16,0x6,0x7,0x18,0x2b, + 0x0,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x7,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33, + 0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x36,0x24,0x33,0x4,0x20,0x3f,0x28,0x7,0x12,0x29,0xb,0xb,0x34,0x37,0x73,0xe3,0xa4,0x18,0x26,0x6,0x27,0x28,0x2, + 0x23,0x1e,0x2,0x90,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x28,0x71,0x1,0x0,0x85,0x3,0xb2,0x15,0xe,0x29,0xf,0x1a,0x41,0x4,0x12,0x8c,0xed,0x8b,0xd7, + 0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x2e,0x24,0x1d,0x15,0x17,0x5,0x10,0xdc,0x8f,0x9a,0x0,0xff,0xff,0x0,0xf4,0xff,0xf6,0x4,0x87,0x5,0x5e,0x0,0x22, + 0x1,0x80,0x3c,0x0,0x0,0x2,0x0,0xd4,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xf4,0xff,0xf6,0x4,0x94,0x5,0x6e,0x0,0x26,0x1,0x83,0x32,0xa,0x1,0x2, + 0x0,0xd4,0x0,0x0,0x0,0x8,0xb1,0x0,0x1,0xb0,0xa,0xb0,0x33,0x2b,0xff,0xff,0x0,0xf4,0xfd,0xf3,0x4,0x87,0x3,0xb2,0x0,0x22,0x0,0xd4,0x0,0x0, + 0x0,0x3,0x1,0x7e,0x4,0xae,0x0,0x0,0x0,0x1,0x0,0x88,0xff,0xea,0x4,0x30,0x3,0xb2,0x0,0x3d,0x0,0x39,0x40,0x36,0x0,0x0,0x1,0x3,0x1,0x0, + 0x3,0x70,0x0,0x3,0x4,0x1,0x3,0x4,0x6e,0x0,0x1,0x1,0x5,0x5b,0x6,0x1,0x5,0x5,0x19,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2, + 0x4c,0x0,0x0,0x0,0x3d,0x0,0x3c,0x2c,0x2a,0x26,0x25,0x1f,0x1d,0x24,0x16,0x7,0x7,0x16,0x2b,0x0,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26, + 0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x17,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x20,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17, + 0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x27,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x3,0x6c,0xa1,0x23,0xd,0x1a,0x23,0xc,0x12, + 0x48,0xad,0x5e,0x4f,0x6c,0x35,0x6d,0x3c,0x60,0x4f,0x5b,0x2e,0x4a,0x57,0x53,0xc6,0xa2,0xff,0x0,0xa2,0x22,0xf,0x1a,0x22,0xf,0x11,0x4a,0xb8,0x66,0x62, + 0x78,0x32,0x6c,0x35,0x6c,0x49,0x61,0x2f,0x48,0x54,0x5c,0xb9,0x84,0x3,0xb2,0x57,0x13,0x22,0x15,0x1a,0x32,0x9,0x29,0x2a,0x29,0x43,0x26,0x47,0x15,0xc, + 0x7,0x8,0xc,0xe,0x16,0x68,0x54,0x49,0x93,0x66,0x64,0x15,0x20,0x15,0x1b,0x30,0xa,0x2e,0x30,0x34,0x49,0x23,0x4c,0x17,0xb,0xa,0x6,0xd,0xf,0x16, + 0x65,0x4f,0x53,0x8c,0x54,0x0,0x0,0x0,0xff,0xff,0x0,0x88,0xff,0xea,0x4,0x30,0x5,0x5e,0x0,0x22,0x1,0x80,0xe2,0x0,0x0,0x2,0x0,0xd8,0x0,0x0, + 0x0,0x0,0xff,0xff,0x0,0x88,0xff,0xea,0x4,0x3d,0x5,0x6e,0x0,0x26,0x1,0x83,0xdb,0xa,0x1,0x2,0x0,0xd8,0x0,0x0,0x0,0x8,0xb1,0x0,0x1,0xb0, + 0xa,0xb0,0x33,0x2b,0x0,0x1,0x0,0x88,0xfe,0x28,0x4,0x30,0x3,0xb2,0x0,0x60,0x0,0x5f,0x40,0x5c,0x3f,0x1,0x2,0x9,0x3c,0x1,0x7,0x3,0x2,0x4a, + 0x0,0x0,0x1,0x8,0x1,0x0,0x8,0x70,0x0,0x8,0x9,0x1,0x8,0x9,0x6e,0x0,0x5,0x7,0x6,0x7,0x5,0x6,0x70,0x0,0x3,0x0,0x7,0x5,0x3,0x7, + 0x63,0x0,0x6,0x0,0x4,0x6,0x4,0x5f,0x0,0x1,0x1,0xa,0x5b,0x0,0xa,0xa,0x19,0x4b,0x0,0x9,0x9,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x5f, + 0x5d,0x4d,0x4b,0x47,0x46,0x3b,0x38,0x35,0x33,0x30,0x2e,0x26,0x24,0x1e,0x1d,0x1c,0x1b,0x24,0x14,0xb,0x7,0x16,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22, + 0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x17,0x16,0x17,0x16,0x16,0x17,0x16,0x16,0x15,0x14,0x6,0x6,0x7,0x7,0x36,0x16,0x15,0x14,0x6,0x7,0x6, + 0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x23,0x7,0x22,0x35,0x34,0x37,0x37,0x26,0x27,0x26, + 0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x27,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17, + 0x4,0x30,0xd,0x1a,0x23,0xc,0x12,0x48,0xad,0x5e,0x4f,0x6c,0x35,0x6d,0x3c,0x60,0x4f,0x5b,0x2e,0x4a,0x57,0x4f,0xbd,0x9a,0x10,0x58,0x5a,0x1c,0x1a,0x45, + 0x97,0x44,0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64,0x31,0x3a,0x3a,0x67,0x23,0x1d,0x1,0x1b,0xb4,0x7d,0x22,0xf,0x1a,0x22,0xf,0x11,0x4a, + 0xb8,0x66,0x62,0x78,0x32,0x6c,0x35,0x6c,0x49,0x61,0x2f,0x48,0x54,0x5c,0xb9,0x84,0xee,0xa1,0x3,0x48,0x22,0x15,0x1a,0x32,0x9,0x29,0x2a,0x29,0x43,0x26, + 0x47,0x15,0xc,0x7,0x8,0xc,0xe,0x16,0x68,0x54,0x47,0x90,0x67,0x4,0x5c,0x2,0x52,0x40,0x22,0x4f,0x1b,0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15, + 0x2,0xf,0x13,0x2d,0x24,0x37,0x1,0x1c,0x9,0x5,0x9e,0x11,0x4e,0x15,0x20,0x15,0x1b,0x30,0xa,0x2e,0x30,0x34,0x49,0x23,0x4c,0x17,0xb,0xa,0x6,0xd, + 0xf,0x16,0x65,0x4f,0x53,0x8c,0x54,0x57,0xff,0xff,0x0,0x88,0xff,0xea,0x4,0x30,0x5,0x60,0x0,0x22,0x1,0x92,0xf0,0x0,0x0,0x2,0x0,0xd8,0x0,0x0, + 0x0,0x0,0xff,0xff,0x0,0x88,0xfd,0xf3,0x4,0x30,0x3,0xb2,0x0,0x22,0x0,0xd8,0x0,0x0,0x0,0x3,0x1,0x7e,0x4,0xcc,0x0,0x0,0x0,0x1,0x0,0xac, + 0xff,0xea,0x4,0x41,0x5,0x25,0x0,0x3b,0x0,0x7f,0x4b,0xb0,0x28,0x50,0x58,0x40,0xb,0x1d,0x6,0x2,0x2,0x3,0x34,0x1,0x0,0x1,0x2,0x4a,0x1b,0x40, + 0xb,0x1d,0x6,0x2,0x2,0x3,0x34,0x1,0x4,0x1,0x2,0x4a,0x59,0x4b,0xb0,0x28,0x50,0x58,0x40,0x1f,0x0,0x2,0x3,0x1,0x3,0x2,0x1,0x70,0x0,0x3, + 0x3,0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x4b,0x0,0x1,0x1,0x0,0x5b,0x4,0x1,0x0,0x0,0x17,0x0,0x4c,0x1b,0x40,0x23,0x0,0x2,0x3,0x1,0x3,0x2, + 0x1,0x70,0x0,0x3,0x3,0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x4b,0x0,0x4,0x4,0xf,0x4b,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x59, + 0x40,0xe,0x0,0x0,0x0,0x3b,0x0,0x3a,0x35,0x2d,0x25,0x24,0x2c,0x7,0x7,0x19,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6, + 0x23,0x22,0x26,0x35,0x34,0x36,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x37,0x3e,0x2,0x35,0x34,0x26,0x23,0x22,0x6, + 0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x3e,0x2,0x33,0x3,0x5d,0x97,0x4d,0x75,0x6e,0x54,0x5c,0x5b,0xd2,0xa7,0x2d,0x21,0x24,0x27, + 0x6f,0x8e,0x3e,0x72,0x66,0x1c,0x19,0x2,0x6,0x23,0x22,0x53,0x6d,0x33,0x64,0x5f,0x66,0x89,0x14,0x9b,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x9d,0x13,0x70, + 0xb1,0x72,0x5,0x25,0x4b,0x82,0x53,0x6f,0xaa,0x35,0x26,0x8f,0x60,0x62,0xca,0x8c,0x19,0x21,0x30,0x2a,0x58,0x86,0x4a,0x5f,0x66,0x16,0x17,0xf,0x9,0x24, + 0x20,0x3,0x8,0x4e,0x6e,0x3b,0x4b,0x53,0x81,0x6f,0xfc,0x93,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x78,0x6f,0xa9,0x5e,0x0,0x0,0x0,0x0,0x1,0x0,0xb4, + 0xff,0xea,0x4,0x33,0x4,0xb9,0x0,0x38,0x0,0x3b,0x40,0x38,0x2b,0x1,0x4,0x5,0x32,0x1e,0x2,0x3,0x4,0x2,0x4a,0x0,0x1,0x3,0x0,0x3,0x1,0x0, + 0x70,0x6,0x1,0x4,0x7,0x1,0x3,0x1,0x4,0x3,0x62,0x0,0x5,0x5,0x16,0x4b,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x26,0x25,0x23, + 0x26,0x25,0x28,0x23,0x24,0x8,0x7,0x1c,0x2b,0x1,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23, + 0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x21,0x32,0x16,0x15, + 0x14,0x7,0x6,0x6,0x23,0x21,0x2,0xb,0x9,0x45,0x4e,0x42,0x9d,0x4e,0xf,0xf,0x10,0x1c,0x9,0x8,0x26,0x58,0xc4,0x55,0x8f,0x8c,0xa,0x3f,0xcb,0x1b, + 0x1a,0x3,0x7,0x22,0x22,0xcb,0x35,0x6,0x26,0x29,0x23,0x20,0x2,0x35,0x1,0x9b,0x1c,0x19,0x2,0x8,0x22,0x22,0xfe,0x65,0x1,0x58,0x2e,0x25,0x46,0x43, + 0x37,0x2e,0x9,0x18,0x18,0x14,0x14,0x23,0x15,0x32,0x3e,0x85,0x7e,0x2a,0x3e,0x1,0x67,0x15,0x18,0xc,0xf,0x27,0x21,0x1,0x2c,0x23,0x1e,0x16,0x18,0x5, + 0xe,0xfe,0xd4,0x16,0x19,0xf,0xa,0x27,0x21,0x0,0x0,0x1,0x0,0xb4,0xff,0xea,0x4,0x33,0x4,0xb9,0x0,0x4e,0x0,0x56,0x40,0x53,0x42,0x1,0x8,0x9, + 0x49,0x35,0x2,0x7,0x8,0x2a,0x5,0x2,0x1,0x0,0x3,0x4a,0x0,0x3,0x1,0x2,0x1,0x3,0x2,0x70,0xa,0x1,0x8,0xc,0xb,0x2,0x7,0x0,0x8,0x7, + 0x62,0x6,0x1,0x0,0x5,0x1,0x1,0x3,0x0,0x1,0x63,0x0,0x9,0x9,0x16,0x4b,0x0,0x2,0x2,0x4,0x5b,0x0,0x4,0x4,0x17,0x4,0x4c,0x0,0x0,0x0, + 0x4e,0x0,0x4d,0x47,0x45,0x40,0x3e,0x26,0x21,0x26,0x25,0x28,0x23,0x25,0x26,0x21,0xd,0x7,0x1d,0x2b,0x1,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6, + 0x23,0x21,0x7,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x23, + 0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3, + 0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x2,0x4a,0x15,0x1,0x10,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0xf0,0x10,0x9,0x45,0x4e,0x42,0x9d,0x4e,0xf, + 0xf,0x10,0x1c,0x9,0x8,0x26,0x58,0xc4,0x55,0x8f,0x8c,0xa,0x11,0x8d,0x1b,0x1a,0x3,0x7,0x23,0x22,0x8c,0x15,0xcb,0x1b,0x1a,0x3,0x7,0x22,0x22,0xcb, + 0x35,0x6,0x26,0x29,0x23,0x20,0x2,0x35,0x1,0x9b,0x1c,0x19,0x2,0x8,0x22,0x22,0x2,0xbc,0x78,0x16,0x18,0xb,0xf,0x27,0x21,0x5c,0x2e,0x25,0x46,0x43, + 0x37,0x2e,0x9,0x18,0x18,0x14,0x14,0x23,0x15,0x32,0x3e,0x85,0x7e,0x2a,0x3e,0x5f,0x16,0x18,0xb,0xf,0x27,0x21,0x78,0x15,0x18,0xc,0xf,0x27,0x21,0x1, + 0x2c,0x23,0x1e,0x16,0x18,0x5,0xe,0xfe,0xd4,0x16,0x19,0xf,0xa,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0xb4,0xff,0xea,0x4,0x9e,0x5,0x78,0x0,0x22, + 0x0,0xdf,0x0,0x0,0x1,0x7,0x1,0x7e,0x6,0xf0,0x6,0xa,0x0,0x9,0xb1,0x1,0x1,0xb8,0x6,0xa,0xb0,0x33,0x2b,0x0,0x0,0x1,0x0,0xb4,0xfe,0x28, + 0x4,0x33,0x4,0xb9,0x0,0x5c,0x0,0x63,0x40,0x60,0x4f,0x1,0x9,0xa,0x56,0x42,0x2,0x8,0x9,0x38,0x1,0x2,0x0,0x35,0x1,0x7,0x3,0x4,0x4a,0x0, + 0x1,0x8,0x0,0x8,0x1,0x0,0x70,0x0,0x5,0x7,0x6,0x7,0x5,0x6,0x70,0xb,0x1,0x9,0xc,0x1,0x8,0x1,0x9,0x8,0x62,0x0,0x3,0x0,0x7,0x5, + 0x3,0x7,0x63,0x0,0x6,0x0,0x4,0x6,0x4,0x5f,0x0,0xa,0xa,0x16,0x4b,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x5c,0x5a,0x54,0x52, + 0x4d,0x4b,0x48,0x46,0x2a,0x33,0x23,0x28,0x26,0x12,0x18,0x23,0x24,0xd,0x7,0x1d,0x2b,0x1,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x16, + 0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x7,0x36,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17, + 0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x23,0x7,0x22,0x35,0x34,0x37,0x37,0x26,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33, + 0x13,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x2,0xb,0x9,0x45,0x4e,0x42,0x9d,0x4e,0xf,0xf, + 0x10,0x1c,0x9,0x8,0x26,0x58,0xc4,0x55,0x6,0x10,0x58,0x5a,0x1c,0x1a,0x45,0x97,0x44,0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64,0x31,0x3a, + 0x3a,0x67,0x23,0x1d,0x1,0x1e,0x49,0x49,0xa,0x3f,0xcb,0x1b,0x1a,0x3,0x7,0x22,0x22,0xcb,0x35,0x6,0x26,0x29,0x23,0x20,0x2,0x35,0x1,0x9b,0x1c,0x19, + 0x2,0x8,0x22,0x22,0xfe,0x65,0x1,0x58,0x2e,0x25,0x46,0x43,0x37,0x2e,0x9,0x18,0x18,0x14,0x14,0x23,0x15,0x32,0x3e,0x5c,0x2,0x52,0x40,0x22,0x4f,0x1b, + 0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15,0x2,0xf,0x13,0x2d,0x24,0x37,0x1,0x1c,0x9,0x5,0xae,0x1b,0x79,0x5a,0x2a,0x3e,0x1,0x67,0x15,0x18,0xc, + 0xf,0x27,0x21,0x1,0x2c,0x23,0x1e,0x16,0x18,0x5,0xe,0xfe,0xd4,0x16,0x19,0xf,0xa,0x27,0x21,0x0,0xff,0xff,0x0,0xb4,0xfd,0xf3,0x4,0x33,0x4,0xb9, + 0x0,0x22,0x0,0xdf,0x0,0x0,0x0,0x3,0x1,0x7e,0x5,0x1c,0x0,0x0,0x0,0x1,0x0,0xa2,0xff,0xea,0x4,0x57,0x3,0xa6,0x0,0x31,0x0,0x53,0x40,0xc, + 0x20,0xf,0x2,0x3,0x3,0x2,0xc,0x1,0x0,0x3,0x2,0x4a,0x4b,0xb0,0x28,0x50,0x58,0x40,0x13,0x5,0x4,0x2,0x2,0x2,0x11,0x4b,0x0,0x3,0x3,0x0, + 0x5c,0x1,0x1,0x0,0x0,0xf,0x0,0x4c,0x1b,0x40,0x17,0x5,0x4,0x2,0x2,0x2,0x11,0x4b,0x0,0x0,0x0,0xf,0x4b,0x0,0x3,0x3,0x1,0x5c,0x0,0x1, + 0x1,0x17,0x1,0x4c,0x59,0x40,0xd,0x0,0x0,0x0,0x31,0x0,0x2f,0x29,0x38,0x27,0x37,0x6,0x7,0x18,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23, + 0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14, + 0x16,0x33,0x32,0x36,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x4,0x39,0x1e,0x2,0x90,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x1b,0x54,0xe0,0x6b,0x55,0x7c,0x42, + 0x7,0x62,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x61,0x5,0x4c,0x4d,0x56,0xba,0x8c,0x13,0x3c,0x6,0x27,0x28,0x2,0x3,0xa6,0x15,0x18,0x4,0x10,0xfc,0xd2, + 0x24,0x1d,0x15,0x17,0x5,0x10,0x99,0x67,0x7f,0x40,0x75,0x4f,0x26,0x26,0x2,0x2b,0x23,0x1e,0x15,0x18,0x4,0x10,0xfd,0xda,0x20,0x16,0x42,0x49,0x6d,0xbb, + 0x6e,0x1,0x51,0x23,0x1e,0x0,0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x57,0x5,0x5e,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x80,0xf4,0x0,0x0,0x0, + 0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x71,0x5,0x4e,0x0,0x22,0x1,0x82,0xec,0x0,0x0,0x2,0x0,0xe4,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xa2,0xff,0xea, + 0x4,0x57,0x5,0x60,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x92,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x57,0x5,0x28,0x0,0x22, + 0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x93,0xf6,0x0,0x0,0x0,0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x57,0x5,0x5e,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2, + 0x1,0x95,0x2,0x0,0x0,0x0,0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0xbe,0x5,0x69,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x96,0xe2,0x0,0x0,0x0, + 0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x57,0x4,0xe2,0x0,0x22,0x0,0xe4,0x0,0x0,0x0,0x2,0x1,0x97,0xec,0x0,0x0,0x0,0x0,0x1,0x0,0xa2,0xfe,0x28, + 0x4,0x57,0x3,0xa6,0x0,0x42,0x0,0x61,0xb7,0x31,0x20,0x2,0x3,0x5,0x4,0x1,0x4a,0x4b,0xb0,0x31,0x50,0x58,0x40,0x1a,0x1,0x1,0x0,0x0,0x2,0x0, + 0x2,0x5f,0x7,0x6,0x2,0x4,0x4,0x11,0x4b,0x0,0x5,0x5,0x3,0x5c,0x0,0x3,0x3,0x17,0x3,0x4c,0x1b,0x40,0x21,0x0,0x1,0x3,0x0,0x3,0x1,0x0, + 0x70,0x0,0x0,0x0,0x2,0x0,0x2,0x5f,0x7,0x6,0x2,0x4,0x4,0x11,0x4b,0x0,0x5,0x5,0x3,0x5c,0x0,0x3,0x3,0x17,0x3,0x4c,0x59,0x40,0xf,0x0, + 0x0,0x0,0x42,0x0,0x40,0x29,0x38,0x28,0x26,0x21,0x2d,0x8,0x7,0x1a,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x7,0x6,0x6,0x15,0x14,0x16,0x33, + 0x32,0x37,0x37,0x32,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x37,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x37,0x13,0x36,0x36, + 0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x4,0x39,0x1e,0x2,0x90,0x4,0xd,0xb, + 0x6d,0x68,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56,0x80,0x7e,0x1e,0x54,0xe0,0x6b,0x55,0x7c,0x42,0x7,0x62,0x6,0x27,0x28,0x2, + 0x23,0x1e,0x2,0x61,0x5,0x4c,0x4d,0x56,0xba,0x8c,0x13,0x3c,0x6,0x27,0x28,0x2,0x3,0xa6,0x15,0x18,0x4,0x10,0xfc,0xd2,0x14,0x19,0x9,0x58,0x88,0x36, + 0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x5a,0xa9,0x59,0xaa,0x67,0x7f,0x40,0x75,0x4f,0x26,0x26,0x2,0x2b,0x23,0x1e,0x15,0x18,0x4, + 0x10,0xfd,0xda,0x20,0x16,0x42,0x49,0x6d,0xbb,0x6e,0x1,0x51,0x23,0x1e,0x0,0x0,0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x57,0x6,0x15,0x0,0x22,0x0,0xe4, + 0x0,0x0,0x0,0x2,0x1,0x99,0xe0,0x0,0x0,0x0,0xff,0xff,0x0,0xa2,0xff,0xea,0x4,0x57,0x5,0x11,0x0,0x22,0x1,0x9a,0xec,0x0,0x0,0x2,0x0,0xe4, + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0xcb,0xff,0xea,0x4,0xa0,0x3,0xa9,0x0,0x1c,0x0,0x1d,0x40,0x1a,0x16,0xd,0x1,0x3,0x0,0x1,0x1,0x4a,0x2,0x1, + 0x1,0x1,0x11,0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x26,0x29,0x26,0x3,0x7,0x17,0x2b,0x0,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x26, + 0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x36,0x33,0x32,0x17,0x4,0xa0,0xf,0xfe,0xc,0x15,0x3b,0x31,0x31,0x31,0x9,0xe2,0x4,0x1c, + 0x21,0x19,0x13,0x13,0x16,0x6,0xcf,0x1,0xda,0xd,0x19,0x10,0x12,0x1d,0x3,0x85,0x1d,0x12,0x18,0xfc,0xea,0x21,0x1d,0x1d,0x21,0x3,0x20,0xd,0xe,0x15, + 0x1b,0x9,0x7,0x13,0x16,0xfd,0x15,0x2,0xf3,0x14,0x13,0xd,0x0,0x1,0x0,0x8a,0xff,0xea,0x4,0xe5,0x3,0xa5,0x0,0x28,0x0,0x28,0x40,0x25,0x22,0x1b, + 0xc,0x3,0x0,0x3,0x1,0x4a,0x0,0x3,0x2,0x0,0x2,0x3,0x0,0x70,0x4,0x1,0x2,0x2,0x11,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x16,0x25,0x25, + 0x26,0x27,0x5,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x26,0x36,0x33, + 0x32,0x16,0x17,0x13,0x1,0x36,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x36,0x33,0x32,0x17,0x4,0xce,0x17,0xb,0xfe,0xae,0xf,0x28,0x26,0x2b,0x2b,0x5,0x4f, + 0xfe,0xfd,0x11,0x32,0x2a,0x26,0x23,0x2,0x3a,0x2,0x22,0x32,0x21,0x19,0x2,0x28,0x1,0xd,0x18,0x3f,0x21,0x23,0x3,0x51,0x1,0x15,0xb,0x1b,0x16,0x13, + 0x10,0x3,0x99,0x15,0x11,0x10,0x19,0xfc,0xe1,0x24,0x1d,0x1f,0x22,0x2,0x0,0xfe,0x0,0x23,0x1e,0x1e,0x23,0x3,0x35,0x25,0x1d,0x18,0x21,0xfd,0x69,0x2, + 0x15,0x2f,0x1a,0x15,0xfd,0xeb,0x2,0xa1,0x1a,0x18,0x5,0x0,0xff,0xff,0x0,0x8a,0xff,0xea,0x4,0xe5,0x5,0x5e,0x0,0x22,0x0,0xf0,0x0,0x0,0x0,0x2, + 0x1,0x80,0xf6,0x0,0x0,0x0,0xff,0xff,0x0,0x8a,0xff,0xea,0x4,0xe5,0x5,0x60,0x0,0x22,0x1,0x92,0xe6,0x0,0x0,0x2,0x0,0xf0,0x0,0x0,0x0,0x0, + 0xff,0xff,0x0,0x8a,0xff,0xea,0x4,0xe5,0x5,0x28,0x0,0x22,0x0,0xf0,0x0,0x0,0x0,0x2,0x1,0x93,0xe7,0x0,0x0,0x0,0xff,0xff,0x0,0x8a,0xff,0xea, + 0x4,0xe5,0x5,0x5e,0x0,0x22,0x0,0xf0,0x0,0x0,0x0,0x2,0x1,0x95,0xce,0x0,0x0,0x0,0x0,0x1,0x0,0x6b,0xff,0xf1,0x4,0x77,0x3,0xab,0x0,0x29, + 0x0,0x20,0x40,0x1d,0x24,0x19,0xf,0x4,0x4,0x0,0x2,0x1,0x4a,0x3,0x1,0x2,0x2,0x19,0x4b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x26,0x1c,0x25,0x2a, + 0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x1,0x1,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1, + 0x3,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x33,0x32,0x17,0x4,0x77,0x17,0xfe,0x82,0x1,0x7,0xc,0x31,0x24,0x13,0xe,0x15,0xb, + 0xf3,0xfe,0x9d,0x1e,0x23,0x18,0x1e,0x27,0x16,0x1,0x8e,0xfd,0xd,0x32,0x22,0x15,0xe,0x15,0xb,0xe9,0x1,0x53,0x1e,0x22,0x19,0x1e,0x3,0x89,0x1c,0x14, + 0x16,0xfe,0x8d,0xfe,0x89,0x12,0x10,0x22,0x15,0xf,0xe,0x10,0x1,0x5f,0xfe,0xa1,0x1e,0xf,0x13,0x1b,0x15,0x16,0x1,0x84,0x1,0x66,0x11,0x12,0x21,0x15, + 0xf,0xe,0x10,0xfe,0xb4,0x1,0x4c,0x1e,0xf,0x0,0x0,0x1,0x0,0xc9,0xfe,0x6d,0x4,0xa0,0x3,0xa9,0x0,0x21,0x0,0x1c,0x40,0x19,0x1b,0xf,0x2,0x0, + 0x1,0x1,0x4a,0x2,0x1,0x1,0x1,0x11,0x4b,0x0,0x0,0x0,0x13,0x0,0x4c,0x26,0x2e,0x26,0x3,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x23, + 0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x13,0x1,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x36,0x33,0x32,0x17,0x4,0x88,0x18,0x10, + 0xfc,0xd8,0x1b,0x1f,0x14,0x1a,0x15,0x15,0x11,0xe9,0xfe,0xfe,0x5,0x1d,0x21,0x1e,0xd,0x12,0x15,0x8,0xdc,0x1,0xce,0xe,0x19,0x10,0x11,0x1d,0x3,0x90, + 0x19,0x10,0x11,0x18,0xfb,0x56,0x27,0xf,0xc,0x1a,0xf,0x12,0x1a,0x1,0x56,0x3,0x15,0x11,0xb,0x15,0x1b,0x8,0x7,0x13,0x16,0xfd,0x59,0x2,0xaf,0x14, + 0x13,0xd,0x0,0x0,0xff,0xff,0x0,0xc9,0xfe,0x6d,0x4,0xa0,0x5,0x5e,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2,0x1,0x80,0xfe,0x0,0x0,0x0,0xff,0xff, + 0x0,0xc9,0xfe,0x6d,0x4,0xa0,0x5,0x60,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2,0x1,0x92,0xf1,0x0,0x0,0x0,0xff,0xff,0x0,0xc9,0xfe,0x6d,0x4,0xa0, + 0x5,0x28,0x0,0x22,0x0,0xf6,0x0,0x0,0x0,0x2,0x1,0x93,0xec,0x0,0x0,0x0,0xff,0xff,0x0,0xc9,0xfe,0x6d,0x4,0xa0,0x5,0x5e,0x0,0x22,0x0,0xf6, + 0x0,0x0,0x0,0x2,0x1,0x95,0xd8,0x0,0x0,0x0,0x0,0x1,0x0,0x7f,0x0,0x0,0x4,0x58,0x3,0x9c,0x0,0x23,0x0,0x31,0x40,0x2e,0x14,0xb,0x2,0x0, + 0x1,0x1d,0x2,0x2,0x3,0x2,0x2,0x4a,0x0,0x0,0x0,0x1,0x59,0x0,0x1,0x1,0x11,0x4b,0x0,0x2,0x2,0x3,0x59,0x4,0x1,0x3,0x3,0xf,0x3,0x4c, + 0x0,0x0,0x0,0x23,0x0,0x21,0x27,0x36,0x27,0x5,0x7,0x17,0x2b,0x32,0x26,0x35,0x34,0x37,0x36,0x37,0x1,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33, + 0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x7,0x1,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x99,0x1a,0x2,0x5,0x11,0x2,0xb6,0xfd,0xf1,0x1b,0x1a, + 0x3,0x7,0x22,0x22,0x2,0xcc,0x1c,0x19,0x2,0x4,0x13,0xfd,0x4c,0x2,0x2d,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfd,0x16,0x15,0x18,0x7,0x10,0x1d,0x10,0x2, + 0x9b,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x19,0x6,0x10,0x1d,0x11,0xfd,0x66,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0x7f,0x0,0x0, + 0x4,0x58,0x5,0x5e,0x0,0x22,0x1,0x80,0xe2,0x0,0x0,0x2,0x0,0xfb,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0x7f,0x0,0x0,0x4,0x58,0x5,0x64,0x0,0x22, + 0x0,0xfb,0x0,0x0,0x0,0x2,0x1,0x83,0xe2,0x0,0x0,0x0,0xff,0xff,0x0,0x7f,0x0,0x0,0x4,0x58,0x5,0x51,0x0,0x22,0x0,0xfb,0x0,0x0,0x0,0x2, + 0x1,0x94,0xe9,0x0,0x0,0x0,0xff,0xff,0x0,0xfb,0xfe,0x72,0x8,0xdc,0x5,0x53,0x0,0x22,0x0,0x9f,0x0,0x0,0x0,0x3,0x0,0xa8,0x4,0xcc,0x0,0x0, + 0xff,0xff,0x0,0xfb,0xfe,0x72,0x8,0xc8,0x5,0x25,0x0,0x22,0x0,0x9f,0x0,0x0,0x0,0x3,0x0,0xb9,0x4,0xcc,0x0,0x0,0x0,0x2,0x1,0x35,0x1,0xd1, + 0x4,0x59,0x4,0xb9,0x0,0x29,0x0,0x37,0x0,0x8,0xb5,0x2f,0x2a,0x15,0xd,0x2,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x27, + 0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x37,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x33, + 0x4,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x4,0x45,0x14,0x2,0x7,0x1d,0x1b,0xa,0x3b,0x53,0xd,0x3d,0x89,0x56,0x53,0x84, + 0x4b,0x5d,0xb8,0x80,0x4e,0x6d,0x1d,0xd,0x6,0x1c,0x26,0x20,0x1a,0x2,0x4d,0x3,0x28,0x23,0x4,0xfe,0x94,0x79,0x3c,0x5e,0x58,0x4a,0x73,0x40,0x59,0x4e, + 0x2,0x64,0x15,0x15,0x7,0x10,0x21,0x1f,0x3d,0x39,0x46,0x42,0x49,0x87,0x5a,0x69,0xce,0x87,0x43,0x3b,0x43,0x1c,0x16,0x10,0x12,0x4,0xc,0xfe,0x4c,0x10, + 0xe,0x24,0x24,0xf,0x52,0x89,0x52,0x5a,0x59,0x56,0x8d,0x50,0x52,0x5b,0x0,0x0,0x0,0x2,0x1,0x3e,0x1,0xd1,0x4,0x28,0x4,0xb9,0x0,0xf,0x0,0x1d, + 0x0,0x8,0xb5,0x15,0x10,0x6,0x0,0x2,0x30,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14, + 0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x43,0x93,0x52,0x67,0xc1,0x80,0x5e,0x92,0x52,0x68,0xc1,0x7f,0x60,0x7b,0x42,0x6a,0x5b,0x4a,0x7c,0x48, + 0x69,0x5b,0x4,0xb9,0x51,0x8f,0x5a,0x6a,0xc7,0x7d,0x50,0x8f,0x5a,0x6c,0xc7,0x7c,0x84,0x55,0x86,0x47,0x56,0x68,0x4c,0x85,0x51,0x56,0x68,0x0,0x0,0x0, + 0x0,0x2,0x0,0x5a,0x0,0x0,0x4,0x0,0x4,0xb9,0x0,0x14,0x0,0x18,0x0,0x8,0xb5,0x16,0x15,0x9,0x0,0x2,0x30,0x2b,0x0,0x16,0x17,0x13,0x16,0x15, + 0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x7,0x1,0x21,0x3,0x3,0x20,0x2b,0x6,0xae,0x1,0x3,0x7,0x21,0x22,0xfc, + 0xd9,0x1f,0x13,0xb,0x2,0x20,0x12,0x38,0x29,0x1e,0xfe,0x3d,0x2,0x4a,0x85,0x4,0xb9,0x1f,0x22,0xfb,0xf2,0x5,0x8,0xb,0xf,0x25,0x1e,0x1a,0x28,0x14, + 0x14,0x4,0xe,0x22,0x1f,0xbb,0xfc,0x8a,0x3,0x76,0x0,0x1,0x0,0x19,0x0,0x0,0x4,0x9f,0x4,0xb9,0x0,0x3f,0x0,0x6,0xb3,0xe,0x0,0x1,0x30,0x2b, + 0x0,0x16,0x16,0x15,0x14,0x2,0x7,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x35,0x34,0x37,0x36,0x37,0x36,0x12,0x35,0x34,0x26,0x26,0x23, + 0x22,0x6,0x7,0x6,0x6,0x15,0x14,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x26,0x26,0x35,0x34,0x36, + 0x37,0x36,0x36,0x33,0x3,0x6c,0xc8,0x6b,0xa4,0xa4,0xbc,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0xa7,0x33,0x2,0x8,0x14,0xc9,0xb1,0x48,0x86,0x5d,0x69,0xaa, + 0x3d,0x37,0x39,0xbd,0x9,0x3,0x7,0x24,0x22,0xfe,0xbd,0x1b,0x1a,0x3,0x7,0x22,0x22,0xc5,0x4e,0x59,0x43,0x45,0x53,0xf0,0x96,0x4,0xb9,0x77,0xda,0x90, + 0xa6,0xfe,0xca,0x6c,0x16,0x18,0xb,0xf,0x27,0x21,0x34,0x10,0xa,0x34,0xc,0x70,0x1,0x2e,0xa6,0x69,0x99,0x51,0x62,0x55,0x4d,0xbf,0x60,0xde,0x95,0x6, + 0x19,0x10,0x12,0x2a,0x24,0x16,0x18,0xb,0xf,0x27,0x21,0x47,0xbe,0x72,0x78,0xe2,0x60,0x74,0x84,0x0,0x0,0x0,0x0,0x1,0x0,0x57,0xfe,0x72,0x4,0x51, + 0x3,0xa6,0x0,0x38,0x0,0x6,0xb3,0x18,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x6,0x6, + 0x23,0x22,0x26,0x27,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33, + 0x32,0x36,0x36,0x37,0x13,0x36,0x36,0x33,0x33,0x4,0x33,0x1e,0x2,0x8f,0x6,0x21,0x27,0x2,0x21,0x1d,0x2,0x19,0x4e,0xc3,0x61,0x35,0x57,0x1f,0x41,0x6, + 0x27,0x28,0x2,0x23,0x1e,0x2,0xd4,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x61,0x5,0x4b,0x4e,0x4c,0xa7,0x7e,0x12,0x40,0x6,0x27,0x28,0x2,0x3,0xa6,0x15, + 0x18,0x4,0x10,0xfc,0xd2,0x24,0x1d,0x15,0x17,0x5,0x10,0x8f,0x62,0x7a,0x1e,0x1c,0xfe,0x8f,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0xb2,0x23,0x1e,0x15,0x18, + 0x4,0x10,0xfd,0xda,0x1e,0x17,0x42,0x4a,0x66,0xad,0x65,0x1,0x6f,0x23,0x1e,0x0,0x0,0x0,0x0,0x1,0x0,0xaf,0xff,0xf6,0x4,0xbc,0x3,0x9c,0x0,0x29, + 0x0,0x6,0xb3,0xb,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x3, + 0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0xa3,0x19,0x2,0x8,0x22,0x22,0x56,0x80,0x6, + 0x27,0x28,0x2,0x23,0x1e,0x2,0x80,0xfe,0x50,0x80,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x80,0x58,0x1b,0x1a,0x3,0x7,0x22,0x22,0x3,0x8a,0x3,0x9c,0x16, + 0x19,0xf,0xa,0x27,0x21,0xfd,0x2b,0x23,0x1e,0x15,0x18,0x4,0x10,0x2,0xd5,0xfd,0x2b,0x23,0x1e,0x15,0x18,0x4,0x10,0x2,0xd5,0x15,0x18,0xc,0xf,0x27, + 0x21,0x0,0x0,0x0,0x0,0x3,0x0,0xd4,0xff,0xea,0x4,0x3d,0x4,0xb9,0x0,0xf,0x0,0x18,0x0,0x21,0x0,0x3a,0x40,0x37,0x1e,0x1c,0x15,0x13,0x4,0x3, + 0x2,0x1,0x4a,0x5,0x1,0x2,0x2,0x1,0x5b,0x4,0x1,0x1,0x1,0x16,0x4b,0x6,0x1,0x3,0x3,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x19,0x19,0x10, + 0x10,0x0,0x0,0x19,0x21,0x19,0x20,0x10,0x18,0x10,0x17,0x0,0xf,0x0,0xe,0x26,0x7,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x6,0x23,0x22,0x26, + 0x26,0x35,0x34,0x12,0x36,0x33,0x6,0x6,0x2,0x15,0x15,0x1,0x26,0x26,0x23,0x2,0x36,0x12,0x35,0x35,0x1,0x16,0x16,0x33,0x3,0x52,0x9a,0x51,0x75,0xf1, + 0xae,0x6a,0x9a,0x51,0x75,0xf1,0xae,0x7c,0xa7,0x5a,0x2,0x1f,0x19,0x5a,0x3c,0x36,0xa7,0x5a,0xfd,0xe1,0x19,0x59,0x3d,0x4,0xb9,0x70,0xcc,0x89,0xac,0xfe, + 0x97,0xf5,0x70,0xcc,0x89,0xac,0x1,0x69,0xf5,0x94,0xc3,0xfe,0xd9,0x91,0xf,0x2,0x9,0x3f,0x42,0xfc,0x59,0xc3,0x1,0x27,0x91,0xd,0xfd,0xf7,0x3e,0x41, + 0x0,0x1,0x0,0xc5,0x0,0x0,0x3,0xea,0x4,0xbc,0x0,0x25,0x0,0x35,0x40,0x32,0x12,0x1,0x2,0x3,0xb,0x2,0x2,0x0,0x1,0x2,0x4a,0x0,0x2,0x3, + 0x1,0x3,0x2,0x1,0x70,0x0,0x3,0x3,0x16,0x4b,0x5,0x4,0x2,0x1,0x1,0x0,0x5a,0x0,0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x25,0x0,0x24,0x17, + 0x23,0x26,0x36,0x6,0x7,0x18,0x2b,0x24,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x5,0x6,0x23,0x22, + 0x27,0x26,0x35,0x34,0x37,0x25,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x21,0x3,0xd0,0x1a,0x3,0x7,0x22,0x22,0xfd,0x5e,0x1c,0x19,0x2,0x7,0x23,0x22, + 0xf9,0x94,0xfe,0xf4,0x10,0xd,0x20,0x17,0xd,0x21,0x1,0xae,0x15,0x15,0x12,0x18,0x1,0xb3,0x1,0x13,0x90,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x19,0xf, + 0xa,0x27,0x21,0x3,0x48,0x97,0x8,0x2c,0x19,0x13,0x1f,0x11,0xef,0xc,0x16,0x13,0x9,0x5,0xfc,0xb,0x0,0x0,0x0,0x1,0x0,0x85,0x0,0x0,0x4,0x24, + 0x4,0xb9,0x0,0x2f,0x0,0x35,0x40,0x32,0x15,0xc,0x2,0x1,0x0,0x1,0x4a,0x0,0x3,0x2,0x0,0x2,0x3,0x0,0x70,0x0,0x2,0x2,0x4,0x5b,0x5,0x1, + 0x4,0x4,0x16,0x4b,0x0,0x0,0x0,0x1,0x59,0x0,0x1,0x1,0xf,0x1,0x4c,0x0,0x0,0x0,0x2f,0x0,0x2e,0x23,0x2d,0x36,0x28,0x6,0x7,0x18,0x2b,0x0, + 0x16,0x16,0x15,0x14,0x6,0x6,0x7,0x1,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x37,0x1,0x3e,0x2,0x35,0x34, + 0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x3,0x36,0x9a,0x54,0x3a,0x74,0x62,0xfe,0x7c,0x2,0x11,0x1b,0x1a,0x3, + 0x7,0x22,0x22,0xfd,0x33,0x1c,0x1a,0x2,0x7,0x12,0x2,0x7,0x50,0x5f,0x2f,0x64,0x60,0x42,0x96,0x48,0x11,0x12,0x22,0x14,0x9,0x28,0x53,0xbc,0x5a,0x4, + 0xb9,0x48,0x87,0x5b,0x52,0x89,0x83,0x54,0xfe,0xb3,0x16,0x18,0xb,0xf,0x27,0x21,0x15,0x18,0x7,0x10,0x26,0x10,0x1,0xbe,0x45,0x68,0x66,0x3a,0x4b,0x55, + 0x2c,0x29,0xa,0x2a,0x15,0x12,0x25,0x17,0x32,0x34,0x0,0x0,0x0,0x1,0x0,0x93,0xff,0xea,0x4,0x16,0x4,0xb9,0x0,0x41,0x0,0x48,0x40,0x45,0x27,0x6, + 0x2,0x3,0x4,0x1,0x4a,0x0,0x6,0x5,0x4,0x5,0x6,0x4,0x70,0x0,0x1,0x3,0x2,0x3,0x1,0x2,0x70,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0, + 0x5,0x5,0x7,0x5b,0x8,0x1,0x7,0x7,0x16,0x4b,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x41,0x0,0x40,0x22,0x25,0x36, + 0x35,0x23,0x28,0x2c,0x9,0x7,0x1b,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36, + 0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x32,0x36,0x36,0x35,0x34,0x26, + 0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x3,0x31,0x96,0x4f,0x62,0x64,0x45,0x4a,0x5e,0xd2,0xa3,0x62,0xbc,0x45,0x16,0x12, + 0xd,0x20,0x10,0x11,0xf,0x39,0x93,0x4e,0x67,0x86,0x3d,0x72,0x68,0x49,0x1c,0x19,0x2,0x7,0x22,0x22,0x37,0x60,0x78,0x34,0x65,0x5f,0x8c,0x8b,0x12,0xc, + 0x20,0x14,0xa,0x29,0x50,0xb2,0x57,0x4,0xb9,0x47,0x7f,0x54,0x66,0x9c,0x2c,0x20,0x7b,0x57,0x5f,0xb9,0x7d,0x44,0x3a,0x13,0x18,0x17,0x1b,0x14,0x1a,0xe, + 0x30,0x37,0x4d,0x77,0x3f,0x53,0x57,0x15,0x18,0x5,0x12,0x25,0x1f,0x41,0x66,0x3b,0x44,0x4c,0x49,0x8,0x2c,0x15,0x13,0x25,0x16,0x2b,0x2b,0x0,0x0,0x2, + 0x0,0x8b,0xff,0xf6,0x4,0x25,0x4,0xb9,0x0,0x25,0x0,0x28,0x0,0x38,0x40,0x35,0x28,0x1,0x2,0x0,0x4,0x1d,0x8,0x2,0x1,0x0,0x16,0x1,0x2,0x1, + 0x3,0x4a,0x5,0x1,0x0,0x3,0x1,0x1,0x2,0x0,0x1,0x62,0x6,0x1,0x4,0x4,0x16,0x4b,0x0,0x2,0x2,0xf,0x2,0x4c,0x0,0x0,0x27,0x26,0x0,0x25, + 0x0,0x24,0x25,0x33,0x26,0x24,0x7,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x3,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x7,0x6,0x6,0x23,0x23, + 0x22,0x26,0x35,0x34,0x37,0x37,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x37,0x1,0x36,0x36,0x33,0x1,0x21,0x13,0x3,0xc9,0x2,0x79,0xa2,0x1b,0x1a,0x3,0x7, + 0x22,0x22,0xa2,0x2c,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x2c,0xfe,0x22,0x1c,0x1a,0x2,0x6,0xe,0x2,0x64,0x1a,0x37,0x26,0xfd,0xe9,0x1,0x53,0x66,0x4, + 0xb9,0x3c,0x6,0xc,0xfd,0x53,0x15,0x18,0xc,0xf,0x27,0x21,0xf7,0x23,0x1e,0x15,0x18,0x4,0x10,0xf7,0x18,0x1a,0xf,0x9,0x20,0x11,0x2,0xd3,0x20,0x1d, + 0xfd,0x5,0x2,0x17,0x0,0x0,0x0,0x1,0x0,0x9d,0xff,0xea,0x4,0x35,0x4,0xa3,0x0,0x35,0x0,0x4a,0x40,0x47,0x2,0x1,0x0,0x7,0x9,0x1,0x5,0x1, + 0x2,0x4a,0x0,0x6,0x5,0x3,0x5,0x6,0x3,0x70,0x0,0x3,0x4,0x5,0x3,0x4,0x6e,0x0,0x1,0x0,0x5,0x6,0x1,0x5,0x63,0x0,0x0,0x0,0x7,0x59, + 0x8,0x1,0x7,0x7,0xe,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x0,0x0,0x0,0x35,0x0,0x33,0x23,0x25,0x24,0x17,0x26,0x22,0x26, + 0x9,0x7,0x1b,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34, + 0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x6,0x23,0x22,0x26,0x37,0x13,0x36,0x36,0x33,0x21,0x4,0x1b, + 0x1a,0x3,0x7,0x23,0x22,0xfe,0x2d,0x42,0x62,0x74,0x68,0x96,0x4e,0x69,0xda,0x9f,0x5f,0xb7,0x46,0x18,0x15,0x1d,0x1c,0xe,0x10,0x39,0x8f,0x4b,0x68,0x8f, + 0x46,0x6e,0x61,0x7b,0x6d,0xd,0x18,0x12,0x23,0x2a,0x4,0x71,0x8,0x26,0x29,0x2,0x16,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0xcc,0x33,0x56,0x99, + 0x64,0x6e,0xd8,0x8f,0x40,0x37,0x12,0x1a,0x18,0x1f,0x2b,0xd,0x2e,0x36,0x5e,0x92,0x4d,0x59,0x6a,0x43,0x8,0x6,0x16,0x14,0x2,0xb,0x23,0x1e,0x0,0x2, + 0x0,0xd7,0xff,0xea,0x4,0x56,0x4,0xba,0x0,0x1a,0x0,0x28,0x0,0x3c,0x40,0x39,0x7,0x1,0x5,0x1,0x1,0x4a,0x0,0x1,0x7,0x1,0x5,0x4,0x1,0x5, + 0x63,0x0,0x0,0x0,0x3,0x5b,0x6,0x1,0x3,0x3,0x16,0x4b,0x0,0x4,0x4,0x2,0x5b,0x0,0x2,0x2,0x17,0x2,0x4c,0x1b,0x1b,0x0,0x0,0x1b,0x28,0x1b, + 0x27,0x22,0x20,0x0,0x1a,0x0,0x19,0x26,0x24,0x23,0x8,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x4,0x4,0x7,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14, + 0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x37,0x0,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x4,0x3a,0x1c,0x30,0xfe, + 0xf4,0xfe,0xb4,0x41,0x41,0x9e,0x57,0x60,0x95,0x53,0x6d,0xd1,0x8d,0x7a,0xa2,0x4d,0xd0,0x1,0x7d,0xfd,0xfe,0x34,0x8f,0x57,0x72,0x65,0x61,0x87,0x43,0x69, + 0x61,0x4,0xba,0x1e,0x26,0x4e,0x2,0xe,0xf4,0xcc,0x40,0x43,0x4f,0x91,0x5e,0x6d,0xc8,0x7e,0x66,0xa9,0x67,0xf7,0x1,0x7c,0xda,0xc,0xfd,0x8e,0x40,0x78, + 0x50,0x58,0x69,0x51,0x80,0x44,0x56,0x5e,0x0,0x0,0x0,0x1,0x1,0x42,0xff,0xea,0x4,0x86,0x4,0xa3,0x0,0x1a,0x0,0x2a,0x40,0x27,0x14,0x2,0x2,0x1, + 0x2,0xd,0x1,0x0,0x1,0x2,0x4a,0x0,0x1,0x1,0x2,0x59,0x3,0x1,0x2,0x2,0xe,0x4b,0x0,0x0,0x0,0x17,0x0,0x4c,0x0,0x0,0x0,0x1a,0x0,0x18, + 0x25,0x29,0x4,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x21,0x22,0x26,0x35,0x34,0x37,0x36, + 0x36,0x33,0x21,0x4,0x6d,0x19,0x2,0x4,0x9,0xfd,0x9c,0xe,0x30,0x1b,0x1d,0x2a,0x9,0x2,0x42,0xfd,0xb9,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xc0,0x4, + 0xa3,0x14,0x18,0xf,0x9,0x16,0x12,0xfb,0xe1,0x17,0x17,0x1a,0x16,0x10,0xe,0x3,0xdb,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x3,0x0,0xc2, + 0xff,0xea,0x4,0x2c,0x4,0xb9,0x0,0x1b,0x0,0x2a,0x0,0x39,0x0,0x44,0x40,0x41,0x14,0x6,0x2,0x5,0x2,0x1,0x4a,0x0,0x2,0x8,0x1,0x5,0x4,0x2, + 0x5,0x63,0x7,0x1,0x3,0x3,0x1,0x5b,0x6,0x1,0x1,0x1,0x16,0x4b,0x0,0x4,0x4,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x2b,0x2b,0x1c,0x1c,0x0, + 0x0,0x2b,0x39,0x2b,0x38,0x33,0x31,0x1c,0x2a,0x1c,0x29,0x24,0x22,0x0,0x1b,0x0,0x1a,0x2c,0x9,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x7,0x16, + 0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x37,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36, + 0x35,0x34,0x26,0x23,0x2,0x6,0x6,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x48,0x93,0x51,0x73,0x60,0x48,0x53,0x6c,0xd2,0x90, + 0x68,0xa2,0x5a,0x8e,0x74,0x38,0x43,0x63,0xbe,0x81,0x5c,0x73,0x3c,0x2f,0x54,0x37,0x43,0x73,0x44,0x66,0x53,0xb2,0x83,0x46,0x34,0x61,0x41,0x57,0x83,0x47, + 0x74,0x62,0x4,0xb9,0x4c,0x82,0x50,0x65,0x96,0x2f,0x23,0x7e,0x50,0x60,0xbc,0x7a,0x51,0x8e,0x59,0x78,0xb1,0x30,0x22,0x6e,0x43,0x51,0xa9,0x71,0x94,0x3e, + 0x63,0x35,0x2c,0x46,0x28,0x3b,0x64,0x3a,0x46,0x51,0xfe,0x5,0x49,0x75,0x3f,0x34,0x4f,0x2c,0x48,0x75,0x40,0x4f,0x60,0x0,0x0,0x0,0x0,0x2,0x0,0xba, + 0xff,0xe9,0x4,0x39,0x4,0xb9,0x0,0x1a,0x0,0x28,0x0,0x3c,0x40,0x39,0xf,0x1,0x2,0x4,0x1,0x4a,0x0,0x4,0x0,0x2,0x1,0x4,0x2,0x63,0x7,0x1, + 0x5,0x5,0x3,0x5b,0x6,0x1,0x3,0x3,0x16,0x4b,0x0,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x17,0x0,0x4c,0x1b,0x1b,0x0,0x0,0x1b,0x28,0x1b,0x27,0x22, + 0x20,0x0,0x1a,0x0,0x19,0x24,0x23,0x26,0x8,0x7,0x17,0x2b,0x0,0x16,0x16,0x15,0x14,0x2,0x4,0x7,0x6,0x26,0x35,0x34,0x37,0x24,0x24,0x37,0x6,0x6, + 0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x4a,0xa2,0x4d,0xd0,0xfe,0x83,0xfd, + 0x19,0x1c,0x30,0x1,0xc,0x1,0x4c,0x41,0x41,0x9e,0x57,0x60,0x95,0x53,0x6d,0xd1,0x8d,0x67,0x87,0x43,0x69,0x61,0x52,0x8f,0x57,0x72,0x65,0x4,0xb9,0x66, + 0xa9,0x67,0xf7,0xfe,0x84,0xda,0xc,0x1,0x1e,0x26,0x4e,0x2,0xe,0xf4,0xcc,0x40,0x43,0x4f,0x91,0x5e,0x6d,0xc8,0x7e,0x94,0x51,0x80,0x44,0x56,0x5e,0x40, + 0x78,0x50,0x58,0x69,0x0,0x1,0x0,0x54,0x0,0xc4,0x4,0xa1,0x3,0x56,0x0,0x11,0x0,0x11,0x40,0xe,0x0,0x0,0x1,0x0,0x72,0x0,0x1,0x1,0x69,0x18, + 0x11,0x2,0x7,0x16,0x2b,0x0,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x4,0x68,0x9,0x19,0xf,0x8,0x13, + 0xfc,0x7,0x7,0x9,0x19,0xf,0x9,0x14,0x3,0xf9,0x3,0x56,0x1c,0xd,0x11,0x19,0xa,0xfd,0xcf,0x4,0x1c,0xf,0xf,0x18,0xb,0x2,0x31,0x0,0x0,0x3, + 0x0,0x3a,0xff,0x28,0x4,0xa1,0x5,0x72,0x0,0x21,0x0,0x33,0x0,0x5d,0x0,0x6a,0xb1,0x6,0x64,0x44,0x40,0x5f,0xd,0x6,0x2,0x1,0x0,0x3e,0x1,0x6, + 0x5,0x2,0x4a,0x21,0x1b,0x13,0x3,0x3,0x48,0x0,0x3,0x0,0x3,0x72,0x0,0x8,0x7,0x4,0x7,0x8,0x4,0x70,0x0,0x4,0x5,0x7,0x4,0x5,0x6e,0x2, + 0x1,0x0,0x0,0x1,0x9,0x0,0x1,0x61,0xa,0x1,0x9,0x0,0x7,0x8,0x9,0x7,0x63,0x0,0x5,0x6,0x6,0x5,0x55,0x0,0x5,0x5,0x6,0x59,0x0,0x6, + 0x5,0x6,0x4d,0x34,0x34,0x34,0x5d,0x34,0x5c,0x55,0x54,0x50,0x4e,0x45,0x42,0x3b,0x3a,0x2d,0x2c,0x24,0x23,0x24,0x34,0x23,0xb,0x7,0x17,0x2b,0xb1,0x6, + 0x0,0x44,0x0,0x16,0x7,0x3,0x33,0x32,0x15,0x14,0x7,0x6,0x23,0x21,0x22,0x35,0x34,0x37,0x36,0x33,0x33,0x13,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35, + 0x34,0x36,0x37,0x37,0x36,0x33,0x0,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x2,0x16,0x15,0x14,0x6,0x7, + 0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x35,0x34,0x37,0x25,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26, + 0x35,0x34,0x37,0x36,0x36,0x33,0x1,0xe2,0xf,0x2,0x65,0xa2,0x22,0x2,0x8,0x2a,0xfe,0x42,0x22,0x2,0x8,0x2a,0xab,0x54,0x99,0x10,0x5,0xc,0xf,0x4, + 0x3,0x11,0x15,0xfa,0xb,0xa,0x2,0x96,0x9,0x19,0xf,0x8,0x13,0xfc,0x7,0x7,0x9,0x19,0xf,0x9,0x14,0x3,0xf9,0x44,0x71,0x51,0x5d,0xe5,0x1,0x3a, + 0x12,0x11,0x1,0x4,0x15,0x14,0xfe,0x2f,0x1f,0x26,0x1,0x3e,0x40,0x38,0x39,0x37,0x2c,0x66,0x2d,0x8,0x9,0x17,0xd,0x7,0x13,0x39,0x87,0x3c,0x5,0x72, + 0x13,0x10,0xfd,0xc5,0x22,0x4,0xe,0x34,0x22,0x4,0xe,0x34,0x1,0xdc,0x2f,0x4,0x11,0x13,0xe,0xa,0x10,0x13,0x6,0x4c,0x4,0xfe,0xc,0x1c,0xd,0x11, + 0x19,0xa,0xfd,0xcf,0x4,0x1c,0xf,0xf,0x18,0xb,0x2,0x31,0xfe,0x74,0x64,0x56,0x49,0x73,0x43,0xa5,0x11,0x14,0x9,0x6,0x1b,0x19,0x26,0x30,0x1c,0xea, + 0x2f,0x49,0x2e,0x29,0x2f,0x19,0x14,0x4,0x23,0xf,0xf,0x13,0xb,0x1e,0x20,0x0,0x0,0x0,0x0,0x4,0x0,0x3a,0xff,0x22,0x4,0xa1,0x5,0x72,0x0,0x21, + 0x0,0x33,0x0,0x52,0x0,0x55,0x0,0xb4,0xb1,0x6,0x64,0x44,0x40,0x15,0xd,0x6,0x2,0x1,0x0,0x55,0x1,0x4,0x9,0x44,0x1,0x7,0x6,0x3,0x4a,0x21, + 0x1b,0x13,0x3,0x3,0x48,0x4b,0xb0,0xe,0x50,0x58,0x40,0x37,0x0,0x3,0x0,0x3,0x72,0xb,0x1,0x9,0x1,0x4,0x1,0x9,0x4,0x70,0x0,0x4,0x5,0x1, + 0x4,0x5,0x6e,0x0,0x7,0x6,0x6,0x7,0x67,0x2,0x1,0x0,0x0,0x1,0x9,0x0,0x1,0x61,0xa,0x1,0x5,0x6,0x6,0x5,0x57,0xa,0x1,0x5,0x5,0x6, + 0x5c,0x8,0x1,0x6,0x5,0x6,0x50,0x1b,0x40,0x36,0x0,0x3,0x0,0x3,0x72,0xb,0x1,0x9,0x1,0x4,0x1,0x9,0x4,0x70,0x0,0x4,0x5,0x1,0x4,0x5, + 0x6e,0x0,0x7,0x6,0x7,0x73,0x2,0x1,0x0,0x0,0x1,0x9,0x0,0x1,0x61,0xa,0x1,0x5,0x6,0x6,0x5,0x57,0xa,0x1,0x5,0x5,0x6,0x5c,0x8,0x1, + 0x6,0x5,0x6,0x50,0x59,0x40,0x1a,0x34,0x34,0x54,0x53,0x34,0x52,0x34,0x51,0x48,0x47,0x43,0x41,0x3e,0x3c,0x39,0x37,0x2d,0x2c,0x24,0x23,0x24,0x34,0x23, + 0xc,0x7,0x17,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x7,0x3,0x33,0x32,0x15,0x14,0x7,0x6,0x23,0x21,0x22,0x35,0x34,0x37,0x36,0x33,0x33,0x13,0x7,0x6, + 0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x36,0x37,0x37,0x36,0x33,0x0,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1, + 0x2,0x16,0x7,0x3,0x33,0x32,0x15,0x14,0x6,0x23,0x23,0x7,0x6,0x6,0x23,0x22,0x35,0x34,0x37,0x37,0x21,0x22,0x26,0x35,0x34,0x36,0x37,0x1,0x36,0x36, + 0x33,0x1,0x33,0x13,0x1,0xe2,0xf,0x2,0x65,0xa2,0x22,0x2,0x8,0x2a,0xfe,0x42,0x22,0x2,0x8,0x2a,0xab,0x54,0x99,0x10,0x5,0xc,0xf,0x4,0x3,0x11, + 0x15,0xfa,0xb,0xa,0x2,0x96,0x9,0x19,0xf,0x8,0x13,0xfc,0x7,0x7,0x9,0x19,0xf,0x9,0x14,0x3,0xf9,0x2e,0x29,0x4,0x42,0x5c,0x22,0x1a,0x1a,0x5c, + 0x1b,0x4,0x1d,0x1e,0x33,0x1,0x1b,0xfe,0xc6,0x11,0x13,0xb,0xd,0x1,0x7f,0x13,0x22,0x15,0xfe,0xb7,0xd8,0x35,0x5,0x72,0x13,0x10,0xfd,0xc5,0x22,0x4, + 0xe,0x34,0x22,0x4,0xe,0x34,0x1,0xdc,0x2f,0x4,0x11,0x13,0xe,0xa,0x10,0x13,0x6,0x4c,0x4,0xfd,0xda,0x1c,0xd,0x11,0x19,0xa,0xfd,0xcf,0x4,0x1c, + 0xf,0xf,0x18,0xb,0x2,0x31,0xfe,0xa7,0x1a,0x14,0xfe,0x8b,0x22,0x22,0x25,0x99,0x14,0x14,0x1f,0x6,0x3,0x99,0x18,0x17,0x19,0x18,0xe,0x1,0x7a,0x13, + 0x11,0xfe,0x5d,0x1,0xa,0x0,0x0,0x0,0x0,0x4,0x0,0x54,0xff,0x22,0x4,0xa1,0x5,0x72,0x0,0x3a,0x0,0x4c,0x0,0x6b,0x0,0x6e,0x1,0x28,0xb1,0x6, + 0x64,0x44,0x40,0x13,0x36,0x1,0x5,0x6,0x23,0x5,0x2,0x3,0x4,0x6e,0x1,0x8,0xd,0x5d,0x1,0xb,0xa,0x4,0x4a,0x4b,0xb0,0xe,0x50,0x58,0x40,0x44, + 0x10,0x1,0xd,0x0,0x8,0x0,0xd,0x8,0x70,0x0,0xb,0xa,0xa,0xb,0x67,0xf,0x1,0x6,0x0,0x5,0x4,0x6,0x5,0x63,0x0,0x4,0x0,0x3,0x1,0x4, + 0x3,0x63,0x0,0x2,0x0,0x0,0xd,0x2,0x0,0x63,0x7,0x1,0x1,0x0,0x8,0x9,0x1,0x8,0x63,0xe,0x1,0x9,0xa,0xa,0x9,0x57,0xe,0x1,0x9,0x9, + 0xa,0x5c,0xc,0x1,0xa,0x9,0xa,0x50,0x1b,0x4b,0xb0,0x13,0x50,0x58,0x40,0x43,0x10,0x1,0xd,0x0,0x8,0x0,0xd,0x8,0x70,0x0,0xb,0xa,0xb,0x73, + 0xf,0x1,0x6,0x0,0x5,0x4,0x6,0x5,0x63,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x2,0x0,0x0,0xd,0x2,0x0,0x63,0x7,0x1,0x1,0x0,0x8, + 0x9,0x1,0x8,0x63,0xe,0x1,0x9,0xa,0xa,0x9,0x57,0xe,0x1,0x9,0x9,0xa,0x5c,0xc,0x1,0xa,0x9,0xa,0x50,0x1b,0x40,0x4a,0x0,0x7,0x3,0x1, + 0x3,0x7,0x1,0x70,0x10,0x1,0xd,0x0,0x8,0x0,0xd,0x8,0x70,0x0,0xb,0xa,0xb,0x73,0xf,0x1,0x6,0x0,0x5,0x4,0x6,0x5,0x63,0x0,0x4,0x0, + 0x3,0x7,0x4,0x3,0x63,0x0,0x2,0x0,0x0,0xd,0x2,0x0,0x63,0x0,0x1,0x0,0x8,0x9,0x1,0x8,0x63,0xe,0x1,0x9,0xa,0xa,0x9,0x57,0xe,0x1, + 0x9,0x9,0xa,0x5c,0xc,0x1,0xa,0x9,0xa,0x50,0x59,0x59,0x40,0x23,0x4d,0x4d,0x0,0x0,0x6d,0x6c,0x4d,0x6b,0x4d,0x6a,0x61,0x60,0x5c,0x5a,0x57,0x55, + 0x52,0x50,0x46,0x45,0x3d,0x3c,0x0,0x3a,0x0,0x39,0x23,0x35,0x34,0x24,0x17,0x2b,0x11,0x7,0x1a,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x15,0x14,0x6,0x7, + 0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x23,0x22,0x35, + 0x34,0x37,0x36,0x36,0x33,0x33,0x32,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x0,0x33,0x32,0x17,0x16,0x15,0x14, + 0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x2,0x16,0x7,0x3,0x33,0x32,0x15,0x14,0x6,0x23,0x23,0x7,0x6,0x6,0x23,0x22,0x35,0x34,0x37, + 0x37,0x21,0x22,0x26,0x35,0x34,0x36,0x37,0x1,0x36,0x36,0x33,0x1,0x33,0x13,0x2,0x25,0x74,0x41,0x3b,0x2c,0x2f,0x45,0x87,0x60,0x40,0x77,0x30,0x10,0xb, + 0x14,0x16,0x9,0x8,0x2c,0x61,0x29,0x53,0x5e,0x48,0x42,0x2c,0x1d,0x2,0x4,0x15,0x15,0x20,0xa2,0x3e,0x35,0x59,0x63,0x8,0x6,0x19,0xc,0x3,0x1a,0x6c, + 0x7c,0x2,0xaa,0x9,0x19,0xf,0x8,0x13,0xfc,0x7,0x7,0x9,0x19,0xf,0x9,0x14,0x3,0xf9,0x2e,0x29,0x4,0x42,0x5c,0x22,0x1a,0x1a,0x5c,0x1b,0x4,0x1d, + 0x1e,0x33,0x1,0x1b,0xfe,0xc6,0x11,0x13,0xb,0xd,0x1,0x7f,0x13,0x22,0x15,0xfe,0xb7,0xd8,0x35,0x5,0x72,0x60,0x52,0x39,0x5a,0x1b,0x12,0x45,0x30,0x46, + 0x6c,0x3c,0x1d,0x1b,0xa,0x12,0xe,0x16,0x24,0x4,0x15,0x18,0x41,0x3a,0x2d,0x26,0x23,0x5,0xe,0x18,0x1a,0x74,0x29,0x2b,0x2a,0x3,0x29,0xc,0x9,0x1d, + 0xc,0x32,0xfd,0xe4,0x1c,0xd,0x11,0x19,0xa,0xfd,0xcf,0x4,0x1c,0xf,0xf,0x18,0xb,0x2,0x31,0xfe,0x9d,0x1a,0x14,0xfe,0x8b,0x22,0x22,0x25,0x99,0x14, + 0x14,0x1f,0x6,0x3,0x99,0x18,0x17,0x19,0x18,0xe,0x1,0x7a,0x13,0x11,0xfe,0x5d,0x1,0xa,0x0,0x0,0x0,0x1,0x1,0x53,0x1,0xe3,0x3,0xd0,0x5,0x36, + 0x0,0x24,0x0,0x6,0xb3,0xb,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x7,0x3,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36, + 0x33,0x33,0x13,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x36,0x37,0x25,0x36,0x33,0x3,0x4c,0x13,0x1,0x79,0xc2,0x16,0x13,0x2,0x9,0x33,0xfd,0xea, + 0x16,0x13,0x2,0x9,0x33,0xcd,0x65,0xb8,0x11,0x8,0xe,0x12,0x5,0x4,0x15,0x19,0x1,0x2b,0xd,0xc,0x5,0x36,0x11,0x10,0x9,0xfd,0x54,0x15,0x14,0x6, + 0x10,0x3e,0x15,0x14,0x6,0x10,0x3e,0x2,0x3b,0x39,0x5,0x15,0x17,0xf,0xe,0x13,0x17,0x7,0x5b,0x4,0x0,0x1,0x1,0x38,0x1,0xe3,0x4,0x2,0x5,0x36, + 0x0,0x29,0x0,0x6,0xb3,0xe,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x6,0x7,0x5,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x35,0x34, + 0x37,0x1,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x3,0x7b,0x87,0x61,0x6f,0xfe,0xee,0x1, + 0x78,0x15,0x15,0x1,0x4,0x1b,0x18,0xfd,0xd4,0x26,0x2e,0x1,0x7d,0x4d,0x43,0x45,0x41,0x34,0x7b,0x36,0xc,0x8,0x1b,0x11,0x9,0x18,0x44,0xa1,0x49,0x5, + 0x36,0x77,0x68,0x57,0x8a,0x50,0xc6,0x15,0x17,0xb,0x7,0x21,0x1e,0x2e,0x3a,0x21,0x1,0x18,0x38,0x58,0x37,0x31,0x39,0x1e,0x18,0x5,0x2a,0x17,0xd,0x17, + 0xd,0x24,0x26,0x0,0x0,0x0,0x0,0x1,0x1,0x4c,0x1,0xd1,0x4,0x2,0x5,0x36,0x0,0x39,0x0,0x6,0xb3,0xb,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14, + 0x6,0x7,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x23, + 0x22,0x35,0x34,0x37,0x36,0x33,0x33,0x32,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x3,0x78,0x8a,0x4e,0x46,0x34, + 0x39,0x53,0xa1,0x73,0x4c,0x90,0x39,0x13,0xd,0x18,0x1a,0x8,0xc,0x35,0x74,0x31,0x64,0x70,0x55,0x50,0x34,0x23,0x2,0xa,0x2d,0x27,0xc2,0x4b,0x3f,0x6b, + 0x76,0x8,0x9,0x1f,0xd,0x4,0x1f,0x80,0x96,0x5,0x36,0x72,0x63,0x44,0x6b,0x21,0x16,0x53,0x39,0x54,0x82,0x48,0x23,0x20,0xb,0x17,0x12,0x19,0x2c,0x5, + 0x19,0x1d,0x4d,0x46,0x36,0x2d,0x2a,0x7,0x10,0x3c,0x8b,0x31,0x34,0x32,0x4,0x31,0xc,0xe,0x21,0xf,0x3c,0x0,0x0,0x0,0x0,0x2,0x1,0x43,0x1,0xdb, + 0x4,0x1a,0x5,0x36,0x0,0x1f,0x0,0x22,0x0,0x8,0xb5,0x22,0x20,0xf,0x0,0x2,0x30,0x2b,0x0,0x16,0x7,0x3,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x23, + 0x23,0x7,0x6,0x6,0x23,0x22,0x35,0x34,0x37,0x37,0x21,0x22,0x35,0x34,0x36,0x37,0x1,0x36,0x36,0x33,0x1,0x21,0x13,0x3,0xa6,0x31,0x4,0x4f,0x6d,0x16, + 0x13,0x2,0x9,0x33,0x6e,0x20,0x5,0x23,0x24,0x3d,0x1,0x21,0xfe,0x88,0x2c,0xe,0xf,0x1,0xcb,0x17,0x28,0x1a,0xfe,0x75,0x1,0x3,0x3f,0x5,0x36,0x20, + 0x17,0xfe,0x41,0x15,0x14,0x6,0x10,0x3e,0xb8,0x18,0x18,0x25,0x7,0x4,0xb8,0x38,0x1e,0x1d,0x10,0x1,0xc5,0x16,0x15,0xfe,0xa,0x1,0x3f,0x0,0x0,0x2, + 0x2,0xcd,0xff,0xf6,0x4,0x6d,0x3,0xa2,0x0,0x11,0x0,0x23,0x0,0x8,0xb5,0x19,0x12,0x7,0x0,0x2,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6, + 0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x2,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x4,0x2b, + 0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x2c,0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x3,0xa2,0x19, + 0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0xfd,0x8a,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x0, + 0x0,0x0,0xff,0xff,0x2,0x35,0xfe,0xda,0x4,0x4,0x1,0x26,0x0,0x3,0x1,0x27,0x1,0x2c,0x0,0x0,0x0,0x0,0xff,0xff,0x2,0xcd,0xff,0xf6,0x3,0xfe, + 0x1,0x2c,0x0,0x3,0x1,0x2c,0x1,0x2c,0x0,0x0,0x0,0x0,0x0,0x2,0x2,0x5d,0xfe,0xda,0x4,0x6d,0x3,0xa2,0x0,0x11,0x0,0x22,0x0,0x8,0xb5,0x18, + 0x12,0x7,0x0,0x2,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x12,0x16,0x15,0x14,0x7,0x1, + 0x6,0x23,0x22,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x4,0x2b,0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x32,0x12,0xb,0xfe, + 0xdc,0x19,0x48,0x3f,0x5,0xad,0x7,0x1f,0x15,0xc0,0x3,0xa2,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0xfd,0x84,0x10,0xe, + 0xe,0x13,0xfe,0x1c,0x29,0x28,0x9,0x11,0x1,0xe2,0x13,0x15,0xff,0xff,0xfe,0x1d,0xff,0xf6,0x6,0x56,0x1,0x2c,0x0,0x23,0x1,0x2c,0xfc,0x7c,0x0,0x0, + 0x0,0x22,0x1,0x2c,0x0,0x0,0x0,0x3,0x1,0x2c,0x3,0x84,0x0,0x0,0xff,0xff,0x2,0xe9,0xff,0xf6,0xb,0x22,0x1,0x2c,0x0,0x23,0x1,0x2c,0x1,0x48, + 0x0,0x0,0x0,0x23,0x1,0x2c,0x4,0xcc,0x0,0x0,0x0,0x3,0x1,0x2c,0x8,0x50,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0xf3,0xff,0xf3,0x6,0x1f,0x0,0xe7, + 0x0,0xf,0x0,0x1f,0x0,0x2f,0x0,0xa,0xb7,0x25,0x20,0x15,0x10,0x5,0x0,0x3,0x30,0x2b,0x24,0x16,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37, + 0x37,0x36,0x36,0x33,0x20,0x16,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x20,0x16,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35, + 0x34,0x37,0x37,0x36,0x36,0x33,0x1,0xb4,0x33,0x4,0x1a,0x5,0x30,0x38,0x35,0x34,0x1,0x1a,0x5,0x30,0x38,0x2,0x55,0x33,0x4,0x1a,0x5,0x30,0x38,0x35, + 0x34,0x1,0x1a,0x5,0x30,0x38,0x2,0x55,0x33,0x4,0x1a,0x5,0x30,0x38,0x35,0x34,0x1,0x1a,0x5,0x30,0x38,0xe7,0x17,0x1a,0x91,0x1b,0x17,0x14,0x16,0x5, + 0x3,0x91,0x1b,0x16,0x17,0x1a,0x91,0x1b,0x17,0x14,0x16,0x5,0x3,0x91,0x1b,0x16,0x17,0x1a,0x91,0x1b,0x17,0x14,0x16,0x5,0x3,0x91,0x1b,0x16,0x0,0x0, + 0x0,0x3,0xfd,0xfb,0xff,0xf3,0x4,0x3f,0x0,0xe7,0x0,0xf,0x0,0x1f,0x0,0x2f,0x0,0xa,0xb7,0x25,0x20,0x15,0x10,0x5,0x0,0x3,0x30,0x2b,0x24,0x16, + 0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x20,0x16,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33, + 0x20,0x16,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0xfe,0xbc,0x33,0x4,0x1a,0x5,0x30,0x38,0x35,0x34,0x1,0x1a,0x5,0x30, + 0x38,0x2,0xe1,0x33,0x4,0x1a,0x5,0x30,0x38,0x35,0x34,0x1,0x1a,0x5,0x30,0x38,0x2,0xe1,0x33,0x4,0x1a,0x5,0x30,0x38,0x35,0x34,0x1,0x1a,0x5,0x30, + 0x38,0xe7,0x17,0x1a,0x91,0x1b,0x17,0x14,0x16,0x5,0x3,0x91,0x1b,0x16,0x17,0x1a,0x91,0x1b,0x17,0x14,0x16,0x5,0x3,0x91,0x1b,0x16,0x17,0x1a,0x91,0x1b, + 0x17,0x14,0x16,0x5,0x3,0x91,0x1b,0x16,0x0,0x0,0xff,0xff,0x2,0xe9,0xff,0xf6,0xc,0x4e,0x1,0x2c,0x0,0x23,0x1,0x2c,0x1,0x48,0x0,0x0,0x0,0x23, + 0x1,0x2c,0x5,0x62,0x0,0x0,0x0,0x3,0x1,0x2c,0x9,0x7c,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0xa7,0x0,0x96,0x4,0x97,0x4,0x67,0x0,0x32,0x0,0x60, + 0x4b,0xb0,0x31,0x50,0x58,0x40,0xe,0x29,0x1,0x2,0x3,0x2c,0x22,0x18,0xe,0x3,0x5,0x0,0x2,0x2,0x4a,0x1b,0x40,0xe,0x29,0x1,0x2,0x3,0x2c,0x22, + 0x18,0xe,0x3,0x5,0x0,0x4,0x2,0x4a,0x59,0x4b,0xb0,0x31,0x50,0x58,0x40,0x10,0x0,0x3,0x2,0x3,0x72,0x4,0x1,0x2,0x0,0x2,0x72,0x1,0x1,0x0, + 0x0,0x69,0x1b,0x40,0x14,0x0,0x3,0x2,0x3,0x72,0x0,0x2,0x4,0x2,0x72,0x0,0x4,0x0,0x4,0x72,0x1,0x1,0x0,0x0,0x69,0x59,0xb7,0x27,0x25,0x2c, + 0x25,0x29,0x5,0x7,0x19,0x2b,0x0,0x6,0x7,0x5,0x13,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x3,0x3,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37, + 0x1,0x25,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x5,0x13,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x25,0x36,0x33,0x32,0x16,0x15,0x4,0x97,0x29, + 0x25,0xfe,0x87,0xc7,0x12,0x30,0x1b,0x19,0x15,0x21,0xa,0x87,0xed,0x20,0x2c,0x1c,0x1b,0x22,0x21,0x1,0x2c,0xfe,0xa4,0x36,0xd,0x1c,0x2e,0x14,0x14,0x1, + 0x40,0x17,0x2,0x36,0x2e,0x25,0x29,0x5,0x69,0x1,0x65,0x15,0x13,0x20,0x27,0x2,0xba,0x2e,0x8,0x48,0xfe,0xdf,0x19,0x19,0x26,0x1c,0x11,0x1c,0x18,0x1, + 0x3d,0xfe,0xc3,0x2b,0x15,0x1d,0x23,0x22,0x1e,0x1,0x11,0x50,0xc,0x2e,0x18,0x1b,0x3d,0xa,0x99,0x1,0x71,0x2a,0x30,0x20,0x1d,0xc,0x11,0xfe,0x89,0x96, + 0x9,0x2d,0x2a,0x0,0x0,0x0,0x0,0x1,0x1,0x72,0xfe,0x9d,0x3,0x84,0x5,0x72,0x0,0x11,0x0,0x36,0xb6,0xc,0x3,0x2,0x0,0x1,0x1,0x4a,0x4b,0xb0, + 0x15,0x50,0x58,0x40,0xc,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x13,0x0,0x4c,0x1b,0x40,0xa,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69, + 0x59,0x40,0xa,0x0,0x0,0x0,0x11,0x0,0x10,0x27,0x3,0x7,0x15,0x2b,0x0,0x16,0x17,0x1,0x16,0x15,0x14,0x6,0x23,0x22,0x26,0x27,0x1,0x26,0x35,0x34, + 0x36,0x33,0x1,0xdc,0x1f,0x4,0x1,0x84,0x1,0x36,0x20,0x15,0x1e,0x4,0xfe,0x7c,0x1,0x35,0x20,0x5,0x72,0xf,0xf,0xf9,0x89,0x3,0x6,0x18,0x1f,0xf, + 0xf,0x6,0x77,0x3,0x6,0x18,0x1f,0x0,0x0,0x0,0xff,0xff,0x1,0xee,0x1,0xa9,0x3,0x1f,0x2,0xdf,0x1,0x7,0x1,0x2c,0x0,0x4d,0x1,0xb3,0x0,0x9, + 0xb1,0x0,0x1,0xb8,0x1,0xb3,0xb0,0x33,0x2b,0x0,0x0,0x0,0x0,0x1,0x1,0x87,0x1,0x63,0x3,0x8e,0x3,0x55,0x0,0x11,0x0,0x26,0x40,0x23,0xb,0x2, + 0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x57,0x2,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x0,0x0,0x0,0x11,0x0,0x10,0x27, + 0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x3,0x20,0x6e,0x1,0x35,0x9,0x6d,0x79, + 0x74,0x6e,0x1,0x35,0x9,0x6d,0x79,0x3,0x55,0x28,0x2c,0x9,0x5,0xfe,0xd2,0x35,0x2d,0x28,0x2c,0x9,0x5,0x1,0x2e,0x35,0x2d,0x0,0x0,0x2,0x1,0xa1, + 0xff,0xf6,0x3,0x41,0x3,0xa2,0x0,0x11,0x0,0x23,0x0,0x38,0x40,0x35,0xb,0x2,0x2,0x0,0x1,0x1d,0x14,0x2,0x2,0x3,0x2,0x4a,0x0,0x0,0x0,0x1, + 0x5b,0x4,0x1,0x1,0x1,0x11,0x4b,0x5,0x1,0x3,0x3,0x2,0x5b,0x0,0x2,0x2,0xf,0x2,0x4c,0x12,0x12,0x0,0x0,0x12,0x23,0x12,0x22,0x1b,0x19,0x0, + 0x11,0x0,0x10,0x27,0x6,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x2,0x16,0x15,0x14, + 0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x2,0xff,0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x2c, + 0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x3,0xa2,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0xfd, + 0x8a,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x0,0x0,0x0,0x0,0x1,0x1,0x9,0xfe,0xda,0x2,0xd8,0x1,0x26,0x0,0x10, + 0x0,0x17,0x40,0x14,0x9,0x1,0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x26,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7, + 0x1,0x6,0x23,0x22,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x2,0xc6,0x12,0xb,0xfe,0xdc,0x19,0x48,0x3f,0x5,0xad,0x7,0x1f,0x15,0xc0,0x1,0x26,0x10, + 0xe,0xe,0x13,0xfe,0x1c,0x29,0x28,0x9,0x11,0x1,0xe2,0x13,0x15,0x0,0x0,0x0,0x0,0x3,0x0,0x2e,0xff,0xf6,0x4,0x39,0x0,0xe6,0x0,0x11,0x0,0x23, + 0x0,0x35,0x0,0x3a,0x40,0x37,0x2f,0x26,0x1d,0x14,0xb,0x2,0x6,0x0,0x1,0x1,0x4a,0x8,0x5,0x7,0x3,0x6,0x5,0x1,0x1,0x0,0x5b,0x4,0x2,0x2, + 0x0,0x0,0xf,0x0,0x4c,0x24,0x24,0x12,0x12,0x0,0x0,0x24,0x35,0x24,0x34,0x2d,0x2b,0x12,0x23,0x12,0x22,0x1b,0x19,0x0,0x11,0x0,0x10,0x27,0x9,0x7, + 0x15,0x2b,0x36,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x20,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22, + 0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x20,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0xe7,0x32,0x1,0x17, + 0x5,0x31,0x37,0x34,0x32,0x1,0x17,0x5,0x31,0x37,0x1,0xc4,0x32,0x1,0x17,0x5,0x31,0x37,0x34,0x32,0x1,0x17,0x5,0x31,0x37,0x1,0xc4,0x32,0x1,0x17, + 0x5,0x31,0x37,0x34,0x32,0x1,0x17,0x5,0x31,0x37,0xe6,0x15,0x17,0x6,0x3,0x86,0x1d,0x18,0x15,0x17,0x6,0x3,0x86,0x1d,0x18,0x15,0x17,0x6,0x3,0x86, + 0x1d,0x18,0x15,0x17,0x6,0x3,0x86,0x1d,0x18,0x15,0x17,0x6,0x3,0x86,0x1d,0x18,0x15,0x17,0x6,0x3,0x86,0x1d,0x18,0x0,0x0,0x0,0x0,0x2,0x1,0xb1, + 0xff,0xf6,0x3,0x5e,0x4,0xf5,0x0,0xe,0x0,0x20,0x0,0x37,0x40,0x34,0x1,0x1,0x0,0x1,0x1a,0x11,0x2,0x2,0x3,0x2,0x4a,0x4,0x1,0x1,0x0,0x1, + 0x72,0x0,0x0,0x3,0x0,0x72,0x5,0x1,0x3,0x3,0x2,0x5b,0x0,0x2,0x2,0xf,0x2,0x4c,0xf,0xf,0x0,0x0,0xf,0x20,0xf,0x1f,0x18,0x16,0x0,0xe, + 0x0,0xc,0x26,0x6,0x7,0x15,0x2b,0x0,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x37,0x13,0x36,0x33,0x33,0x2,0x16,0x15,0x14,0x7,0x7,0x6,0x6, + 0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x3,0x5e,0x3,0xae,0x5,0x22,0x1a,0x1a,0x1a,0x2,0x4d,0x4,0x2e,0x82,0xaf,0x3c,0x1,0x1b,0x6,0x39, + 0x41,0x3e,0x3d,0x1,0x1b,0x6,0x3a,0x41,0x4,0xf5,0x1d,0x9,0xc,0xfd,0x3d,0x17,0x19,0x19,0x17,0x2,0xc3,0x32,0xfc,0x19,0x19,0x1b,0x7,0x4,0x9a,0x22, + 0x1d,0x19,0x1c,0x6,0x4,0x9a,0x22,0x1d,0x0,0x0,0x0,0x2,0x1,0x6e,0xfe,0xa7,0x3,0x1b,0x3,0xa6,0x0,0x11,0x0,0x20,0x0,0x39,0x40,0x36,0xb,0x2, + 0x2,0x1,0x0,0x13,0x1,0x3,0x2,0x2,0x4a,0x0,0x2,0x1,0x3,0x1,0x2,0x3,0x70,0x5,0x1,0x3,0x3,0x71,0x4,0x1,0x1,0x1,0x0,0x5b,0x0,0x0, + 0x0,0x11,0x1,0x4c,0x12,0x12,0x0,0x0,0x12,0x20,0x12,0x1e,0x1a,0x18,0x0,0x11,0x0,0x10,0x27,0x6,0x7,0x15,0x2b,0x0,0x26,0x35,0x34,0x37,0x37,0x36, + 0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x0,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x32,0x16,0x7,0x3,0x6,0x23,0x23,0x2,0x40,0x3c,0x1, + 0x1b,0x6,0x39,0x41,0x3e,0x3d,0x1,0x1b,0x6,0x3a,0x41,0xfe,0xf0,0x3,0xae,0x5,0x22,0x1a,0x1a,0x1a,0x2,0x4d,0x4,0x2e,0x82,0x2,0x8e,0x19,0x1b,0x7, + 0x4,0x9a,0x22,0x1d,0x19,0x1c,0x6,0x4,0x9a,0x22,0x1d,0xfc,0x19,0x1d,0x9,0xc,0x2,0xc3,0x17,0x19,0x19,0x17,0xfd,0x3d,0x32,0x0,0x0,0x0,0x0,0x2, + 0x0,0x3b,0xff,0xea,0x4,0xd9,0x4,0xb9,0x0,0x4f,0x0,0x53,0x0,0x5d,0x40,0x5a,0x4b,0x41,0x2,0x9,0xa,0x35,0x2,0x2,0x0,0x9,0x2a,0xd,0x2,0x2, + 0x1,0x23,0x19,0x2,0x3,0x2,0x4,0x4a,0x10,0xd,0xb,0x3,0x9,0xe,0x8,0x2,0x0,0x1,0x9,0x0,0x62,0xf,0x7,0x2,0x1,0x6,0x4,0x2,0x2,0x3, + 0x1,0x2,0x61,0xc,0x1,0xa,0xa,0x16,0x4b,0x5,0x1,0x3,0x3,0x17,0x3,0x4c,0x0,0x0,0x53,0x52,0x51,0x50,0x0,0x4f,0x0,0x4e,0x49,0x47,0x45,0x44, + 0x3f,0x3d,0x3b,0x39,0x21,0x26,0x25,0x22,0x15,0x22,0x26,0x21,0x26,0x11,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x7,0x33,0x32,0x16, + 0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35, + 0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x3,0x33,0x13,0x36,0x33, + 0x32,0x16,0x15,0x14,0x7,0x3,0x33,0x5,0x23,0x7,0x33,0x4,0xbf,0x1a,0x3,0x7,0x23,0x22,0xc0,0x69,0xb8,0x1b,0x1a,0x3,0x7,0x22,0x22,0xdc,0x8a,0xe, + 0x2e,0x1d,0x29,0x4,0x7b,0xfd,0x8a,0xe,0x2e,0x1d,0x29,0x4,0x7b,0x9d,0x1c,0x19,0x2,0x7,0x23,0x22,0xc2,0x69,0xba,0x1b,0x1a,0x3,0x7,0x23,0x22,0xde, + 0x85,0xe,0x2e,0x1d,0x29,0x4,0x77,0xfe,0x85,0xe,0x2e,0x1d,0x29,0x4,0x77,0x9c,0xfe,0x9a,0xfe,0x69,0xfe,0x3,0x61,0x16,0x18,0xb,0xf,0x27,0x21,0xf5, + 0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0xbf,0x21,0x1a,0x16,0xa,0x9,0x1,0x1f,0xfe,0xbf,0x21,0x1a,0x16,0xa,0x9,0x1,0x1f,0x16,0x19,0xf,0xa,0x27,0x21, + 0xf5,0x16,0x18,0xb,0xf,0x27,0x21,0x1,0x37,0x21,0x1a,0x16,0xa,0x9,0xfe,0xeb,0x1,0x37,0x21,0x1a,0x16,0xa,0x9,0xfe,0xeb,0x90,0xf5,0x0,0x0,0x0, + 0x0,0x1,0x1,0xa1,0xff,0xf6,0x2,0xd2,0x1,0x2c,0x0,0x11,0x0,0x20,0x40,0x1d,0xb,0x2,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x1,0x0,0x5b,0x0, + 0x0,0x0,0xf,0x0,0x4c,0x0,0x0,0x0,0x11,0x0,0x10,0x27,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37, + 0x37,0x36,0x36,0x33,0x2,0x90,0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x1,0x2c,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c, + 0x7,0x3,0xb8,0x22,0x1d,0x0,0x0,0x2,0x1,0x82,0xff,0xf6,0x4,0x30,0x4,0xf5,0x0,0x24,0x0,0x36,0x0,0x42,0x40,0x3f,0x30,0x27,0x2,0x4,0x5,0x1, + 0x4a,0x0,0x2,0x1,0x0,0x1,0x2,0x0,0x70,0x0,0x0,0x5,0x1,0x0,0x5,0x6e,0x6,0x1,0x3,0x0,0x1,0x2,0x3,0x1,0x63,0x7,0x1,0x5,0x5,0x4, + 0x5b,0x0,0x4,0x4,0xf,0x4,0x4c,0x25,0x25,0x0,0x0,0x25,0x36,0x25,0x35,0x2e,0x2c,0x0,0x24,0x0,0x23,0x22,0x2c,0x29,0x8,0x7,0x17,0x2b,0x0,0x16, + 0x16,0x15,0x14,0x6,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x37,0x37,0x36,0x37,0x37,0x3e,0x2,0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35, + 0x34,0x37,0x36,0x33,0x2,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x3,0x5c,0x8b,0x49,0xbd,0xc1,0x26,0x5, + 0x2a,0x1f,0x1f,0x20,0x3,0x1c,0x4,0x23,0x4a,0x5c,0x6e,0x38,0x55,0x51,0x7d,0x94,0x12,0xd,0x1d,0x12,0xa,0x20,0xa5,0xb3,0x9d,0x36,0x1,0x14,0x6,0x36, + 0x3c,0x38,0x37,0x1,0x14,0x6,0x37,0x3c,0x4,0xf5,0x43,0x7b,0x52,0x8b,0xb4,0x48,0xa6,0x17,0x1c,0x1c,0x17,0xe1,0x26,0xd,0x1c,0x23,0x41,0x56,0x3c,0x3d, + 0x46,0x41,0x8,0x2b,0x18,0x12,0x21,0x11,0x56,0xfb,0xf1,0x18,0x1b,0x8,0x4,0x72,0x22,0x1d,0x19,0x1b,0x7,0x4,0x72,0x22,0x1d,0x0,0x0,0x0,0x0,0x2, + 0x0,0x9c,0xfe,0xa7,0x3,0x4a,0x3,0xa6,0x0,0x11,0x0,0x36,0x0,0x43,0x40,0x40,0xb,0x2,0x2,0x1,0x0,0x1,0x4a,0x0,0x2,0x1,0x4,0x1,0x2,0x4, + 0x70,0x0,0x4,0x3,0x1,0x4,0x3,0x6e,0x0,0x3,0x7,0x1,0x5,0x3,0x5,0x60,0x6,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x0,0x11,0x1,0x4c,0x12,0x12, + 0x0,0x0,0x12,0x36,0x12,0x35,0x2f,0x2d,0x2b,0x29,0x1d,0x1b,0x0,0x11,0x0,0x10,0x27,0x8,0x7,0x15,0x2b,0x0,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33, + 0x32,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x0,0x26,0x26,0x35,0x34,0x36,0x37,0x37,0x36,0x36,0x33,0x32,0x16,0x7,0x7,0x6,0x7,0x7,0xe,0x2,0x15, + 0x14,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x2,0x6f,0x36,0x1,0x14,0x6,0x36,0x3c,0x38,0x37,0x1,0x14,0x6,0x37,0x3c, + 0xfe,0xc9,0x8b,0x49,0xbd,0xc1,0x26,0x5,0x2a,0x1f,0x1f,0x20,0x3,0x1c,0x4,0x23,0x4a,0x5c,0x6e,0x38,0x55,0x51,0x7d,0x94,0x12,0xd,0x1d,0x12,0xa,0x20, + 0xa5,0xb3,0x2,0xb6,0x18,0x1b,0x8,0x4,0x72,0x22,0x1d,0x19,0x1b,0x7,0x4,0x72,0x22,0x1d,0xfb,0xf1,0x43,0x7b,0x52,0x8b,0xb4,0x48,0xa6,0x17,0x1c,0x1c, + 0x17,0xe1,0x26,0xd,0x1c,0x23,0x41,0x56,0x3c,0x3d,0x46,0x41,0x8,0x2b,0x18,0x12,0x21,0x11,0x56,0x0,0xff,0xff,0x1,0x7c,0x2,0xcb,0x4,0x5b,0x4,0xf5, + 0x0,0x23,0x1,0x30,0xff,0x1a,0x0,0x0,0x0,0x3,0x1,0x30,0x0,0xe6,0x0,0x0,0x0,0x0,0x0,0x1,0x2,0x62,0x2,0xcb,0x3,0x75,0x4,0xf5,0x0,0xe, + 0x0,0x26,0x40,0x23,0xa,0x1,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x5b,0x0,0x0,0x1,0x0,0x4f,0x0, + 0x0,0x0,0xe,0x0,0xc,0x26,0x3,0x7,0x15,0x2b,0x0,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x37,0x13,0x36,0x33,0x33,0x3,0x75,0x3,0x86,0x8, + 0x28,0x1e,0x1d,0x1f,0x2,0x18,0x3,0x2f,0xa4,0x4,0xf5,0x1d,0x9,0xc,0xfe,0x3e,0x1a,0x1c,0x1c,0x1a,0x1,0xc2,0x32,0x0,0x0,0x2,0x1,0x31,0xfe,0xda, + 0x3,0x41,0x3,0xa2,0x0,0x11,0x0,0x22,0x0,0x34,0x40,0x31,0xb,0x2,0x2,0x0,0x1,0x1b,0x1,0x2,0x3,0x2,0x4a,0x0,0x3,0x0,0x2,0x0,0x3,0x2, + 0x70,0x0,0x2,0x2,0x71,0x0,0x0,0x0,0x1,0x5b,0x4,0x1,0x1,0x1,0x11,0x0,0x4c,0x0,0x0,0x22,0x20,0x1a,0x18,0x0,0x11,0x0,0x10,0x27,0x5,0x7, + 0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x36,0x33,0x12,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x35, + 0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x2,0xff,0x42,0x1,0x21,0x6,0x3e,0x46,0x43,0x42,0x1,0x21,0x6,0x3e,0x46,0x32,0x12,0xb,0xfe,0xdc,0x19,0x48,0x3f, + 0x5,0xad,0x7,0x1f,0x15,0xc0,0x3,0xa2,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0x19,0x1c,0x7,0x3,0xb8,0x22,0x1d,0xfd,0x84,0x10,0xe,0xe,0x13,0xfe,0x1c, + 0x29,0x28,0x9,0x11,0x1,0xe2,0x13,0x15,0x0,0x1,0x0,0x52,0xfe,0x9d,0x4,0xa5,0x5,0x72,0x0,0xf,0x0,0x36,0xb6,0xa,0x2,0x2,0x0,0x1,0x1,0x4a, + 0x4b,0xb0,0x15,0x50,0x58,0x40,0xc,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x13,0x0,0x4c,0x1b,0x40,0xa,0x2,0x1,0x1,0x0,0x1,0x72,0x0,0x0, + 0x0,0x69,0x59,0x40,0xa,0x0,0x0,0x0,0xf,0x0,0xe,0x26,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x1, + 0x36,0x33,0x4,0x7a,0x2b,0x7,0xfc,0x47,0x12,0x32,0x24,0x2b,0x7,0x3,0xb9,0x12,0x32,0x5,0x72,0x1f,0x17,0xc,0xd,0xf9,0x9a,0x20,0x1f,0x17,0xc,0xd, + 0x6,0x66,0x20,0x0,0x0,0x1,0x0,0x1,0xfe,0x77,0x4,0x46,0xff,0x7,0x0,0x11,0x0,0x2e,0xb1,0x6,0x64,0x44,0x40,0x23,0xb,0x2,0x2,0x0,0x1,0x1, + 0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0x11,0x0,0xf,0x36,0x3,0x7,0x15,0x2b, + 0xb1,0x6,0x0,0x44,0x4,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x2c,0x1a,0x3,0x7,0x22,0x22,0xfc, + 0x3e,0x1c,0x19,0x2,0x8,0x22,0x22,0x3,0xc2,0xf9,0x15,0x18,0xc,0xf,0x27,0x21,0x16,0x19,0xf,0xa,0x27,0x21,0x0,0x1,0x0,0xc8,0xfe,0xb3,0x4,0x75, + 0x5,0x5c,0x0,0x3b,0x0,0xe5,0x40,0xf,0x2,0x1,0x0,0x5,0x30,0xf,0x2,0x3,0x4,0x1d,0x1,0x2,0x1,0x3,0x4a,0x4b,0xb0,0xc,0x50,0x58,0x40,0x21, + 0x6,0x1,0x5,0x0,0x0,0x4,0x5,0x0,0x63,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x2,0x2,0x1,0x57,0x0,0x1,0x1,0x2,0x5b,0x0,0x2, + 0x1,0x2,0x4f,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x1b,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x0,0x2,0x1,0x2,0x5f,0x0,0x0,0x0,0x5, + 0x5b,0x6,0x1,0x5,0x5,0x10,0x0,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x21,0x6,0x1,0x5,0x0,0x0,0x4,0x5,0x0,0x63,0x0,0x4,0x0,0x3,0x1, + 0x4,0x3,0x63,0x0,0x1,0x2,0x2,0x1,0x57,0x0,0x1,0x1,0x2,0x5b,0x0,0x2,0x1,0x2,0x4f,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x1b,0x0,0x4,0x0, + 0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x0,0x2,0x1,0x2,0x5f,0x0,0x0,0x0,0x5,0x5b,0x6,0x1,0x5,0x5,0x10,0x0,0x4c,0x1b,0x40,0x21,0x6,0x1,0x5, + 0x0,0x0,0x4,0x5,0x0,0x63,0x0,0x4,0x0,0x3,0x1,0x4,0x3,0x63,0x0,0x1,0x2,0x2,0x1,0x57,0x0,0x1,0x1,0x2,0x5b,0x0,0x2,0x1,0x2,0x4f, + 0x59,0x59,0x59,0x59,0x40,0x12,0x0,0x0,0x0,0x3b,0x0,0x3a,0x36,0x34,0x2e,0x2c,0x23,0x21,0x1b,0x19,0x26,0x7,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7, + 0x6,0x6,0x23,0x22,0x6,0x6,0x7,0x7,0x6,0x6,0x7,0x7,0x16,0x15,0x14,0x7,0x7,0x6,0x15,0x14,0x16,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23, + 0x22,0x26,0x35,0x34,0x37,0x37,0x36,0x35,0x34,0x26,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x20,0x13,0x37,0x36,0x36,0x33,0x4,0x5a,0x1b,0x2,0x5, + 0x22,0x22,0x66,0x80,0x46,0xe,0xa,0x12,0x8a,0x87,0x1,0xbd,0xa,0x18,0xc,0x76,0x7b,0x1c,0x18,0x2,0x5,0x23,0x22,0xb0,0xbf,0x10,0x15,0xc,0x70,0x7d, + 0x1d,0x1a,0x2,0x5,0x23,0x22,0x1,0x1e,0x22,0xb,0x19,0xef,0xd6,0x5,0x5c,0x18,0x1b,0x5,0x10,0x27,0x21,0x3b,0x7a,0x64,0x48,0x82,0xa0,0x27,0xa,0x46, + 0xa9,0x24,0x30,0x70,0x37,0x2c,0x61,0x5e,0x16,0x1a,0x6,0x12,0x27,0x21,0x9f,0x98,0x3e,0x46,0x5d,0x35,0x29,0x57,0x55,0x17,0x1b,0x6,0x10,0x27,0x21,0x1, + 0x10,0x5a,0xce,0xbf,0x0,0x0,0x0,0x1,0x0,0x6c,0xfe,0xb3,0x4,0x20,0x5,0x5c,0x0,0x3c,0x0,0xe5,0x40,0xf,0x1d,0x1,0x1,0x2,0x30,0xf,0x2,0x4, + 0x3,0x2,0x1,0x5,0x0,0x3,0x4a,0x4b,0xb0,0xc,0x50,0x58,0x40,0x21,0x0,0x2,0x0,0x1,0x3,0x2,0x1,0x63,0x0,0x3,0x0,0x4,0x0,0x3,0x4,0x63, + 0x0,0x0,0x5,0x5,0x0,0x57,0x0,0x0,0x0,0x5,0x5b,0x6,0x1,0x5,0x0,0x5,0x4f,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x1b,0x0,0x3,0x0,0x4,0x0, + 0x3,0x4,0x63,0x0,0x0,0x6,0x1,0x5,0x0,0x5,0x5f,0x0,0x1,0x1,0x2,0x5b,0x0,0x2,0x2,0x10,0x1,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x21, + 0x0,0x2,0x0,0x1,0x3,0x2,0x1,0x63,0x0,0x3,0x0,0x4,0x0,0x3,0x4,0x63,0x0,0x0,0x5,0x5,0x0,0x57,0x0,0x0,0x0,0x5,0x5b,0x6,0x1,0x5, + 0x0,0x5,0x4f,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x1b,0x0,0x3,0x0,0x4,0x0,0x3,0x4,0x63,0x0,0x0,0x6,0x1,0x5,0x0,0x5,0x5f,0x0,0x1,0x1, + 0x2,0x5b,0x0,0x2,0x2,0x10,0x1,0x4c,0x1b,0x40,0x21,0x0,0x2,0x0,0x1,0x3,0x2,0x1,0x63,0x0,0x3,0x0,0x4,0x0,0x3,0x4,0x63,0x0,0x0,0x5, + 0x5,0x0,0x57,0x0,0x0,0x0,0x5,0x5b,0x6,0x1,0x5,0x0,0x5,0x4f,0x59,0x59,0x59,0x59,0x40,0x12,0x0,0x0,0x0,0x3c,0x0,0x3b,0x36,0x34,0x2e,0x2c, + 0x23,0x21,0x1b,0x19,0x26,0x7,0x7,0x15,0x2b,0x12,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x36,0x36,0x37,0x37,0x36,0x36,0x37,0x37,0x26,0x35,0x34,0x37, + 0x37,0x36,0x35,0x34,0x26,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7,0x7,0x6,0x15,0x14,0x16,0x33,0x32,0x16,0x15,0x14,0x7, + 0x6,0x6,0x23,0x22,0x6,0x7,0x7,0x6,0x6,0x23,0x87,0x1b,0x2,0x5,0x22,0x22,0x66,0x80,0x47,0xd,0x10,0x12,0x8c,0x86,0x1,0xb5,0x8,0xb,0xa,0x73, + 0x7c,0x1c,0x18,0x2,0x5,0x23,0x22,0xb2,0xba,0xd,0xa,0xa,0x6c,0x7b,0x1d,0x1a,0x2,0x5,0x23,0x22,0x93,0x9f,0x10,0x10,0x19,0xf0,0xd5,0xfe,0xb3,0x18, + 0x1b,0x5,0x10,0x27,0x21,0x3b,0x7b,0x63,0x76,0x80,0xa3,0x27,0xa,0x46,0xb2,0x22,0x2d,0x3d,0x3a,0x25,0x64,0x5f,0x16,0x1a,0x6,0x12,0x27,0x21,0xa1,0x9d, + 0x3c,0x41,0x34,0x37,0x24,0x58,0x55,0x17,0x1b,0x6,0x10,0x27,0x21,0x91,0x82,0x82,0xcd,0xc0,0x0,0x0,0x0,0x1,0x0,0xd3,0xfe,0xb3,0x4,0x8,0x5,0x5c, + 0x0,0x1d,0x0,0xb3,0x40,0xb,0x2,0x1,0x0,0x3,0x16,0xd,0x2,0x2,0x1,0x2,0x4a,0x4b,0xb0,0xc,0x50,0x58,0x40,0x19,0x4,0x1,0x3,0x0,0x0,0x1, + 0x3,0x0,0x61,0x0,0x1,0x2,0x2,0x1,0x55,0x0,0x1,0x1,0x2,0x59,0x0,0x2,0x1,0x2,0x4d,0x1b,0x4b,0xb0,0xe,0x50,0x58,0x40,0x13,0x0,0x1,0x0, + 0x2,0x1,0x2,0x5d,0x0,0x0,0x0,0x3,0x59,0x4,0x1,0x3,0x3,0x10,0x0,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x19,0x4,0x1,0x3,0x0,0x0,0x1, + 0x3,0x0,0x61,0x0,0x1,0x2,0x2,0x1,0x55,0x0,0x1,0x1,0x2,0x59,0x0,0x2,0x1,0x2,0x4d,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x13,0x0,0x1,0x0, + 0x2,0x1,0x2,0x5d,0x0,0x0,0x0,0x3,0x59,0x4,0x1,0x3,0x3,0x10,0x0,0x4c,0x1b,0x40,0x19,0x4,0x1,0x3,0x0,0x0,0x1,0x3,0x0,0x61,0x0,0x1, + 0x2,0x2,0x1,0x55,0x0,0x1,0x1,0x2,0x59,0x0,0x2,0x1,0x2,0x4d,0x59,0x59,0x59,0x59,0x40,0xc,0x0,0x0,0x0,0x1d,0x0,0x1b,0x36,0x21,0x26,0x5, + 0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x1,0x36, + 0x36,0x33,0x21,0x3,0xee,0x1a,0x3,0x7,0x23,0x22,0xfe,0xb9,0xf9,0x1,0x47,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0x62,0x1c,0x19,0x2,0x1,0x15,0x7,0x22, + 0x22,0x1,0x9e,0x5,0x5c,0x16,0x18,0xb,0xf,0x27,0x21,0xfa,0x77,0x16,0x18,0xb,0xf,0x27,0x21,0x14,0x18,0xf,0x9,0x6,0x21,0x25,0x1f,0x0,0x0,0x0, + 0x0,0x1,0x0,0xef,0xfe,0xb3,0x4,0x24,0x5,0x5c,0x0,0x1d,0x0,0xb3,0x40,0xb,0x17,0x2,0x2,0x2,0x3,0xc,0x1,0x0,0x1,0x2,0x4a,0x4b,0xb0,0xc, + 0x50,0x58,0x40,0x19,0x4,0x1,0x3,0x0,0x2,0x1,0x3,0x2,0x61,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x1b, + 0x4b,0xb0,0xe,0x50,0x58,0x40,0x13,0x0,0x1,0x0,0x0,0x1,0x0,0x5d,0x0,0x2,0x2,0x3,0x59,0x4,0x1,0x3,0x3,0x10,0x2,0x4c,0x1b,0x4b,0xb0,0x10, + 0x50,0x58,0x40,0x19,0x4,0x1,0x3,0x0,0x2,0x1,0x3,0x2,0x61,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x1b, + 0x4b,0xb0,0x15,0x50,0x58,0x40,0x13,0x0,0x1,0x0,0x0,0x1,0x0,0x5d,0x0,0x2,0x2,0x3,0x59,0x4,0x1,0x3,0x3,0x10,0x2,0x4c,0x1b,0x40,0x19,0x4, + 0x1,0x3,0x0,0x2,0x1,0x3,0x2,0x61,0x0,0x1,0x0,0x0,0x1,0x55,0x0,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x59,0x59,0x59,0x59,0x40,0xc, + 0x0,0x0,0x0,0x1d,0x0,0x1b,0x21,0x26,0x37,0x5,0x7,0x17,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36, + 0x33,0x21,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0xb,0x19,0x2,0xfe,0xeb,0x7,0x22,0x22,0xfe,0x62,0x1b,0x1a,0x3,0x7,0x23,0x22, + 0x1,0x47,0xf9,0xfe,0xb9,0x1b,0x1a,0x3,0x7,0x23,0x22,0x1,0x9e,0x5,0x5c,0x14,0x18,0xf,0x9,0xf9,0xdf,0x25,0x1f,0x16,0x18,0xb,0xf,0x27,0x21,0x5, + 0x89,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x1,0x30,0xfe,0xa8,0x3,0xfd,0x5,0x64,0x0,0x21,0x0,0x11,0x40,0xe,0x11,0x1,0x2,0x0, + 0x48,0x0,0x0,0x0,0x69,0x18,0x16,0x1,0x7,0x14,0x2b,0x0,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x2,0x2,0x15,0x14,0x12,0x17,0x16,0x15,0x14, + 0x6,0x7,0x6,0x6,0x23,0x22,0x27,0x26,0x26,0x2,0x35,0x34,0x12,0x0,0x37,0x3,0xb8,0x7,0x10,0x1c,0x8,0xa,0x14,0xa9,0xf8,0x85,0xa1,0x7d,0x9,0xf, + 0xd,0xc,0x1c,0xe,0xd,0xa,0x5a,0x99,0x5e,0xa2,0x1,0x21,0xb9,0x5,0x64,0x1a,0x14,0x15,0x1a,0x22,0xa,0x58,0xfe,0xf4,0xfe,0xaf,0xbc,0xc8,0xfe,0xd0, + 0x5d,0x8,0xd,0xd,0x20,0xe,0xd,0x10,0x7,0x3d,0xcc,0x1,0x13,0x9f,0xd2,0x1,0x8d,0x1,0x3c,0x5a,0x0,0x0,0x0,0x1,0x0,0xf9,0xfe,0xa9,0x3,0xc6, + 0x5,0x65,0x0,0x21,0x0,0x11,0x40,0xe,0x19,0x9,0x2,0x0,0x47,0x0,0x0,0x0,0x69,0x20,0x1e,0x1,0x7,0x14,0x2b,0x0,0x16,0x12,0x15,0x14,0x2,0x0, + 0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x12,0x12,0x35,0x34,0x2,0x27,0x26,0x35,0x34,0x36,0x37,0x36,0x36,0x33,0x32,0x17,0x2,0xcf,0x99, + 0x5e,0xa2,0xfe,0xdf,0xb9,0xc,0x7,0x10,0x1c,0x8,0xa,0x14,0xa9,0xf8,0x85,0xa1,0x7d,0x9,0xf,0xd,0xc,0x1c,0xe,0xd,0xa,0x5,0x21,0xcc,0xfe,0xed, + 0x9f,0xd2,0xfe,0x73,0xfe,0xc4,0x5a,0x5,0x1a,0x14,0x15,0x1a,0x22,0xa,0x58,0x1,0xc,0x1,0x51,0xbc,0xc8,0x1,0x30,0x5d,0x8,0xd,0xd,0x20,0xe,0xd, + 0x10,0x7,0x0,0x0,0x0,0x1,0x1,0x2b,0x1,0xf8,0x3,0xe1,0x2,0x94,0x0,0x11,0x0,0x6,0xb3,0x6,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6, + 0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x3,0xc9,0x18,0x3,0x7,0x23,0x23,0xfd,0xce,0x1c,0x18,0x3,0x8,0x23,0x22,0x2,0x32,0x2, + 0x94,0x14,0x1a,0xe,0x12,0x2c,0x22,0x15,0x1a,0xd,0x12,0x2c,0x22,0x0,0x0,0x0,0x0,0x1,0xfe,0x70,0x1,0xfe,0x6,0x9d,0x2,0x8e,0x0,0x11,0x0,0x6, + 0xb3,0x6,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x6,0x83,0x1a,0x3,0x7,0x23, + 0x22,0xf8,0x57,0x1b,0x1a,0x3,0x7,0x23,0x22,0x7,0xa9,0x2,0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1, + 0x0,0xd,0x1,0xfe,0x9,0xcb,0x2,0x8e,0x0,0x11,0x0,0x6,0xb3,0x6,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35, + 0x34,0x37,0x36,0x36,0x33,0x21,0x9,0xb1,0x1a,0x3,0x7,0x23,0x22,0xf6,0xc6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x9,0x3a,0x2,0x8e,0x16,0x18,0xb,0xf,0x27, + 0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x1,0x39,0x1,0xfe,0x8,0x9f,0x2,0x8e,0x0,0x11,0x0,0x6,0xb3,0x6,0x0,0x1,0x30,0x2b, + 0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x8,0x85,0x1a,0x3,0x7,0x23,0x22,0xf9,0x1e,0x1b,0x1a,0x3, + 0x7,0x23,0x22,0x6,0xe2,0x2,0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0xff,0x38,0x1,0xfe,0x5,0xd5, + 0x2,0x8e,0x0,0x11,0x0,0x6,0xb3,0x6,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21, + 0x5,0xbb,0x1a,0x3,0x7,0x23,0x22,0xf9,0xe7,0x1b,0x1a,0x3,0x7,0x23,0x22,0x6,0x19,0x2,0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27, + 0x21,0x0,0x0,0x0,0x0,0x1,0xff,0xff,0x1,0xfe,0x5,0xd,0x2,0x8e,0x0,0x11,0x0,0x26,0x40,0x23,0xb,0x2,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1, + 0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0x11,0x0,0xf,0x36,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14, + 0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0xf3,0x1a,0x3,0x7,0x23,0x22,0xfb,0x76,0x1b,0x1a,0x3,0x7,0x23,0x22,0x4, + 0x8a,0x2,0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xc7,0x1,0xfe,0x4,0x45,0x2,0x8e,0x0,0x11, + 0x0,0x26,0x40,0x23,0xb,0x2,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0, + 0x0,0x0,0x11,0x0,0xf,0x36,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x2b, + 0x1a,0x3,0x7,0x23,0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0x2,0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0, + 0x0,0x0,0x0,0x1,0x0,0xc7,0x1,0xfe,0x4,0x45,0x2,0x8e,0x0,0x11,0x0,0x26,0x40,0x23,0xb,0x2,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0, + 0x1,0x55,0x2,0x1,0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0x11,0x0,0xf,0x36,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x6, + 0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x2b,0x1a,0x3,0x7,0x23,0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0x2, + 0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0xff,0xff,0x0,0xc7,0x1,0xfe,0x4,0x45,0x2,0x8e,0x0,0x2,0x1,0x41, + 0x0,0x0,0x0,0x2,0x0,0xac,0x0,0xb6,0x4,0x7a,0x3,0xb2,0x0,0x17,0x0,0x2f,0x0,0x22,0x40,0x1f,0x28,0x1c,0x19,0x10,0x4,0x1,0x6,0x0,0x1,0x1, + 0x4a,0x2,0x1,0x0,0x1,0x0,0x73,0x3,0x1,0x1,0x1,0x19,0x1,0x4c,0x28,0x2c,0x28,0x2a,0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x5,0x13,0x16,0x15, + 0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x32,0x17,0x4,0x15,0x14,0x7,0x1,0x13,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27, + 0x3,0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x32,0x17,0x2,0x86,0x12,0xfe,0xe9,0xda,0xa,0x24,0x20,0x19,0x16,0xe,0xfe,0xf3,0x7,0xc,0x1,0x5a,0xc,0x11, + 0x1b,0x22,0x2,0xe,0x12,0xfe,0xd5,0xc6,0xa,0x24,0x20,0x19,0x16,0xe,0xf9,0x7,0xc,0x1,0x6e,0xc,0x11,0x1b,0x22,0x3,0x74,0x16,0x13,0x10,0xf9,0xfe, + 0xdb,0xd,0x10,0x1b,0x19,0x16,0x13,0x1,0x73,0xb,0xa,0x11,0xa,0x1,0x3a,0xc,0x23,0x1b,0x16,0x13,0x10,0xfe,0xf3,0xfe,0xef,0xd,0x10,0x1b,0x19,0x16, + 0x13,0x1,0x5f,0xb,0xa,0x11,0xa,0x1,0x4e,0xc,0x23,0x0,0x0,0x0,0x0,0x2,0x0,0x8c,0x0,0xb6,0x4,0x5a,0x3,0xb2,0x0,0x17,0x0,0x2f,0x0,0x22, + 0x40,0x1f,0x2a,0x27,0x1e,0x12,0xf,0x6,0x6,0x1,0x0,0x1,0x4a,0x3,0x1,0x1,0x0,0x1,0x73,0x2,0x1,0x0,0x0,0x19,0x0,0x4c,0x28,0x2c,0x28,0x20, + 0x4,0x7,0x18,0x2b,0x0,0x33,0x32,0x17,0x13,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x3,0x26,0x35,0x34,0x37,0x24,0x33, + 0x32,0x17,0x1,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x25,0x3,0x26,0x35,0x34,0x37,0x1,0x3d,0x19,0x17,0xd,0xf9,0x7,0xc, + 0xfe,0x92,0xc,0x11,0x1b,0x22,0x1a,0x12,0x1,0x2b,0xc6,0xa,0x24,0x1,0xec,0x19,0x17,0xd,0x1,0xd,0x7,0xc,0xfe,0xa6,0xc,0x11,0x1b,0x22,0x1a,0x12, + 0x1,0x17,0xda,0xb,0x25,0x3,0xb2,0x13,0xfe,0xa1,0xa,0xb,0x10,0xb,0xfe,0xb2,0xc,0x23,0x1b,0x16,0x13,0x10,0x1,0xd,0x1,0x11,0xd,0x10,0x1b,0x19, + 0x16,0x13,0xfe,0x8d,0xa,0xb,0x10,0xb,0xfe,0xc6,0xc,0x23,0x1b,0x16,0x13,0x10,0xf9,0x1,0x25,0xe,0xf,0x1a,0x1a,0x0,0x0,0x0,0x0,0x1,0x1,0xa6, + 0x0,0xb6,0x3,0x8a,0x3,0xb2,0x0,0x17,0x0,0x1b,0x40,0x18,0x10,0x4,0x1,0x3,0x0,0x1,0x1,0x4a,0x0,0x0,0x1,0x0,0x73,0x0,0x1,0x1,0x19,0x1, + 0x4c,0x28,0x2a,0x2,0x7,0x16,0x2b,0x0,0x15,0x14,0x7,0x1,0x13,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x32, + 0x17,0x3,0x8a,0x12,0xfe,0xdf,0xd0,0xb,0x25,0x20,0x19,0x16,0xe,0xfe,0xfd,0x7,0xc,0x1,0x64,0xc,0x11,0x1b,0x22,0x3,0x74,0x16,0x13,0x10,0xfe,0xfd, + 0xfe,0xe5,0xe,0xf,0x1a,0x1a,0x16,0x13,0x1,0x69,0xb,0xa,0x11,0xa,0x1,0x44,0xc,0x23,0x0,0x1,0x1,0x7c,0x0,0xb6,0x3,0x60,0x3,0xb2,0x0,0x17, + 0x0,0x1b,0x40,0x18,0x12,0xf,0x6,0x3,0x1,0x0,0x1,0x4a,0x0,0x1,0x0,0x1,0x73,0x0,0x0,0x0,0x19,0x0,0x4c,0x28,0x20,0x2,0x7,0x16,0x2b,0x0, + 0x33,0x32,0x17,0x1,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x3,0x26,0x35,0x34,0x37,0x2,0x19,0x19,0x17,0xd,0x1,0x3, + 0x7,0xc,0xfe,0x9c,0xc,0x11,0x1b,0x22,0x1a,0x12,0x1,0x21,0xd0,0xb,0x25,0x3,0xb2,0x13,0xfe,0x97,0xa,0xb,0x10,0xb,0xfe,0xbc,0xc,0x23,0x1b,0x16, + 0x13,0x10,0x1,0x3,0x1,0x1b,0xe,0xf,0x1a,0x1a,0xff,0xff,0x0,0x52,0xfe,0xfb,0x4,0x7,0x1,0x26,0x0,0x23,0x1,0x4d,0x0,0xf5,0x0,0x0,0x0,0x3, + 0x1,0x4d,0xff,0xb,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xee,0x2,0xf0,0x4,0xa3,0x5,0x1b,0x0,0x23,0x1,0x4b,0xff,0xb,0x0,0x0,0x0,0x3,0x1,0x4b, + 0x0,0xf5,0x0,0x0,0x0,0x0,0xff,0xff,0x0,0xfe,0x2,0xca,0x4,0xb3,0x4,0xf5,0x0,0x23,0x1,0x4c,0xff,0xb,0x0,0x0,0x0,0x3,0x1,0x4c,0x0,0xf5, + 0x0,0x0,0x0,0x0,0x0,0x1,0x1,0xe3,0x2,0xf0,0x3,0xae,0x5,0x1b,0x0,0x11,0x0,0x1f,0x40,0x1c,0x2,0x1,0x0,0x1,0x1,0x4a,0x0,0x0,0x1,0x0, + 0x73,0x2,0x1,0x1,0x1,0x10,0x1,0x4c,0x0,0x0,0x0,0x11,0x0,0x10,0x27,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22, + 0x26,0x35,0x34,0x37,0x1,0x36,0x33,0x3,0x90,0x1e,0x6,0xae,0x7,0x1f,0x15,0xbd,0xf,0x10,0xe,0x1,0x30,0x1d,0x37,0x5,0x1b,0x16,0x14,0xc,0xf,0xfe, + 0x42,0x13,0x15,0xe,0xc,0xf,0x16,0x1,0xc1,0x2b,0x0,0x1,0x1,0xf3,0x2,0xca,0x3,0xbe,0x4,0xf5,0x0,0x11,0x0,0x17,0x40,0x14,0xa,0x1,0x0,0x1, + 0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x27,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x26,0x35,0x34,0x37, + 0x13,0x36,0x36,0x33,0x33,0x3,0xae,0x10,0xe,0xfe,0xd0,0x1d,0x37,0x1b,0x1e,0x6,0xae,0x7,0x1f,0x15,0xbd,0x4,0xf5,0xe,0xc,0xf,0x16,0xfe,0x3f,0x2b, + 0x16,0x14,0xc,0xf,0x1,0xbe,0x13,0x15,0x0,0x1,0x1,0x47,0xfe,0xfb,0x3,0x12,0x1,0x26,0x0,0x11,0x0,0x17,0x40,0x14,0xa,0x1,0x0,0x1,0x1,0x4a, + 0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x27,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36, + 0x36,0x33,0x33,0x3,0x2,0x10,0xe,0xfe,0xd0,0x1d,0x37,0x1b,0x1e,0x6,0xae,0x7,0x1f,0x15,0xbd,0x1,0x26,0xe,0xc,0xf,0x16,0xfe,0x3f,0x2b,0x16,0x14, + 0xc,0xf,0x1,0xbe,0x13,0x15,0x0,0x2,0x0,0xb3,0xff,0x83,0x4,0x73,0x5,0x20,0x0,0x37,0x0,0x3f,0x0,0x34,0x40,0x31,0x3b,0x34,0x31,0x9,0x4,0x0, + 0x3,0x3a,0x22,0x1f,0xa,0x4,0x2,0x1,0x2,0x4a,0x0,0x0,0x3,0x1,0x3,0x0,0x1,0x70,0x0,0x1,0x2,0x3,0x1,0x2,0x6e,0x0,0x2,0x2,0x71,0x0, + 0x3,0x3,0x10,0x3,0x4c,0x2f,0x2d,0x2b,0x29,0x14,0x4,0x7,0x17,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x27,0x3,0x36,0x36,0x37,0x36,0x33, + 0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x2e,0x2,0x35,0x34,0x36,0x36,0x37,0x37,0x36,0x36,0x33, + 0x32,0x16,0x15,0x14,0x7,0x7,0x16,0x16,0x17,0x0,0x16,0x17,0x13,0xe,0x2,0x15,0x4,0x73,0xd,0x17,0x21,0x12,0x13,0x65,0x7c,0x75,0x43,0x83,0x38,0x13, + 0x11,0x23,0x15,0xc,0x29,0x47,0xb4,0x5c,0x20,0x6,0x27,0x25,0x1f,0x1d,0x2,0x20,0x6b,0x9c,0x53,0x81,0xeb,0x97,0x1d,0x6,0x27,0x25,0x1f,0x1d,0x2,0x1d, + 0x49,0x89,0x39,0xfd,0x1,0x73,0x66,0x75,0x60,0x98,0x56,0x3,0xb4,0x23,0x15,0x17,0x28,0xd,0x48,0x13,0xfd,0x6b,0x8,0x2c,0x20,0xb,0x2c,0x18,0x13,0x25, + 0x16,0x27,0x35,0x8,0xb5,0x22,0x1f,0x16,0x17,0x6,0xe,0xb6,0xd,0x6d,0xab,0x69,0x8c,0xf9,0xa2,0xd,0xa3,0x22,0x1f,0x16,0x17,0x6,0xe,0xa7,0xb,0x35, + 0x29,0xfd,0xdb,0x8c,0x10,0x2,0x97,0x10,0x75,0xac,0x61,0x0,0x0,0x0,0x0,0x2,0x0,0x62,0x0,0x6a,0x4,0xb2,0x4,0x4a,0x0,0x3b,0x0,0x49,0x0,0x85, + 0x40,0x13,0x36,0x31,0x2,0x7,0x4,0x27,0x22,0x9,0x4,0x4,0x6,0x7,0x18,0x13,0x2,0x1,0x6,0x3,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x24,0x5,0x1, + 0x3,0x4,0x3,0x72,0x2,0x1,0x0,0x1,0x0,0x73,0x0,0x4,0x0,0x7,0x6,0x4,0x7,0x63,0x0,0x6,0x1,0x1,0x6,0x57,0x0,0x6,0x6,0x1,0x5b,0x0, + 0x1,0x6,0x1,0x4f,0x1b,0x40,0x2e,0x0,0x3,0x5,0x3,0x72,0x0,0x5,0x4,0x5,0x72,0x0,0x2,0x1,0x0,0x1,0x2,0x0,0x70,0x0,0x0,0x0,0x71,0x0, + 0x4,0x0,0x7,0x6,0x4,0x7,0x63,0x0,0x6,0x1,0x1,0x6,0x57,0x0,0x6,0x6,0x1,0x5b,0x0,0x1,0x6,0x1,0x4f,0x59,0x40,0x10,0x46,0x44,0x3f,0x3d, + 0x3a,0x38,0x34,0x32,0x2f,0x2d,0x24,0x23,0x2f,0x8,0x7,0x17,0x2b,0x0,0x15,0x14,0x7,0x7,0x16,0x15,0x14,0x6,0x7,0x17,0x16,0x15,0x14,0x7,0x6,0x23, + 0x22,0x27,0x27,0x6,0x23,0x22,0x26,0x27,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x26,0x35,0x34,0x36,0x37,0x27,0x26,0x35,0x34,0x37,0x36,0x33, + 0x32,0x17,0x17,0x36,0x33,0x32,0x16,0x17,0x37,0x36,0x33,0x32,0x17,0x0,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x4,0xb2,0x1b, + 0x9c,0x22,0x37,0x33,0x71,0x13,0x21,0x1c,0x17,0x16,0x17,0x6f,0x6b,0x80,0x46,0x76,0x2e,0x99,0x16,0x14,0x18,0x1d,0x18,0x1b,0x9c,0x22,0x37,0x33,0x71,0x13, + 0x21,0x1c,0x17,0x17,0x16,0x6f,0x6b,0x80,0x46,0x76,0x2e,0x99,0x16,0x14,0x19,0x1c,0xfc,0xf0,0x75,0x67,0x57,0x85,0x48,0x75,0x67,0x57,0x85,0x48,0x3,0xf9, + 0x17,0x16,0x17,0x83,0x47,0x58,0x53,0x9b,0x3d,0x87,0x16,0x14,0x18,0x1d,0x18,0x1b,0x84,0x43,0x27,0x24,0x80,0x13,0x21,0x1d,0x16,0x17,0x16,0x83,0x47,0x58, + 0x53,0x9b,0x3d,0x87,0x16,0x14,0x19,0x1c,0x18,0x1b,0x84,0x43,0x27,0x24,0x80,0x13,0x21,0xfd,0xb3,0x74,0x59,0x90,0x4f,0x60,0x74,0x59,0x90,0x4f,0x0,0x1, + 0x0,0x98,0xff,0x1f,0x4,0x55,0x5,0x84,0x0,0x53,0x0,0x57,0x40,0x54,0x4e,0x1,0x6,0x7,0x51,0x1,0x1,0x6,0x27,0x1,0x2,0x5,0x24,0x1,0x3,0x2, + 0x4,0x4a,0x0,0x7,0x6,0x7,0x72,0x0,0x0,0x1,0x4,0x1,0x0,0x4,0x70,0x0,0x4,0x5,0x1,0x4,0x5,0x6e,0x0,0x3,0x2,0x3,0x73,0x0,0x6,0x0, + 0x1,0x0,0x6,0x1,0x63,0x0,0x5,0x2,0x2,0x5,0x57,0x0,0x5,0x5,0x2,0x5c,0x0,0x2,0x5,0x2,0x50,0x4c,0x4a,0x47,0x46,0x35,0x33,0x2f,0x2e,0x22, + 0x20,0x1d,0x1c,0x24,0x14,0x8,0x7,0x16,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x16,0x17,0x16, + 0x16,0x17,0x16,0x16,0x15,0x14,0x6,0x6,0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16, + 0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x27,0x26,0x26,0x27,0x26,0x26,0x27,0x26,0x26,0x35,0x34,0x36,0x36,0x37,0x37,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x7, + 0x7,0x16,0x17,0x4,0x55,0xe,0x19,0x23,0xf,0xe,0x49,0xb0,0x5d,0x51,0x72,0x38,0x36,0x34,0x30,0x68,0x47,0x6c,0x31,0x4a,0x54,0x53,0xc3,0x9e,0x29,0x6, + 0x27,0x25,0x1f,0x1d,0x2,0x2a,0xae,0x7b,0x21,0xf,0x1a,0x22,0xe,0x11,0x4a,0xb8,0x64,0x63,0x7e,0x38,0x67,0x23,0x5b,0x2c,0x50,0x5b,0x2d,0x49,0x52,0x5c, + 0xba,0x86,0x29,0x6,0x26,0x25,0x20,0x1d,0x2,0x2a,0x98,0x77,0x3,0xf2,0x20,0x16,0x1b,0x30,0x8,0x29,0x2c,0x2f,0x4c,0x2b,0x28,0x2e,0xd,0xb,0xe,0x8, + 0x14,0x11,0x1a,0x6e,0x54,0x4f,0x9b,0x6c,0x4,0xe9,0x22,0x1f,0x16,0x17,0x6,0xe,0xf0,0x14,0x4e,0x14,0x20,0x15,0x1c,0x30,0xa,0x2f,0x33,0x37,0x53,0x2c, + 0x51,0x1d,0xa,0xe,0x6,0xb,0x10,0x10,0x19,0x68,0x4f,0x54,0x95,0x5d,0x2,0xe3,0x22,0x1f,0x16,0x18,0x5,0xe,0xeb,0x12,0x41,0x0,0x0,0x1,0x0,0x5f, + 0xff,0xea,0x4,0xc9,0x4,0xb9,0x0,0x51,0x0,0x5e,0x40,0x5b,0x46,0x11,0x2,0x3,0x2,0x3a,0x1d,0x2,0x5,0x4,0x2,0x4a,0x0,0x0,0x1,0x2,0x1,0x0, + 0x2,0x70,0x0,0x7,0x5,0x6,0x5,0x7,0x6,0x70,0xc,0x1,0x2,0xb,0x1,0x3,0x4,0x2,0x3,0x63,0xa,0x1,0x4,0x9,0x1,0x5,0x7,0x4,0x5,0x63, + 0x0,0x1,0x1,0xd,0x5b,0x0,0xd,0xd,0x16,0x4b,0x0,0x6,0x6,0x8,0x5b,0x0,0x8,0x8,0x17,0x8,0x4c,0x50,0x4e,0x4c,0x4a,0x44,0x42,0x40,0x3e,0x38, + 0x36,0x26,0x23,0x22,0x26,0x22,0x26,0x22,0x24,0x14,0xe,0x7,0x1d,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x7,0x21,0x32, + 0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x6,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17, + 0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x36,0x37,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33, + 0x33,0x36,0x24,0x33,0x32,0x17,0x4,0xc9,0xe,0x17,0x23,0x11,0xe,0x3a,0x8f,0x48,0x73,0xb7,0x3b,0x1,0x5c,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0x84,0x18, + 0x4,0x1,0x7b,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0xa3,0x11,0x84,0x6d,0x52,0xa3,0x46,0xe,0x12,0x22,0x17,0xe,0x24,0xba,0xcf,0xae,0xd1,0x15,0x6a,0x1c, + 0x19,0x2,0x8,0x22,0x22,0x4f,0x4,0x15,0x4b,0x1b,0x1a,0x3,0x7,0x23,0x22,0x61,0x4c,0x1,0x15,0xb6,0xaf,0x9a,0x4,0x47,0x20,0x14,0x1c,0x2d,0xa,0x28, + 0x29,0x80,0x6d,0x16,0x18,0xb,0xf,0x27,0x21,0x55,0x51,0x15,0x18,0xc,0xf,0x27,0x21,0x75,0x7f,0x32,0x2e,0xa,0x2d,0x1c,0x14,0x20,0x15,0x6c,0xd1,0xb7, + 0x16,0x19,0xf,0xa,0x27,0x21,0x50,0x56,0x16,0x18,0xb,0xf,0x27,0x21,0xaf,0xd2,0x5d,0x0,0x0,0x0,0x0,0x1,0xff,0xc7,0xfe,0xe9,0x5,0x5,0x5,0x25, + 0x0,0x38,0x0,0x48,0x40,0x45,0x2d,0x11,0x2,0x3,0x2,0x1e,0x1,0x4,0x6,0x2,0x4a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x0,0x5,0x3,0x6,0x3, + 0x5,0x6,0x70,0x8,0x1,0x2,0x7,0x1,0x3,0x5,0x2,0x3,0x61,0x0,0x6,0x0,0x4,0x6,0x4,0x5f,0x0,0x1,0x1,0x9,0x5b,0x0,0x9,0x9,0x10,0x1, + 0x4c,0x37,0x35,0x26,0x22,0x23,0x16,0x22,0x26,0x22,0x23,0x15,0xa,0x7,0x1d,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x7,0x7, + 0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x2,0x21,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16,0x33,0x32,0x37,0x13,0x23,0x22, + 0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x12,0x21,0x32,0x17,0x4,0xf2,0x13,0x8,0x15,0x25,0x7,0xe,0x57,0x5a,0x99,0x33,0x26,0xea,0x1b,0x1a,0x3, + 0x7,0x23,0x22,0xf8,0xba,0x56,0xfe,0xe6,0x71,0x5c,0x25,0x7,0x14,0x26,0x7,0xe,0x57,0x5a,0x99,0x33,0xb4,0xc5,0x1b,0x1a,0x3,0x7,0x23,0x22,0xd3,0x2c, + 0x56,0x1,0x1a,0x71,0x5c,0x5,0x0,0x17,0x13,0x13,0x15,0x3c,0x4,0x1d,0xbb,0x88,0x16,0x18,0xb,0xf,0x27,0x21,0xfd,0x5f,0xfe,0xca,0x1f,0xd,0x24,0x12, + 0x15,0x3c,0x4,0x1d,0xbb,0x2,0x8a,0x16,0x18,0xb,0xf,0x27,0x21,0x9f,0x1,0x36,0x1f,0x0,0x0,0x0,0x0,0x1,0x0,0x1e,0xff,0xf6,0x4,0x91,0x4,0xa3, + 0x0,0x38,0x0,0x4a,0x40,0x47,0x2,0x1,0x0,0x8,0xd,0x1,0x2,0x1,0x2d,0x18,0x2,0x4,0x3,0x26,0x1,0x5,0x4,0x4,0x4a,0x0,0x1,0x0,0x2,0x3, + 0x1,0x2,0x61,0x7,0x1,0x3,0x6,0x1,0x4,0x5,0x3,0x4,0x63,0x0,0x0,0x0,0x8,0x59,0x9,0x1,0x8,0x8,0xe,0x4b,0x0,0x5,0x5,0xf,0x5,0x4c, + 0x0,0x0,0x0,0x38,0x0,0x36,0x26,0x25,0x33,0x26,0x21,0x26,0x21,0x26,0xa,0x7,0x1c,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x21,0x32, + 0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x37, + 0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x36,0x36,0x33,0x21,0x4,0x77,0x1a,0x3,0x7,0x23,0x22,0xfd,0xba,0x3c,0x1,0xd4,0x1b,0x1a,0x3, + 0x7,0x22,0x22,0xfe,0x2c,0x21,0x1,0x4b,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0xb6,0x1f,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x1f,0x84,0x1b,0x1a,0x3,0x7, + 0x23,0x22,0x83,0x84,0x7,0x20,0x22,0x2,0x9f,0x4,0xa3,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0xad,0x15,0x18,0xc,0xf,0x27,0x21,0xba,0x16,0x18,0xb,0xf, + 0x27,0x21,0xaf,0x23,0x1e,0x15,0x18,0x4,0x10,0xaf,0x16,0x18,0xb,0xf,0x27,0x21,0x2,0xe9,0x26,0x1e,0x0,0x1,0x0,0xc7,0x0,0x0,0x4,0x32,0x4,0xb9, + 0x0,0x45,0x0,0x41,0x40,0x3e,0x35,0x16,0x2,0x3,0x2,0x23,0x1,0x5,0x4,0x2,0x4a,0x0,0x0,0x1,0x2,0x1,0x0,0x2,0x70,0x7,0x1,0x2,0x6,0x1, + 0x3,0x4,0x2,0x3,0x63,0x0,0x1,0x1,0x8,0x5b,0x0,0x8,0x8,0x16,0x4b,0x0,0x4,0x4,0x5,0x59,0x0,0x5,0x5,0xf,0x5,0x4c,0x26,0x26,0x27,0x36, + 0x23,0x26,0x28,0x23,0x14,0x9,0x7,0x1d,0x2b,0x0,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x17,0x16,0x17,0x21,0x32, + 0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x6,0x6,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x35,0x23, + 0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x4,0x32,0x16,0x1c,0x1b,0xd,0x11,0x65,0x7a,0x43,0x65, + 0x35,0xf,0x11,0xc,0x5,0x1,0x1f,0x1b,0x1a,0x3,0x7,0x23,0x22,0xef,0x2,0x5e,0x55,0x1,0xc9,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfd,0xa7,0x16,0x17,0x1c, + 0x6b,0x6d,0x8e,0x1b,0x1a,0x3,0x7,0x23,0x22,0x56,0x17,0x14,0x5c,0xb2,0x79,0x51,0x94,0x3b,0x4,0x54,0x18,0x16,0x22,0x2a,0xa,0x41,0x3f,0x67,0x3a,0x20, + 0x38,0x34,0x20,0x11,0x16,0x18,0xb,0xf,0x27,0x21,0x66,0xb5,0x4d,0x16,0x18,0xb,0xf,0x27,0x21,0x34,0x23,0x1c,0x17,0x5b,0xaf,0x64,0x16,0x18,0xb,0xf, + 0x27,0x21,0x46,0x4b,0x2e,0x5f,0xaa,0x69,0x2d,0x28,0x0,0x3,0x0,0x13,0xff,0xea,0x5,0x21,0x4,0xae,0x0,0x3f,0x0,0x42,0x0,0x45,0x0,0x7a,0x40,0xd, + 0x1b,0xf,0x2,0x3,0x0,0x4,0x45,0x42,0x2,0x1,0x0,0x2,0x4a,0x4b,0xb0,0x19,0x50,0x58,0x40,0x21,0xd,0xa,0x8,0x6,0x4,0x4,0xc,0xb,0x3,0x3, + 0x0,0x1,0x4,0x0,0x64,0x9,0x1,0x5,0x5,0xe,0x4b,0x0,0x7,0x7,0x11,0x4b,0x2,0x1,0x1,0x1,0x17,0x1,0x4c,0x1b,0x40,0x24,0x0,0x7,0x5,0x4, + 0x5,0x7,0x4,0x70,0xd,0xa,0x8,0x6,0x4,0x4,0xc,0xb,0x3,0x3,0x0,0x1,0x4,0x0,0x64,0x9,0x1,0x5,0x5,0xe,0x4b,0x2,0x1,0x1,0x1,0x17, + 0x1,0x4c,0x59,0x40,0x18,0x0,0x0,0x44,0x43,0x41,0x40,0x0,0x3f,0x0,0x3e,0x36,0x35,0x12,0x23,0x13,0x23,0x26,0x23,0x25,0x23,0x26,0xe,0x7,0x1d,0x2b, + 0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x22,0x27,0x3,0x1,0x6,0x6,0x23,0x22,0x26,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37, + 0x36,0x36,0x33,0x33,0x13,0x36,0x36,0x33,0x32,0x16,0x7,0x3,0x33,0x37,0x36,0x36,0x33,0x32,0x17,0x17,0x33,0x13,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x15, + 0x14,0x7,0x3,0x33,0x5,0x23,0x3,0x1,0x23,0x13,0x5,0x7,0x1a,0x3,0x7,0x23,0x22,0x74,0xb2,0xb,0x2c,0x27,0x50,0xc,0x68,0xfe,0xca,0x12,0x34,0x26, + 0x28,0x27,0x1,0x16,0x68,0x1b,0x1a,0x3,0x7,0x23,0x22,0x53,0xf,0x2,0x1d,0x2b,0x2c,0x1f,0x2,0x13,0xee,0x30,0xb,0x24,0x20,0x3f,0x6,0x10,0xef,0x75, + 0x9,0x1e,0x1b,0xe,0x10,0x1e,0x1b,0x8,0x70,0x61,0xfc,0xfa,0xa9,0x11,0x2,0x9d,0xa9,0x3e,0x2,0xf2,0x16,0x18,0xb,0xf,0x27,0x21,0xfd,0xc9,0x24,0x1d, + 0x41,0x2,0x4a,0xfd,0xb6,0x22,0x1f,0x1e,0x23,0x2,0x37,0x16,0x18,0xb,0xf,0x27,0x21,0x1,0x7e,0x22,0x1a,0x1b,0x24,0xfe,0x85,0x5b,0x14,0x14,0x28,0x5b, + 0x1,0x83,0x1e,0x1b,0x3,0x5,0x16,0x13,0xf,0x18,0xfe,0x9c,0x90,0xfe,0xa0,0x1,0x60,0xfe,0xa0,0x0,0x0,0x1,0x0,0xa1,0xff,0xf6,0x4,0xc7,0x4,0xb2, + 0x0,0x4c,0x0,0x48,0x40,0x45,0x47,0x35,0x8,0x3,0x1,0x0,0x30,0x1,0x2,0x1,0x29,0x14,0x2,0x3,0x2,0x22,0x1,0x4,0x3,0x4,0x4a,0x8,0x1,0x0, + 0x7,0x1,0x1,0x2,0x0,0x1,0x62,0x6,0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9,0xe,0x4b,0x0,0x4,0x4,0xf,0x4,0x4c,0x4b, + 0x49,0x43,0x42,0x26,0x22,0x26,0x25,0x33,0x26,0x22,0x26,0x24,0xb,0x7,0x1d,0x2b,0x0,0x15,0x14,0x7,0x1,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23, + 0x21,0x7,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x7,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x21,0x22,0x26,0x35,0x34,0x37, + 0x36,0x36,0x33,0x21,0x37,0x27,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x3,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x13,0x1,0x36, + 0x33,0x32,0x17,0x4,0xc7,0x15,0xfe,0xe0,0xa2,0x1b,0x1a,0x3,0x7,0x23,0x22,0xff,0x1,0x5f,0x9,0x1,0x36,0x1b,0x1a,0x3,0x7,0x22,0x22,0xfe,0xc9,0x29, + 0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0x29,0xfe,0xd3,0x1c,0x19,0x2,0x7,0x23,0x22,0x1,0x2e,0xb,0x30,0xff,0x0,0x1b,0x1a,0x3,0x7,0x23,0x22,0xa2,0xa9, + 0xa,0x19,0x1c,0x1a,0x14,0x10,0x14,0x8,0xf5,0x1,0xb2,0x18,0x20,0x17,0x19,0x4,0x8b,0x1b,0x14,0x1a,0xfe,0xa6,0x16,0x18,0xb,0xf,0x27,0x21,0x72,0x34, + 0x16,0x18,0xb,0xf,0x27,0x21,0xeb,0x23,0x1e,0x15,0x18,0x4,0x10,0xeb,0x16,0x19,0xf,0xa,0x27,0x21,0x41,0x65,0x16,0x18,0xb,0xf,0x27,0x21,0x1,0x65, + 0x16,0xc,0x10,0x19,0xb,0xb,0x10,0x11,0xfd,0xf5,0x2,0x12,0x1e,0xf,0x0,0x0,0xff,0xff,0x0,0x90,0x1,0x6,0x4,0x7a,0x3,0x84,0x0,0x27,0x1,0x59, + 0x0,0x23,0x0,0xc8,0x1,0x7,0x1,0x59,0xff,0xdd,0xff,0x38,0x0,0x11,0xb1,0x0,0x1,0xb0,0xc8,0xb0,0x33,0x2b,0xb1,0x1,0x1,0xb8,0xff,0x38,0xb0,0x33, + 0x2b,0x0,0x0,0x0,0x0,0x1,0x0,0xb3,0x1,0xce,0x4,0x57,0x2,0xbc,0x0,0x27,0x0,0x34,0xb1,0x6,0x64,0x44,0x40,0x29,0x20,0x1,0x3,0x2,0xc,0x1, + 0x0,0x1,0x2,0x4a,0x0,0x3,0x1,0x0,0x3,0x57,0x0,0x2,0x0,0x1,0x0,0x2,0x1,0x63,0x0,0x3,0x3,0x0,0x5b,0x0,0x0,0x3,0x0,0x4f,0x24,0x2c, + 0x24,0x21,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x0,0x6,0x23,0x22,0x26,0x27,0x26,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37, + 0x36,0x36,0x33,0x32,0x16,0x17,0x16,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x3,0xfd,0x80,0x3d,0x31,0x5b,0x40,0x41,0x51,0x2c, + 0x59,0x5a,0xa,0xa,0xe,0x19,0x9,0xc,0x15,0x46,0x80,0x3e,0x31,0x5b,0x40,0x41,0x51,0x2c,0x59,0x5a,0xb,0x9,0xe,0x19,0x9,0xa,0x14,0x1,0xfc,0x2e, + 0x16,0x16,0x16,0x14,0x3a,0x6,0x12,0xf,0x15,0x14,0x1c,0xf,0x35,0x2e,0x16,0x16,0x16,0x14,0x3a,0x6,0x13,0x10,0x14,0x13,0x1b,0x10,0x0,0x3,0x0,0xc7, + 0x0,0x82,0x4,0x45,0x4,0x8,0x0,0xd,0x0,0x1f,0x0,0x2d,0x0,0x48,0x40,0x45,0x19,0x10,0x2,0x2,0x3,0x1,0x4a,0x6,0x1,0x1,0x0,0x0,0x3,0x1, + 0x0,0x63,0x7,0x1,0x3,0x0,0x2,0x5,0x3,0x2,0x61,0x8,0x1,0x5,0x4,0x4,0x5,0x57,0x8,0x1,0x5,0x5,0x4,0x5b,0x0,0x4,0x5,0x4,0x4f,0x20, + 0x20,0xe,0xe,0x0,0x0,0x20,0x2d,0x20,0x2c,0x27,0x25,0xe,0x1f,0xe,0x1d,0x17,0x14,0x0,0xd,0x0,0xc,0x25,0x9,0x7,0x15,0x2b,0x0,0x16,0x7,0x7, + 0x6,0x6,0x23,0x22,0x26,0x37,0x37,0x36,0x36,0x33,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x0,0x16, + 0x7,0x7,0x6,0x6,0x23,0x22,0x26,0x37,0x37,0x36,0x36,0x33,0x2,0xf9,0x2d,0x4,0x17,0x4,0x2b,0x31,0x32,0x2e,0x4,0x17,0x4,0x2b,0x31,0x1,0x65,0x1a, + 0x3,0x7,0x23,0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0xfe,0x85,0x2d,0x4,0x17,0x4,0x2b,0x31,0x32,0x2e,0x4,0x17,0x4,0x2b,0x31,0x4, + 0x8,0x15,0x17,0x80,0x18,0x14,0x15,0x17,0x80,0x18,0x14,0xfe,0x86,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0xcc,0x15,0x17,0x80, + 0x18,0x14,0x15,0x17,0x80,0x18,0x14,0x0,0x0,0x0,0xff,0xff,0x0,0xa4,0x1,0x36,0x4,0x68,0x3,0x56,0x0,0x27,0x1,0x63,0x0,0x23,0x0,0xc8,0x1,0x7, + 0x1,0x63,0xff,0xdd,0xff,0x38,0x0,0x11,0xb1,0x0,0x1,0xb0,0xc8,0xb0,0x33,0x2b,0xb1,0x1,0x1,0xb8,0xff,0x38,0xb0,0x33,0x2b,0x0,0x0,0x0,0x0,0x1, + 0x0,0x89,0x0,0x79,0x4,0x71,0x4,0x16,0x0,0x1b,0x0,0x18,0x40,0x15,0x1a,0xa,0x2,0x1,0x0,0x1,0x4a,0x0,0x0,0x1,0x0,0x72,0x0,0x1,0x1,0x69, + 0x2c,0x14,0x2,0x7,0x16,0x2b,0x0,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x1,0x16,0x15,0x14,0x7,0x6,0x6,0x7,0x1,0x6,0x23,0x22,0x26,0x27,0x26,0x35, + 0x34,0x37,0x1,0x1,0x1,0x10,0x14,0x1f,0x24,0x10,0x11,0x2,0xc6,0x23,0x2,0x5,0x1b,0x19,0xfc,0xb3,0x13,0xd,0x15,0x1d,0x8,0x6,0x2f,0x2,0xd2,0xfd, + 0xa6,0x3,0x9a,0x1b,0x16,0x1d,0x2e,0x9,0xfe,0x83,0x13,0x24,0x6,0xc,0x1a,0x23,0xc,0xfe,0x83,0x8,0x1b,0x19,0x14,0x10,0x2b,0x14,0x1,0x3e,0x1,0x3b, + 0x0,0x0,0x0,0x2,0x0,0x81,0x0,0x6e,0x4,0x63,0x4,0x6b,0x0,0x1c,0x0,0x2e,0x0,0x8,0xb5,0x23,0x1d,0x19,0x9,0x2,0x30,0x2b,0x1,0x16,0x15,0x14, + 0x7,0x6,0x6,0x7,0x1,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x25,0x25,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x0,0x16,0x15,0x14,0x7, + 0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x3a,0x29,0x2,0x5,0x21,0x1c,0xfc,0xf1,0x12,0x10,0x12,0x18,0x9,0x7,0x35,0x2, + 0x86,0xfd,0xda,0x25,0xd,0xb,0x19,0x10,0x9,0x13,0x2,0x64,0x1a,0x3,0x7,0x23,0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0x3,0x3e,0x11, + 0x28,0x4,0xe,0x1d,0x24,0xa,0xfe,0xe0,0x7,0x17,0x1a,0x12,0x12,0x2e,0x13,0xe4,0xdf,0xf,0x1e,0x10,0x20,0x1b,0x19,0x7,0xfc,0x9a,0x16,0x18,0xb,0xf, + 0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x3,0x0,0x3b,0x1,0x25,0x4,0xd1,0x3,0x67,0x0,0x1f,0x0,0x2b,0x0,0x37,0x0,0xa,0xb7,0x33,0x2d,0x24, + 0x20,0x6,0x0,0x3,0x30,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x27,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x37,0x3e,0x2,0x33, + 0x32,0x16,0x16,0x17,0x36,0x36,0x33,0x0,0x36,0x37,0x26,0x26,0x23,0x22,0x6,0x15,0x14,0x16,0x33,0x24,0x26,0x23,0x22,0x6,0x7,0x16,0x16,0x33,0x32,0x36, + 0x35,0x4,0x1d,0x74,0x40,0x4f,0x8a,0x54,0x47,0x6b,0x4b,0x26,0x4a,0x95,0x68,0x4b,0x74,0x40,0x1,0x7,0x52,0x84,0x50,0x47,0x6b,0x4b,0x26,0x4a,0x95,0x68, + 0xfd,0xbf,0x72,0x3e,0x2f,0x64,0x48,0x48,0x5a,0x45,0x3d,0x3,0x0,0x45,0x3d,0x4b,0x72,0x3e,0x2f,0x64,0x48,0x48,0x5a,0x3,0x67,0x43,0x77,0x4a,0x5b,0x91, + 0x52,0x33,0x52,0x3b,0x5b,0x65,0x43,0x77,0x4a,0x13,0xa,0x54,0x83,0x4a,0x33,0x52,0x3b,0x5b,0x65,0xfe,0x44,0x52,0x4d,0x49,0x4e,0x63,0x4c,0x3b,0x4c,0xea, + 0x4c,0x52,0x4d,0x49,0x4e,0x63,0x4c,0x0,0x0,0x1,0xff,0x8d,0xfe,0x66,0x5,0x75,0x5,0xed,0x0,0x27,0x0,0x6,0xb3,0x12,0x0,0x1,0x30,0x2b,0x0,0x16, + 0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x23,0x22,0x6,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x32,0x17,0x16, + 0x33,0x32,0x36,0x37,0x13,0x36,0x36,0x33,0x4,0x8e,0x8a,0x3a,0x23,0xa,0x16,0x20,0x9,0xd,0x7a,0x6e,0x69,0x8b,0x17,0xc4,0x21,0xe0,0xaa,0x49,0x8a,0x3a, + 0x23,0xa,0x16,0x20,0x9,0xd,0x7a,0x6e,0x69,0x8b,0x17,0xc4,0x21,0xe0,0xaa,0x5,0xed,0x1f,0x1b,0x10,0x21,0x11,0x17,0x34,0x5,0x30,0x8f,0x83,0xfb,0xab, + 0xbc,0xd2,0x1f,0x1b,0x10,0x21,0x11,0x17,0x34,0x5,0x30,0x8f,0x83,0x4,0x55,0xbc,0xd2,0x0,0x0,0x0,0x0,0x1,0x0,0x9b,0x0,0x78,0x4,0x83,0x4,0x15, + 0x0,0x1b,0x0,0x18,0x40,0x15,0x1a,0xa,0x2,0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x2c,0x14,0x2,0x7,0x16,0x2b,0x24,0x15, + 0x14,0x7,0x6,0x23,0x22,0x27,0x1,0x26,0x35,0x34,0x37,0x36,0x36,0x37,0x1,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x1,0x1,0x3,0xfc,0x14,0x1f, + 0x24,0x10,0x11,0xfd,0x3a,0x23,0x2,0x5,0x1b,0x19,0x3,0x4d,0x13,0xd,0x15,0x1d,0x8,0x6,0x2f,0xfd,0x2e,0x2,0x5a,0xf4,0x1b,0x16,0x1d,0x2e,0x9,0x1, + 0x7d,0x13,0x24,0x6,0xc,0x1a,0x23,0xc,0x1,0x7d,0x8,0x1b,0x19,0x13,0x11,0x2b,0x14,0xfe,0xc2,0xfe,0xc5,0x0,0x0,0x0,0x0,0x2,0x0,0x81,0x0,0x6e, + 0x4,0x96,0x4,0x65,0x0,0x1c,0x0,0x2e,0x0,0x8,0xb5,0x23,0x1d,0x10,0x0,0x2,0x30,0x2b,0x0,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x5,0x5,0x16, + 0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x27,0x1,0x26,0x35,0x34,0x37,0x36,0x36,0x37,0x1,0x2,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34, + 0x37,0x36,0x36,0x33,0x21,0x4,0x4c,0x10,0x12,0x18,0x9,0x7,0x35,0xfd,0x7a,0x2,0x26,0x25,0xd,0xb,0x19,0x10,0x9,0x13,0xfd,0x47,0x29,0x2,0x5,0x21, + 0x1c,0x3,0xf,0x55,0x1a,0x3,0x7,0x23,0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0x4,0x65,0x17,0x1a,0x12,0x12,0x2e,0x13,0xe4,0xdf,0xf, + 0x1e,0xf,0x21,0x1b,0x19,0x7,0x1,0x26,0x11,0x28,0x4,0xe,0x1d,0x24,0xa,0x1,0x20,0xfc,0xa0,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27, + 0x21,0x0,0x0,0x0,0x0,0x1,0x0,0xcc,0x1,0x3e,0x4,0x7b,0x3,0x51,0x0,0x18,0x0,0x30,0x40,0x2d,0x12,0x2,0x2,0x1,0x2,0xb,0x1,0x0,0x1,0x2, + 0x4a,0x0,0x0,0x1,0x0,0x73,0x3,0x1,0x2,0x1,0x1,0x2,0x55,0x3,0x1,0x2,0x2,0x1,0x59,0x0,0x1,0x2,0x1,0x4d,0x0,0x0,0x0,0x18,0x0,0x16, + 0x25,0x27,0x4,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33, + 0x21,0x4,0x62,0x19,0x2,0x46,0x6,0x27,0x29,0x23,0x1f,0x2,0x39,0xfd,0x2b,0x1b,0x1a,0x3,0x7,0x22,0x22,0x3,0x2c,0x3,0x51,0x14,0x18,0xf,0x9,0xfe, + 0x72,0x23,0x1e,0x15,0x18,0x6,0xe,0x1,0x42,0x15,0x18,0xc,0xf,0x27,0x21,0x0,0x0,0x1,0x0,0xc7,0x1,0xfe,0x4,0x45,0x2,0x8e,0x0,0x11,0x0,0x6, + 0xb3,0x6,0x0,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x2b,0x1a,0x3,0x7,0x23, + 0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0x2,0x8e,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x0,0x0,0x1, + 0x0,0xe4,0x0,0xc8,0x4,0x27,0x3,0xc4,0x0,0x29,0x0,0x55,0x4b,0xb0,0x24,0x50,0x58,0x40,0x9,0x24,0x19,0xf,0x4,0x4,0x0,0x2,0x1,0x4a,0x1b,0x40, + 0x9,0x24,0x19,0xf,0x4,0x4,0x1,0x3,0x1,0x4a,0x59,0x4b,0xb0,0x24,0x50,0x58,0x40,0xd,0x1,0x1,0x0,0x2,0x0,0x73,0x3,0x1,0x2,0x2,0x19,0x2, + 0x4c,0x1b,0x40,0x17,0x0,0x1,0x3,0x0,0x3,0x1,0x0,0x70,0x0,0x0,0x0,0x71,0x0,0x2,0x2,0x19,0x4b,0x0,0x3,0x3,0x19,0x3,0x4c,0x59,0xb6,0x24, + 0x2d,0x24,0x2b,0x4,0x7,0x18,0x2b,0x0,0x15,0x14,0x7,0x5,0x13,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x27,0x27,0x5,0x6,0x23,0x22,0x27,0x26,0x35, + 0x34,0x37,0x25,0x3,0x26,0x35,0x34,0x36,0x37,0x36,0x33,0x32,0x17,0x17,0x25,0x36,0x33,0x32,0x17,0x4,0x27,0x19,0xfe,0xdc,0xda,0x12,0x11,0x11,0x1c,0x16, + 0x19,0x17,0xd5,0xfe,0xe2,0x17,0x14,0x19,0x1d,0x1a,0x19,0x1,0x24,0xd9,0x12,0x11,0x11,0x1c,0x16,0x1a,0x16,0xd4,0x1,0x1e,0x17,0x14,0x19,0x1d,0x3,0x7b, + 0x16,0x16,0x15,0xfb,0xfe,0xfc,0x15,0x12,0xd,0x19,0xf,0x17,0x1b,0xfe,0xf7,0x14,0x1f,0x1c,0x16,0x16,0x15,0xfc,0x1,0x3,0x15,0x12,0xd,0x19,0xf,0x17, + 0x1b,0xfd,0xf6,0x14,0x1f,0x0,0x0,0x0,0x0,0x1,0x0,0xa4,0x0,0x45,0x4,0x68,0x4,0x47,0x0,0x3d,0x0,0x6,0xb3,0x34,0x15,0x1,0x30,0x2b,0x0,0x16, + 0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x23,0x22, + 0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x7,0x33, + 0x4,0x4e,0x1a,0x3,0x7,0x23,0x22,0xde,0xc4,0x1,0x76,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0x36,0x9d,0x1d,0x1e,0x15,0x13,0x20,0x12,0x68,0x8a,0x1b,0x1a, + 0x3,0x7,0x23,0x22,0xde,0xc4,0xfe,0x8a,0x1b,0x1a,0x3,0x7,0x23,0x22,0x1,0xcb,0x9c,0x1d,0x1f,0x15,0x13,0x1f,0x13,0x66,0x89,0x3,0x56,0x16,0x18,0xb, + 0xf,0x27,0x21,0xff,0x0,0x16,0x18,0xb,0xf,0x27,0x21,0xcc,0x25,0x10,0x18,0x18,0x12,0x18,0x87,0x16,0x18,0xb,0xf,0x27,0x21,0x1,0x0,0x16,0x18,0xb, + 0xf,0x27,0x21,0xcc,0x25,0x10,0x19,0x17,0x13,0x19,0x85,0x0,0x0,0x2,0x0,0xa7,0xff,0xe9,0x4,0x4a,0x4,0xb8,0x0,0x27,0x0,0x36,0x0,0x8,0xb5,0x2c, + 0x28,0x9,0x0,0x2,0x30,0x2b,0x0,0x33,0x32,0x16,0x16,0x15,0x14,0x7,0x6,0x4,0x23,0x22,0x26,0x26,0x35,0x34,0x37,0x3e,0x2,0x33,0x32,0x16,0x17,0x36, + 0x35,0x34,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x12,0x36,0x37,0x26,0x26,0x23,0x22,0x6,0x6,0x7,0x6,0x15,0x14,0x16,0x33, + 0x2,0x7b,0x5b,0x69,0xa8,0x63,0x49,0x59,0xfe,0xfc,0xb7,0x64,0x93,0x4f,0x2,0xa,0x77,0xbd,0x70,0x6e,0x9f,0x23,0x2f,0x7d,0x7b,0x3a,0x4d,0x4,0x9,0x10, + 0x17,0x8,0x4,0x27,0x47,0xa2,0x3c,0xb,0x79,0x64,0x4e,0x7a,0x4a,0x8,0x2,0x62,0x56,0x4,0xb8,0x55,0xb0,0x83,0x9c,0xca,0xf5,0xec,0x4e,0x8f,0x5e,0xe, + 0x1c,0x75,0xb5,0x63,0x69,0x5e,0x96,0x6f,0x7e,0x88,0x11,0x1,0x19,0x20,0xd,0xf,0x2a,0xe,0xfb,0xe4,0x72,0x78,0x62,0x7d,0x3d,0x72,0x4b,0x16,0x9,0x53, + 0x5d,0x0,0x0,0x0,0x0,0x5,0x0,0x42,0xff,0xea,0x4,0xce,0x4,0xb9,0x0,0xf,0x0,0x21,0x0,0x2f,0x0,0x3f,0x0,0x4d,0x0,0x62,0x40,0x5f,0x0,0x2, + 0x1,0x5,0x1,0x2,0x5,0x70,0x0,0x3,0x8,0x6,0x8,0x3,0x6,0x70,0x0,0x4,0x0,0x0,0x7,0x4,0x0,0x63,0xc,0x1,0x7,0xd,0x1,0x9,0x8,0x7, + 0x9,0x63,0xb,0x1,0x5,0x5,0x1,0x5b,0xa,0x1,0x1,0x1,0x16,0x4b,0x0,0x8,0x8,0x6,0x5b,0x0,0x6,0x6,0x17,0x6,0x4c,0x40,0x40,0x30,0x30,0x22, + 0x22,0x0,0x0,0x40,0x4d,0x40,0x4c,0x47,0x45,0x30,0x3f,0x30,0x3e,0x38,0x36,0x22,0x2f,0x22,0x2e,0x29,0x27,0x1b,0x19,0x12,0x10,0x0,0xf,0x0,0xe,0x26, + 0xe,0x7,0x15,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x4,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6, + 0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x1,0x24,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23, + 0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x2,0xe,0x6b,0x3d,0x5a,0x93,0x51,0x42,0x6b, + 0x3d,0x5a,0x93,0x51,0x2,0xad,0x17,0x18,0x15,0x11,0x20,0xfc,0x3,0x1a,0x17,0x1a,0x13,0x11,0x21,0x3,0xfc,0xfd,0x31,0x4f,0x31,0x44,0x35,0x2b,0x4f,0x31, + 0x45,0x34,0x2,0x1f,0x6b,0x3d,0x5a,0x93,0x51,0x42,0x6b,0x3d,0x5a,0x93,0x51,0x3c,0x4f,0x31,0x44,0x35,0x2b,0x4f,0x31,0x45,0x34,0x4,0xb9,0x40,0x6d,0x40, + 0x55,0x8f,0x53,0x3f,0x6d,0x41,0x55,0x8f,0x53,0x80,0x1b,0x16,0x14,0x1b,0x1a,0xfc,0xc2,0x16,0x1b,0x16,0x13,0x1b,0x1b,0x3,0x3e,0x14,0x2f,0x4e,0x2c,0x33, + 0x44,0x2f,0x4e,0x2c,0x33,0x44,0xfd,0xd7,0x40,0x6d,0x40,0x55,0x8f,0x53,0x3f,0x6d,0x41,0x55,0x8f,0x53,0x82,0x2f,0x4e,0x2c,0x33,0x44,0x2f,0x4e,0x2c,0x33, + 0x44,0x0,0x0,0x6,0x0,0x42,0xff,0xea,0x6,0x26,0x4,0xb9,0x0,0xf,0x0,0x21,0x0,0x2f,0x0,0x4b,0x0,0x59,0x0,0x67,0x0,0x7d,0x40,0x7a,0x48,0x1, + 0xb,0x8,0x3a,0x1,0x6,0x3,0x2,0x4a,0x0,0x2,0x1,0x5,0x1,0x2,0x5,0x70,0x0,0x3,0xa,0x6,0xa,0x3,0x6,0x70,0x0,0x4,0x0,0x0,0x8,0x4, + 0x0,0x63,0x10,0x9,0x2,0x8,0x12,0xd,0x11,0x3,0xb,0xa,0x8,0xb,0x63,0xf,0x1,0x5,0x5,0x1,0x5b,0xe,0x1,0x1,0x1,0x16,0x4b,0xc,0x1,0xa, + 0xa,0x6,0x5b,0x7,0x1,0x6,0x6,0x17,0x6,0x4c,0x5a,0x5a,0x4c,0x4c,0x30,0x30,0x22,0x22,0x0,0x0,0x5a,0x67,0x5a,0x66,0x61,0x5f,0x4c,0x59,0x4c,0x58, + 0x53,0x51,0x30,0x4b,0x30,0x4a,0x46,0x44,0x3e,0x3c,0x38,0x36,0x22,0x2f,0x22,0x2e,0x29,0x27,0x1b,0x19,0x12,0x10,0x0,0xf,0x0,0xe,0x26,0x13,0x7,0x15, + 0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x4,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x1,0x6,0x23,0x22,0x27, + 0x26,0x35,0x34,0x37,0x1,0x24,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x27, + 0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x17,0x36,0x36,0x33,0x4,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26, + 0x23,0x20,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x2,0xe,0x6b,0x3d,0x5a,0x93,0x51,0x42,0x6b,0x3d,0x5a,0x93,0x51,0x2,0xad, + 0x17,0x18,0x15,0x11,0x20,0xfc,0x3,0x1a,0x17,0x1a,0x13,0x11,0x21,0x3,0xfc,0xfd,0x31,0x4f,0x31,0x44,0x35,0x2b,0x4f,0x31,0x45,0x34,0x3,0xc3,0x6b,0x3d, + 0x5a,0x93,0x51,0x3e,0x63,0x1d,0x2b,0x79,0x42,0x42,0x6b,0x3d,0x5a,0x93,0x51,0x3e,0x63,0x1d,0x2c,0x78,0x42,0xfe,0x20,0x4f,0x31,0x44,0x35,0x2b,0x4f,0x31, + 0x45,0x34,0x1,0x79,0x4f,0x31,0x44,0x35,0x2b,0x4f,0x31,0x45,0x34,0x4,0xb9,0x40,0x6d,0x40,0x55,0x8f,0x53,0x3f,0x6d,0x41,0x55,0x8f,0x53,0x80,0x1b,0x16, + 0x14,0x1b,0x1a,0xfc,0xc2,0x16,0x1b,0x16,0x13,0x1b,0x1b,0x3,0x3e,0x14,0x2f,0x4e,0x2c,0x33,0x44,0x2f,0x4e,0x2c,0x33,0x44,0xfd,0xd7,0x40,0x6d,0x40,0x55, + 0x8f,0x53,0x39,0x31,0x31,0x39,0x3f,0x6d,0x41,0x55,0x8f,0x53,0x39,0x31,0x32,0x38,0x82,0x2f,0x4e,0x2c,0x33,0x44,0x2f,0x4e,0x2c,0x33,0x44,0x2f,0x4e,0x2c, + 0x33,0x44,0x2f,0x4e,0x2c,0x33,0x44,0x0,0x0,0x0,0x0,0x1,0x0,0xc7,0x0,0x8a,0x4,0x45,0x4,0x2,0x0,0x27,0x0,0x3e,0x40,0x3b,0x2,0x1,0x0,0x5, + 0x1d,0x9,0x2,0x1,0x0,0x16,0x1,0x2,0x1,0x3,0x4a,0x6,0x1,0x5,0x0,0x5,0x72,0x0,0x2,0x1,0x2,0x73,0x4,0x1,0x0,0x1,0x1,0x0,0x55,0x4, + 0x1,0x0,0x0,0x1,0x5a,0x3,0x1,0x1,0x0,0x1,0x4e,0x0,0x0,0x0,0x27,0x0,0x26,0x26,0x25,0x23,0x26,0x25,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14, + 0x7,0x3,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36, + 0x33,0x21,0x13,0x36,0x36,0x33,0x2,0xf3,0x20,0x2,0x36,0x1,0x35,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0xcb,0x36,0x6,0x24,0x27,0x21,0x20,0x2,0x36,0xfe, + 0xcb,0x1b,0x1a,0x3,0x7,0x23,0x22,0x1,0x35,0x36,0x6,0x24,0x27,0x4,0x2,0x15,0x18,0x4,0xe,0xfe,0xcb,0x16,0x18,0xb,0xf,0x27,0x21,0xfe,0xcb,0x22, + 0x1d,0x15,0x18,0x4,0xe,0x1,0x35,0x16,0x18,0xb,0xf,0x27,0x21,0x1,0x35,0x22,0x1d,0x0,0x0,0x2,0x0,0x81,0x0,0x6e,0x4,0x61,0x4,0x66,0x0,0x27, + 0x0,0x39,0x0,0x57,0x40,0x54,0x2,0x1,0x0,0x5,0x1d,0x9,0x2,0x1,0x0,0x16,0x1,0x2,0x1,0x33,0x2a,0x2,0x6,0x7,0x4,0x4a,0x8,0x1,0x5,0x0, + 0x5,0x72,0x0,0x2,0x1,0x7,0x1,0x2,0x7,0x70,0x4,0x1,0x0,0x3,0x1,0x1,0x2,0x0,0x1,0x62,0x9,0x1,0x7,0x6,0x6,0x7,0x55,0x9,0x1,0x7, + 0x7,0x6,0x59,0x0,0x6,0x7,0x6,0x4d,0x28,0x28,0x0,0x0,0x28,0x39,0x28,0x37,0x31,0x2e,0x0,0x27,0x0,0x26,0x26,0x25,0x23,0x26,0x25,0xa,0x7,0x19, + 0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x37,0x21,0x22,0x26, + 0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x37,0x36,0x36,0x33,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x3, + 0x5,0x20,0x2,0x2c,0x1,0x35,0x1b,0x1a,0x3,0x7,0x23,0x22,0xfe,0xcc,0x2c,0x6,0x24,0x27,0x21,0x20,0x2,0x2c,0xfe,0xca,0x1b,0x1a,0x3,0x7,0x23,0x22, + 0x1,0x35,0x2c,0x6,0x24,0x27,0x1,0x1,0x1a,0x3,0x7,0x23,0x22,0xfd,0x6,0x1b,0x1a,0x3,0x7,0x23,0x22,0x2,0xfa,0x4,0x66,0x15,0x18,0x4,0xe,0xf9, + 0x16,0x18,0xb,0xf,0x27,0x21,0xf9,0x22,0x1d,0x15,0x18,0x4,0xe,0xf9,0x16,0x18,0xb,0xf,0x27,0x21,0xf9,0x22,0x1d,0xfc,0x98,0x16,0x18,0xb,0xf,0x27, + 0x21,0x16,0x18,0xb,0xf,0x27,0x21,0x0,0x0,0x1,0x0,0x84,0xff,0xf6,0x4,0x8a,0x4,0xa3,0x0,0x1f,0x0,0x6,0xb3,0x7,0x0,0x1,0x30,0x2b,0x0,0x16, + 0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x21,0x3,0x6,0x6,0x23,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x21, + 0x4,0x71,0x19,0x2,0xbc,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xaf,0xfd,0xe6,0xaf,0x6,0x27,0x28,0x2,0x23,0x1e,0x2,0xbc,0x7,0x22,0x22,0x2,0xc8,0x4, + 0xa3,0x14,0x18,0xf,0x9,0xfb,0xd8,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0xdc,0xfc,0x24,0x23,0x1e,0x15,0x18,0x4,0x10,0x4,0x28,0x25,0x1f,0x0,0x0,0x0, + 0x0,0x1,0x0,0x95,0xff,0xea,0x4,0xd1,0x4,0xad,0x0,0x1f,0x0,0x6,0xb3,0x1c,0x7,0x1,0x30,0x2b,0x0,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22, + 0x26,0x27,0x3,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x32,0x16,0x17,0x13,0x1,0x36,0x33,0x32,0x17,0x4,0xbb,0x16,0xc,0xfd,0xce,0x13,0x33, + 0x2b,0x2b,0x2e,0x7,0x6f,0x89,0x1b,0x1a,0x3,0x7,0x22,0x22,0xbc,0x17,0x19,0x4,0x68,0x2,0x1,0x16,0x23,0x14,0x1a,0x4,0x96,0x17,0x10,0x11,0x17,0xfb, + 0xe3,0x23,0x1d,0x1f,0x22,0x1,0xd3,0x15,0x18,0xc,0xf,0x27,0x21,0xf,0x11,0xfe,0x48,0x3,0xcd,0x2a,0xc,0x0,0x0,0x3,0x0,0x69,0xfc,0xba,0x4,0x7d, + 0x7,0x5,0x0,0x3,0x0,0x2d,0x0,0x31,0x0,0xa,0xb7,0x30,0x2e,0x1a,0x4,0x2,0x0,0x3,0x30,0x2b,0x1,0x23,0x35,0x33,0x0,0x16,0x15,0x14,0x7,0x6, + 0x6,0x23,0x21,0x1,0x16,0x15,0x14,0x7,0x1,0x21,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x37,0x1,0x1,0x26,0x35, + 0x34,0x37,0x36,0x36,0x33,0x21,0x1,0x23,0x35,0x33,0x3,0x5d,0x1,0x1,0x1,0x7,0x19,0x2,0x8,0x22,0x22,0xfd,0xc9,0x1,0x8,0x8,0xd,0xfe,0x62,0x2, + 0x47,0x1c,0x19,0x2,0x7,0x23,0x22,0xfd,0x15,0x1c,0x1b,0x2,0x6,0x13,0x1,0xdb,0xfe,0xdd,0x6,0x2,0x7,0x24,0x22,0x2,0xc3,0xfd,0x44,0x1,0x1,0x7, + 0x4,0x1,0xfd,0x9e,0x16,0x19,0xf,0xa,0x27,0x21,0xfe,0x5f,0xe,0xe,0x13,0xe,0xfe,0x5b,0x16,0x19,0xf,0xa,0x27,0x21,0x15,0x18,0xe,0x9,0x20,0x15, + 0x1,0xe6,0x1,0xcf,0x8,0x11,0x6,0x12,0x25,0x1f,0xf8,0x17,0x1,0x0,0x0,0x2,0x0,0xf0,0xff,0xea,0x4,0x20,0x4,0xb9,0x0,0x17,0x0,0x1b,0x0,0x8, + 0xb5,0x1b,0x19,0xa,0x0,0x2,0x30,0x2b,0x0,0x16,0x17,0x13,0x16,0x15,0x14,0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x27,0x3,0x26,0x35,0x34,0x37,0x1,0x36, + 0x36,0x33,0x1,0x13,0x1,0x3,0x3,0x16,0x29,0xd,0xd0,0x4,0xf,0xfe,0x89,0x1a,0x33,0x29,0x29,0x27,0xe,0xd2,0x4,0xf,0x1,0x79,0x19,0x33,0x29,0xfe, + 0xa6,0xa9,0x1,0x43,0xaa,0x4,0xb9,0x1e,0x23,0xfd,0xe9,0xe,0x6,0x14,0x14,0xfe,0x6,0x23,0x1e,0x1e,0x23,0x2,0x16,0xe,0x6,0x15,0x13,0x1,0xfb,0x23, + 0x1e,0xfd,0x98,0xfe,0x4d,0x1,0xb3,0x1,0xb4,0x0,0x0,0x1,0x1,0x95,0xfe,0x61,0x3,0x4c,0x5,0x36,0x0,0x11,0x0,0x20,0x40,0x1d,0xb,0x2,0x2,0x0, + 0x1,0x1,0x4a,0x2,0x1,0x1,0x1,0x10,0x4b,0x0,0x0,0x0,0x13,0x0,0x4c,0x0,0x0,0x0,0x11,0x0,0x10,0x27,0x3,0x7,0x15,0x2b,0x0,0x16,0x15,0x14, + 0x7,0x1,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x3,0x2e,0x1e,0x2,0xfe,0xe3,0x6,0x27,0x2a,0x23,0x1e,0x2,0x1,0x1d,0x6,0x27, + 0x2a,0x5,0x36,0x15,0x18,0x4,0x10,0xf9,0xad,0x23,0x1e,0x15,0x18,0x4,0x10,0x6,0x53,0x23,0x1e,0x0,0x0,0x2,0x1,0x95,0xfe,0x61,0x3,0x4c,0x5,0x36, + 0x0,0x11,0x0,0x23,0x0,0x3d,0x40,0x3a,0xb,0x2,0x2,0x0,0x1,0x1d,0x14,0x2,0x2,0x3,0x2,0x4a,0x0,0x0,0x1,0x3,0x1,0x0,0x3,0x70,0x5,0x1, + 0x3,0x2,0x1,0x3,0x2,0x6e,0x4,0x1,0x1,0x1,0x10,0x4b,0x0,0x2,0x2,0x13,0x2,0x4c,0x12,0x12,0x0,0x0,0x12,0x23,0x12,0x22,0x1b,0x19,0x0,0x11, + 0x0,0x10,0x27,0x6,0x7,0x15,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x2,0x16,0x15,0x14,0x7, + 0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x3,0x2e,0x1e,0x2,0x6d,0x6,0x27,0x29,0x23,0x1f,0x2,0x6d,0x6,0x27,0x2a,0x8e,0x1f, + 0x2,0x6d,0x6,0x27,0x2a,0x23,0x1e,0x2,0x6d,0x6,0x27,0x29,0x5,0x36,0x15,0x18,0x4,0x10,0xfd,0x95,0x23,0x1e,0x15,0x18,0x6,0xe,0x2,0x6b,0x23,0x1e, + 0xfc,0x18,0x15,0x18,0x6,0xe,0xfd,0x95,0x23,0x1e,0x15,0x18,0x4,0x10,0x2,0x6b,0x23,0x1e,0x0,0x0,0x0,0x2,0x0,0x26,0xff,0x67,0x4,0xb2,0x4,0x36, + 0x0,0x49,0x0,0x57,0x0,0xc2,0x4b,0xb0,0x15,0x50,0x58,0x40,0xf,0x1d,0x16,0x2,0xb,0x2,0xa,0x1,0x4,0xb,0x3c,0x1,0x8,0x6,0x3,0x4a,0x1b,0x40, + 0xf,0x1d,0x16,0x2,0xb,0x3,0xa,0x1,0x4,0xb,0x3c,0x1,0x8,0x6,0x3,0x4a,0x59,0x4b,0xb0,0x15,0x50,0x58,0x40,0x35,0x0,0x7,0x0,0x6,0x0,0x7, + 0x6,0x70,0xc,0x1,0x9,0x0,0x5,0x2,0x9,0x5,0x63,0x3,0x1,0x2,0xd,0x1,0xb,0x4,0x2,0xb,0x63,0xa,0x1,0x4,0x1,0x1,0x0,0x7,0x4,0x0, + 0x64,0x0,0x6,0x8,0x8,0x6,0x57,0x0,0x6,0x6,0x8,0x5b,0x0,0x8,0x6,0x8,0x4f,0x1b,0x40,0x3c,0x0,0x3,0x2,0xb,0x2,0x3,0xb,0x70,0x0,0x7, + 0x0,0x6,0x0,0x7,0x6,0x70,0xc,0x1,0x9,0x0,0x5,0x2,0x9,0x5,0x63,0x0,0x2,0xd,0x1,0xb,0x4,0x2,0xb,0x63,0xa,0x1,0x4,0x1,0x1,0x0, + 0x7,0x4,0x0,0x64,0x0,0x6,0x8,0x8,0x6,0x57,0x0,0x6,0x6,0x8,0x5b,0x0,0x8,0x6,0x8,0x4f,0x59,0x40,0x1a,0x4a,0x4a,0x0,0x0,0x4a,0x57,0x4a, + 0x56,0x51,0x4f,0x0,0x49,0x0,0x48,0x27,0x32,0x25,0x25,0x2a,0x23,0x25,0x24,0x26,0xe,0x7,0x1d,0x2b,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26, + 0x27,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x17,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x3,0x6,0x15,0x14,0x16,0x33,0x32,0x36, + 0x36,0x35,0x34,0x26,0x23,0x22,0x4,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35, + 0x34,0x12,0x24,0x33,0x2,0x6,0x6,0x15,0x14,0x16,0x33,0x32,0x36,0x36,0x35,0x34,0x26,0x23,0x3,0x87,0xc3,0x68,0x58,0xa1,0x6a,0x40,0x4e,0xe,0x3b,0x6d, + 0x3d,0x42,0x56,0x78,0xba,0x5c,0x56,0x18,0x2a,0x9,0x12,0xe,0x13,0x21,0x2,0x82,0x12,0x20,0x1d,0x45,0x63,0x32,0xad,0x9c,0xa5,0xfe,0xf0,0x9b,0xa6,0x9d, + 0x45,0x89,0x38,0x8,0x4,0x19,0x9,0x3,0x19,0x3a,0x9c,0x51,0x89,0xc5,0x67,0xc0,0x1,0x50,0xcc,0x83,0x70,0x4f,0x1c,0x18,0x3b,0x70,0x48,0x20,0x1d,0x4, + 0x36,0x6e,0xc6,0x81,0x80,0xe8,0x90,0x43,0x3f,0x43,0x44,0x5b,0x50,0x5e,0xe5,0x9f,0x64,0x3f,0xc,0x8,0xd,0x16,0x7,0x4,0xfe,0xd2,0x2c,0x21,0x1e,0x22, + 0x75,0xad,0x51,0x97,0xaa,0xcb,0xfe,0xc7,0x9d,0x94,0xa4,0x14,0x11,0x2,0x2c,0xe,0xa,0x20,0xa,0x18,0x1c,0x66,0xbf,0x82,0xc8,0x1,0x76,0xea,0xfe,0x5c, + 0x6f,0x9d,0x3f,0x1f,0x1e,0x75,0x9d,0x32,0x21,0x23,0x0,0x2,0x0,0x8c,0xff,0xea,0x4,0x43,0x4,0xf5,0x0,0x3b,0x0,0x43,0x0,0x41,0x40,0x3e,0x3e,0x3d, + 0x34,0x19,0x10,0x6,0x6,0x6,0x5,0x1,0x4a,0x0,0x3,0x4,0x5,0x4,0x3,0x5,0x70,0x0,0x5,0x6,0x4,0x5,0x6,0x6e,0x0,0x2,0x0,0x4,0x3,0x2, + 0x4,0x63,0x7,0x1,0x6,0x6,0x0,0x5b,0x1,0x1,0x0,0x0,0x17,0x0,0x4c,0x3c,0x3c,0x3c,0x43,0x3c,0x42,0x1a,0x24,0x17,0x2b,0x23,0x2c,0x8,0x7,0x1a, + 0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x7,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x27,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x37,0x26,0x35,0x34, + 0x36,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x17,0x13,0x36,0x37,0x36,0x36,0x33,0x32, + 0x17,0x0,0x37,0x3,0x6,0x15,0x14,0x16,0x33,0x4,0x29,0x1a,0xa,0x55,0x65,0x76,0xe,0x2f,0x20,0x17,0x19,0x12,0x59,0xa0,0xbf,0x5f,0x89,0x46,0x8e,0x7d, + 0x3d,0x5e,0xb3,0x7a,0x55,0xa1,0x3e,0x19,0x16,0x1c,0x1b,0xd,0x11,0x34,0x77,0x3e,0x42,0x6a,0x3c,0x48,0xe7,0x47,0x3d,0xb,0x1d,0x16,0xd,0x17,0xfe,0x3d, + 0x7b,0xde,0xbd,0x54,0x4a,0x2,0x9a,0x15,0x11,0xe,0x17,0xcb,0x88,0xa0,0x13,0xf,0x1c,0x19,0x12,0x18,0x7a,0x9b,0x4e,0x85,0x52,0x7c,0xbf,0x4c,0x6a,0x73, + 0x65,0xb1,0x6c,0x31,0x28,0x10,0x18,0x18,0x20,0x2a,0xa,0x20,0x25,0x3d,0x6e,0x46,0x60,0x61,0xfe,0xc7,0x6a,0x96,0x1a,0x17,0x5,0xfd,0xdc,0x7b,0x1,0x2e, + 0x70,0x9d,0x49,0x53,0x0,0x1,0x0,0xcd,0xfe,0x66,0x4,0xde,0x4,0xa3,0x0,0x26,0x0,0x37,0x40,0x34,0x2,0x1,0x0,0x5,0x1a,0xf,0x2,0x1,0x4,0x2, + 0x4a,0x0,0x4,0x0,0x1,0x0,0x4,0x1,0x70,0x2,0x1,0x0,0x0,0x5,0x59,0x6,0x1,0x5,0x5,0xe,0x4b,0x3,0x1,0x1,0x1,0x13,0x1,0x4c,0x0,0x0, + 0x0,0x26,0x0,0x24,0x15,0x23,0x15,0x23,0x26,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34, + 0x37,0x13,0x23,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x2e,0x2,0x35,0x34,0x36,0x36,0x33,0x21,0x4,0xc4,0x1a,0x3,0x7,0x23,0x22,0x44,0xf4, + 0x6,0x27,0x2a,0x23,0x1e,0x2,0xf4,0xa0,0xf4,0x6,0x27,0x2a,0x23,0x1e,0x2,0x95,0x67,0x99,0x53,0x6b,0xd5,0x98,0x2,0x4,0x4,0xa3,0x16,0x18,0xb,0xf, + 0x27,0x21,0xfa,0x94,0x23,0x1e,0x15,0x18,0x4,0x10,0x5,0x6c,0xfa,0x94,0x23,0x1e,0x15,0x18,0x4,0x10,0x3,0x4f,0x3,0x47,0x80,0x55,0x6b,0xb6,0x6d,0x0, + 0x0,0x3,0x0,0x3d,0xff,0xea,0x4,0xd3,0x4,0xb9,0x0,0xf,0x0,0x1f,0x0,0x50,0x0,0x6d,0xb1,0x6,0x64,0x44,0x40,0x62,0x24,0x1,0x5,0x9,0x1,0x4a, + 0x0,0x4,0x5,0x7,0x5,0x4,0x7,0x70,0x0,0x7,0x6,0x5,0x7,0x6,0x6e,0xa,0x1,0x1,0xb,0x1,0x3,0x9,0x1,0x3,0x63,0xc,0x1,0x9,0x0,0x5, + 0x4,0x9,0x5,0x63,0x0,0x6,0x0,0x8,0x2,0x6,0x8,0x63,0x0,0x2,0x0,0x0,0x2,0x57,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x20,0x20, + 0x10,0x10,0x0,0x0,0x20,0x50,0x20,0x4f,0x47,0x45,0x3c,0x3a,0x37,0x35,0x2e,0x2c,0x28,0x27,0x10,0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0xd, + 0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x16,0x15,0x14,0x2,0x4,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0x6,0x4,0x2,0x15,0x14,0x16,0x16, + 0x33,0x32,0x36,0x12,0x35,0x34,0x26,0x26,0x23,0x16,0x16,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x27,0x26,0x26,0x23,0x22,0x6,0x7,0x6,0x6,0x15,0x14, + 0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x6,0x7,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x37,0x36,0x36,0x33,0x3,0x7a, + 0xdf,0x7a,0xb9,0xfe,0xc6,0xb7,0x92,0xe0,0x7a,0xba,0x1,0x3a,0xb7,0x9b,0xff,0x1,0x98,0x5c,0xab,0x74,0x94,0xfe,0x97,0x5b,0xab,0x74,0x17,0x59,0x27,0x24, + 0xa,0x13,0x1e,0xe,0xe,0x22,0x3e,0x26,0x2e,0x51,0x1f,0x20,0x24,0x52,0x43,0x26,0x43,0x28,0xf,0xe,0xe,0x13,0x7,0x5,0x15,0x18,0x2d,0x61,0x2d,0x4f, + 0x7a,0x43,0x39,0x37,0x31,0x84,0x4d,0x4,0xb9,0x84,0xe5,0x8f,0xc4,0xfe,0xb2,0xc5,0x84,0xe7,0x8f,0xc4,0x1,0x4d,0xc4,0x78,0xa0,0xfe,0xec,0xa6,0x73,0xb0, + 0x62,0xa1,0x1,0x15,0xa6,0x72,0xb0,0x61,0x98,0x15,0x13,0x13,0x1d,0x11,0x14,0x28,0x7,0x11,0xf,0x26,0x26,0x27,0x6b,0x36,0x4d,0x53,0xf,0x11,0x7,0x14, + 0x16,0x12,0xc,0x12,0x19,0xa,0x13,0x15,0x43,0x7e,0x54,0x51,0xa4,0x3a,0x35,0x37,0x0,0x0,0x0,0x4,0x0,0x3d,0xff,0xea,0x4,0xd3,0x4,0xb9,0x0,0xf, + 0x0,0x1f,0x0,0x40,0x0,0x49,0x0,0x70,0xb1,0x6,0x64,0x44,0x40,0x65,0x26,0x1,0x5,0x8,0x39,0x1,0x4,0x5,0x2,0x4a,0x6,0x1,0x4,0x5,0x2,0x5, + 0x4,0x2,0x70,0xa,0x1,0x1,0xb,0x1,0x3,0x7,0x1,0x3,0x63,0xc,0x1,0x7,0xd,0x1,0x9,0x8,0x7,0x9,0x63,0x0,0x8,0x0,0x5,0x4,0x8,0x5, + 0x61,0x0,0x2,0x0,0x0,0x2,0x57,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x41,0x41,0x20,0x20,0x10,0x10,0x0,0x0,0x41,0x49,0x41,0x48,0x44, + 0x42,0x20,0x40,0x20,0x3e,0x37,0x35,0x32,0x31,0x2e,0x2c,0x10,0x1f,0x10,0x1e,0x18,0x16,0x0,0xf,0x0,0xe,0x26,0xe,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44, + 0x0,0x16,0x16,0x15,0x14,0x2,0x4,0x23,0x22,0x26,0x26,0x35,0x34,0x12,0x24,0x33,0x6,0x4,0x2,0x15,0x14,0x16,0x16,0x33,0x32,0x36,0x12,0x35,0x34,0x26, + 0x26,0x23,0x1e,0x2,0x15,0x14,0x6,0x7,0x17,0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x27,0x23,0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13, + 0x36,0x36,0x33,0x33,0x7,0x7,0x33,0x32,0x36,0x35,0x34,0x26,0x23,0x3,0x7a,0xdf,0x7a,0xb9,0xfe,0xc6,0xb7,0x92,0xe0,0x7a,0xba,0x1,0x3a,0xb7,0x9b,0xff, + 0x1,0x98,0x5c,0xab,0x74,0x94,0xfe,0x97,0x5b,0xab,0x74,0x2f,0x61,0x35,0x5f,0x57,0x5b,0x10,0x21,0x1b,0x10,0xb,0x10,0x9,0x7c,0x65,0x17,0x6,0x23,0x22, + 0x1c,0x17,0x2,0x5b,0x6,0x24,0x22,0xb1,0x8a,0x26,0x6a,0x4c,0x4f,0x36,0x36,0x4,0xb9,0x84,0xe5,0x8f,0xc4,0xfe,0xb2,0xc5,0x84,0xe7,0x8f,0xc4,0x1,0x4d, + 0xc4,0x78,0xa0,0xfe,0xec,0xa6,0x73,0xb0,0x62,0xa1,0x1,0x15,0xa6,0x72,0xb0,0x61,0xac,0x31,0x57,0x37,0x54,0x7b,0x1c,0x7a,0x16,0x10,0x17,0x17,0x12,0xc, + 0xc,0xb3,0x87,0x23,0x1e,0x13,0x16,0xf,0x9,0x2,0x7,0x22,0x1d,0x75,0xd5,0x4b,0x38,0x27,0x2b,0x0,0x0,0x2,0x0,0xa9,0xff,0x1a,0x4,0x3f,0x4,0xa3, + 0x0,0x37,0x0,0x47,0x0,0x33,0x40,0x30,0x2,0x1,0x0,0x3,0x42,0x3a,0x2,0x2,0x0,0x1e,0x1,0x1,0x2,0x3,0x4a,0x0,0x2,0x0,0x1,0x2,0x1,0x5d, + 0x0,0x0,0x0,0x3,0x59,0x4,0x1,0x3,0x3,0xe,0x0,0x4c,0x0,0x0,0x0,0x37,0x0,0x35,0x25,0x22,0x1c,0x19,0x36,0x5,0x7,0x15,0x2b,0x0,0x16,0x15, + 0x14,0x7,0x6,0x6,0x23,0x21,0x22,0x6,0x15,0x14,0x16,0x17,0x5,0x16,0x16,0x15,0x14,0x6,0x7,0x16,0x15,0x14,0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37, + 0x36,0x36,0x33,0x21,0x32,0x36,0x35,0x34,0x26,0x27,0x25,0x26,0x26,0x35,0x34,0x36,0x37,0x26,0x35,0x34,0x36,0x33,0x21,0x1,0x26,0x27,0x6,0x6,0x15,0x14, + 0x17,0x5,0x16,0x17,0x36,0x36,0x35,0x34,0x27,0x4,0x25,0x1a,0x3,0x7,0x22,0x22,0xfe,0xce,0x51,0x51,0x20,0x23,0x1,0x1f,0x3f,0x42,0x52,0x51,0x7,0xa2, + 0x94,0xfe,0xb0,0x1b,0x1a,0x3,0x7,0x22,0x22,0x1,0x32,0x51,0x51,0x20,0x23,0xfe,0xe1,0x3f,0x42,0x52,0x51,0x7,0xa2,0x94,0x1,0x50,0xfd,0xec,0x1a,0x10, + 0x25,0x27,0x49,0x1,0x29,0x1a,0x10,0x25,0x27,0x49,0x4,0xa3,0x15,0x18,0xc,0xf,0x27,0x21,0x43,0x3f,0x21,0x34,0x18,0xc8,0x2c,0x75,0x46,0x59,0x7a,0x2e, + 0x23,0x1c,0x83,0x98,0x15,0x18,0xc,0xf,0x27,0x21,0x43,0x3e,0x21,0x34,0x19,0xc8,0x2c,0x75,0x46,0x59,0x7a,0x2e,0x1b,0x23,0x84,0x98,0xfe,0x10,0x13,0x10, + 0x18,0x3f,0x2d,0x48,0x32,0xce,0x13,0x10,0x18,0x3e,0x2d,0x49,0x32,0x0,0x0,0x2,0x0,0xd0,0x2,0xec,0x5,0x71,0x5,0x2a,0x0,0x28,0x0,0x45,0x0,0x8, + 0xb5,0x34,0x29,0x6,0x0,0x2,0x30,0x2b,0x0,0x16,0x15,0x7,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x7,0x6,0x23,0x22,0x26,0x27,0x27,0x3, + 0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x32,0x16,0x17,0x13,0x13,0x36,0x33,0x4,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6, + 0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x5,0x52,0x1f,0x1,0x30,0x4,0x1f,0x22,0x1d,0x17,0x1,0x1c, + 0x7f,0x21,0x2e,0x17,0x23,0x7,0x3c,0x3f,0x8,0x21,0x22,0x1a,0x17,0x4,0x6c,0x8,0x23,0x22,0x19,0x1b,0x4,0x59,0xc3,0x10,0x34,0xfd,0x83,0x1a,0x2,0x6, + 0x21,0x22,0x81,0x43,0x6,0x22,0x22,0x1c,0x18,0x2,0x43,0x81,0x1d,0x1a,0x2,0x6,0x22,0x22,0x1,0x7e,0x5,0x2a,0x19,0x1b,0xd,0xfe,0x44,0x23,0x1e,0x16, + 0x18,0xc,0x7,0x1,0x3,0xc0,0x30,0x19,0x17,0xc0,0xfe,0xfd,0x23,0x1e,0x11,0x13,0xe,0xf,0x1,0xbc,0x23,0x1e,0xc,0xe,0xfe,0xd5,0x1,0x2b,0x1a,0xa, + 0x12,0x16,0x4,0x10,0x21,0x1a,0xfe,0x84,0x23,0x1e,0x14,0x16,0xe,0x9,0x1,0x7c,0x12,0x15,0x6,0xe,0x21,0x1b,0x0,0x0,0x0,0x2,0x1,0x51,0x2,0x89, + 0x3,0x85,0x4,0xb9,0x0,0xf,0x0,0x1d,0x0,0x37,0xb1,0x6,0x64,0x44,0x40,0x2c,0x4,0x1,0x1,0x5,0x1,0x3,0x2,0x1,0x3,0x63,0x0,0x2,0x0,0x0, + 0x2,0x57,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x10,0x10,0x0,0x0,0x10,0x1d,0x10,0x1c,0x17,0x15,0x0,0xf,0x0,0xe,0x26,0x6,0x7,0x15, + 0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x22,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0xe,0x2,0x15,0x14,0x16,0x33,0x32,0x36,0x36, + 0x35,0x34,0x26,0x23,0x2,0xd2,0x71,0x42,0x50,0x90,0x5b,0x45,0x72,0x42,0x50,0x91,0x5b,0x3c,0x4d,0x2c,0x43,0x3b,0x30,0x4c,0x2c,0x43,0x3a,0x4,0xb9,0x3e, + 0x6f,0x47,0x54,0x91,0x57,0x3f,0x6f,0x47,0x52,0x91,0x58,0x87,0x30,0x50,0x2c,0x34,0x42,0x30,0x4f,0x2d,0x34,0x42,0x0,0x1,0x1,0x4,0x1,0xf6,0x4,0x1, + 0x4,0xb9,0x0,0x1c,0x0,0x27,0xb1,0x6,0x64,0x44,0x40,0x1c,0xd,0x1,0x0,0x2,0x1,0x4a,0x3,0x1,0x2,0x0,0x2,0x72,0x1,0x1,0x0,0x0,0x69,0x0, + 0x0,0x0,0x1c,0x0,0x1b,0x15,0x29,0x4,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x17,0x13,0x16,0x15,0x14,0x6,0x7,0x6,0x23,0x22,0x27,0x3,0x1, + 0x6,0x6,0x23,0x22,0x27,0x26,0x26,0x35,0x34,0x37,0x1,0x36,0x36,0x33,0x3,0x11,0x1a,0x7,0xcc,0x3,0x1f,0x17,0x14,0x16,0x27,0x8,0x9a,0xfe,0xc0,0x8, + 0x21,0x14,0x12,0x12,0x16,0x1d,0xa,0x1,0x9c,0xe,0x21,0x1c,0x4,0xb9,0x12,0x13,0xfd,0xb1,0x7,0x8,0x12,0x1e,0x8,0x7,0x18,0x1,0xe0,0xfe,0x20,0xd, + 0xc,0x5,0x6,0x19,0x10,0xd,0xe,0x2,0x4f,0x13,0x12,0x0,0x0,0x1,0x1,0x6f,0x1,0x19,0x3,0xfc,0x4,0xb9,0x0,0x27,0x0,0x38,0x40,0x35,0x2,0x1, + 0x0,0x5,0x1d,0x9,0x2,0x1,0x0,0x16,0x1,0x2,0x1,0x3,0x4a,0x0,0x2,0x1,0x2,0x73,0x6,0x1,0x5,0x5,0x16,0x4b,0x3,0x1,0x1,0x1,0x0,0x59, + 0x4,0x1,0x0,0x0,0x11,0x1,0x4c,0x0,0x0,0x0,0x27,0x0,0x26,0x26,0x25,0x23,0x26,0x25,0x7,0x7,0x19,0x2b,0x0,0x16,0x15,0x14,0x7,0x7,0x33,0x32, + 0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x3,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x36, + 0x36,0x33,0x3,0x14,0x20,0x2,0x28,0xbd,0x1c,0x19,0x2,0x7,0x23,0x22,0xbd,0x4d,0x6,0x24,0x27,0x21,0x20,0x2,0x4d,0xbd,0x1b,0x1a,0x3,0x7,0x22,0x22, + 0xbd,0x28,0x6,0x24,0x27,0x4,0xb9,0x15,0x18,0x4,0xe,0xde,0x16,0x19,0xf,0xa,0x27,0x21,0xfe,0x4c,0x22,0x1d,0x15,0x18,0x4,0xe,0x1,0xb4,0x16,0x18, + 0xb,0xf,0x27,0x21,0xde,0x22,0x1d,0x0,0x0,0x1,0x1,0x36,0x0,0xdd,0x4,0x5,0x4,0xb9,0x0,0x3d,0x0,0xf6,0x40,0x14,0x2,0x1,0x0,0x9,0x33,0x9, + 0x2,0x1,0x0,0x28,0x14,0x2,0x3,0x2,0x21,0x1,0x4,0x3,0x4,0x4a,0x4b,0xb0,0xc,0x50,0x58,0x40,0x21,0x0,0x4,0x3,0x3,0x4,0x67,0x8,0x1,0x0, + 0x7,0x1,0x1,0x2,0x0,0x1,0x62,0x6,0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9,0x16,0x9,0x4c,0x1b,0x4b,0xb0,0xe,0x50,0x58, + 0x40,0x22,0x0,0x4,0x3,0x4,0x73,0x6,0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9,0x16,0x4b,0x7,0x1,0x1,0x1,0x0,0x59,0x8, + 0x1,0x0,0x0,0x11,0x1,0x4c,0x1b,0x4b,0xb0,0x10,0x50,0x58,0x40,0x20,0x0,0x4,0x3,0x4,0x73,0x8,0x1,0x0,0x7,0x1,0x1,0x2,0x0,0x1,0x62,0x6, + 0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9,0x16,0x9,0x4c,0x1b,0x4b,0xb0,0x15,0x50,0x58,0x40,0x22,0x0,0x4,0x3,0x4,0x73,0x6, + 0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9,0x16,0x4b,0x7,0x1,0x1,0x1,0x0,0x59,0x8,0x1,0x0,0x0,0x11,0x1,0x4c,0x1b,0x40, + 0x20,0x0,0x4,0x3,0x4,0x73,0x8,0x1,0x0,0x7,0x1,0x1,0x2,0x0,0x1,0x62,0x6,0x1,0x2,0x5,0x1,0x3,0x4,0x2,0x3,0x61,0xa,0x1,0x9,0x9, + 0x16,0x9,0x4c,0x59,0x59,0x59,0x59,0x40,0x12,0x0,0x0,0x0,0x3d,0x0,0x3c,0x26,0x21,0x26,0x25,0x23,0x26,0x21,0x26,0x25,0xb,0x7,0x1d,0x2b,0x0,0x16, + 0x15,0x14,0x7,0x7,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x7,0x33,0x32,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x23,0x7,0x6,0x6,0x23,0x22, + 0x26,0x35,0x34,0x37,0x37,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x23,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x33,0x37,0x36,0x36,0x33, + 0x3,0x14,0x20,0x2,0x1f,0xbd,0x1c,0x19,0x2,0x8,0x22,0x22,0xbd,0x29,0xbd,0x1c,0x19,0x2,0x8,0x22,0x22,0xbd,0x1e,0x6,0x25,0x27,0x21,0x1f,0x2,0x1e, + 0xbd,0x1b,0x1a,0x3,0x7,0x22,0x22,0xbd,0x29,0xbd,0x1b,0x1a,0x3,0x7,0x22,0x22,0xbd,0x1f,0x6,0x24,0x27,0x4,0xb9,0x15,0x18,0x4,0xe,0xac,0x16,0x19, + 0xf,0xa,0x27,0x21,0xe6,0x16,0x19,0xf,0xa,0x27,0x21,0xac,0x22,0x1d,0x15,0x18,0x4,0xe,0xac,0x15,0x18,0xc,0xf,0x27,0x21,0xe6,0x15,0x18,0xc,0xf, + 0x27,0x21,0xac,0x22,0x1d,0x0,0x0,0x0,0x0,0x1,0xfc,0x66,0xfd,0xf3,0xfd,0xae,0xff,0x6e,0x0,0x11,0x0,0x1f,0xb1,0x6,0x64,0x44,0x40,0x14,0xe,0x1, + 0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x37,0x21,0x2,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x0,0x6,0x23,0x22,0x26,0x35,0x34, + 0x37,0x13,0x36,0x36,0x33,0x33,0x32,0x15,0x14,0x7,0x3,0xfc,0xd2,0x28,0x17,0x16,0x17,0x4,0x6e,0x6,0x19,0x11,0x8e,0x18,0xb,0xc6,0xfe,0x7,0x14,0x12, + 0x11,0xa,0xb,0x1,0x23,0x10,0x10,0x15,0xf,0xf,0xfe,0xdd,0x0,0x0,0xff,0xff,0xfc,0x66,0xfd,0xf3,0xfd,0xae,0xff,0x6e,0x0,0x2,0x1,0x7e,0x0,0x0, + 0x0,0x1,0x2,0x13,0x4,0xd,0x4,0x48,0x5,0x5e,0x0,0x13,0x0,0x17,0xb1,0x6,0x64,0x44,0x40,0xc,0x10,0x1,0x0,0x47,0x0,0x0,0x0,0x69,0x20,0x1, + 0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x25,0x3,0xdd,0xe, + 0x10,0x21,0x13,0x19,0x19,0xfe,0x1f,0x8,0x4,0xe,0x18,0x5,0x4,0x17,0x1,0xa0,0x5,0x5e,0x1e,0x23,0x2c,0x1c,0x1b,0x8,0xa3,0x2,0x13,0xf,0x9,0xd, + 0x1b,0xd,0xe6,0x0,0x0,0x0,0x0,0x1,0x1,0x53,0x3,0x5e,0x2,0xbf,0x5,0x20,0x0,0x11,0x0,0x13,0x40,0x10,0x0,0x0,0x1,0x0,0x73,0x0,0x1,0x1, + 0x10,0x1,0x4c,0x27,0x26,0x2,0x7,0x16,0x2b,0x0,0x16,0x15,0x14,0x7,0x3,0x6,0x23,0x22,0x26,0x35,0x34,0x37,0x13,0x36,0x36,0x33,0x33,0x2,0xaf,0x10, + 0x8,0xf4,0x14,0x25,0x19,0x1e,0x4,0x93,0x6,0x12,0x12,0x8e,0x5,0x20,0x11,0xd,0xc,0xe,0xfe,0x94,0x1e,0x18,0x13,0x6,0xc,0x1,0x6a,0xf,0xc,0x0, + 0x0,0x1,0x1,0x8f,0x4,0x2f,0x4,0x85,0x5,0x4e,0x0,0x1c,0x0,0x2e,0xb1,0x6,0x64,0x44,0x40,0x23,0xa,0x1,0x2,0x1,0x1,0x4a,0x3,0x1,0x1,0x2, + 0x1,0x72,0x0,0x2,0x0,0x0,0x2,0x57,0x0,0x2,0x2,0x0,0x5b,0x0,0x0,0x2,0x0,0x4f,0x13,0x24,0x26,0x26,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44, + 0x0,0x16,0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x26,0x27,0x26,0x36,0x37,0x36,0x33,0x32,0x16,0x17,0x16,0x16,0x33,0x32,0x36,0x37,0x36,0x33,0x32,0x17,0x4, + 0x71,0x14,0x3,0x2c,0xd5,0x98,0x99,0xb5,0xb,0x1,0x19,0x13,0xe,0xd,0xc,0x13,0x4,0x1a,0x79,0x68,0x69,0x89,0x2d,0xe,0x1f,0x12,0xf,0x5,0x42,0x16, + 0xd,0x5,0x8,0x6a,0x79,0x7a,0x69,0x12,0x1d,0x7,0x6,0xa,0xa,0x42,0x39,0x39,0x42,0x14,0x6,0x0,0x0,0x1,0x1,0xab,0x4,0xd,0x4,0x62,0x5,0x64, + 0x0,0x19,0x0,0x20,0xb1,0x6,0x64,0x44,0x40,0x15,0x18,0x1,0x2,0x0,0x1,0x1,0x4a,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x28,0x2a,0x2,0x7, + 0x16,0x2b,0xb1,0x6,0x0,0x44,0x0,0x33,0x32,0x16,0x17,0x16,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17, + 0x17,0x25,0x4,0x2b,0x8,0xd,0x16,0x6,0x6,0x14,0xfe,0xcc,0x19,0x21,0x20,0x14,0xf6,0xb,0xb,0x8,0x16,0xb,0x9,0x9,0xfc,0x1,0x32,0x5,0x63,0xf, + 0xc,0xc,0xe,0x17,0x10,0xe8,0x12,0x12,0xe8,0xb,0x12,0x14,0x11,0xc,0xf,0x6,0x9f,0x9f,0x0,0x0,0xff,0xff,0x2,0x3b,0x5,0x1b,0x4,0x70,0x6,0x6c, + 0x1,0x7,0x1,0x80,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xb7,0x5,0x3d,0x4,0xad, + 0x6,0x5c,0x1,0x7,0x1,0x82,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xd3,0x5,0x1b, + 0x4,0x8a,0x6,0x72,0x1,0x7,0x1,0x83,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x0,0xde, + 0xfe,0x28,0x2,0xef,0x0,0x1c,0x0,0x2,0x1,0x91,0x0,0x0,0xff,0xff,0x1,0xae,0x5,0x17,0x4,0x65,0x6,0x6e,0x1,0x7,0x1,0x92,0x0,0x28,0x1,0xe, + 0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xc0,0x5,0x3c,0x4,0x74,0x6,0x36,0x1,0x7,0x1,0x93,0x0,0x28, + 0x1,0xe,0x0,0x9,0xb1,0x0,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x2,0x8f,0x5,0x45,0x3,0xad,0x6,0x5f,0x1,0x7,0x1,0x94, + 0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xb8,0x5,0x1b,0x3,0xed,0x6,0x6c,0x1,0x7, + 0x1,0x95,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xe1,0x5,0x2b,0x5,0x4,0x6,0x77, + 0x1,0x7,0x1,0x96,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xbd,0x5,0x60,0x4,0x72, + 0x5,0xf0,0x1,0x7,0x1,0x97,0x0,0x28,0x1,0xe,0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0x25,0xfe,0x28, + 0x2,0xbd,0x0,0x1c,0x0,0x2,0x1,0x98,0x0,0x0,0xff,0xff,0x2,0x3a,0x5,0x37,0x4,0x29,0x7,0x23,0x1,0x7,0x1,0x99,0x0,0x28,0x1,0xe,0x0,0x9, + 0xb1,0x0,0x2,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0xff,0xff,0x1,0xbe,0x5,0x4c,0x4,0x74,0x6,0x1f,0x1,0x7,0x1,0x9a,0x0,0x28,0x1,0xe, + 0x0,0x9,0xb1,0x0,0x1,0xb8,0x1,0xe,0xb0,0x33,0x2b,0x0,0x0,0x0,0x0,0x1,0x0,0xde,0xfe,0x28,0x2,0xef,0x0,0x1c,0x0,0x23,0x0,0x75,0xb1,0x6, + 0x64,0x44,0xb5,0x1f,0x1,0x4,0x0,0x1,0x4a,0x4b,0xb0,0x13,0x50,0x58,0x40,0x27,0x0,0x0,0x5,0x4,0x5,0x0,0x68,0x0,0x2,0x4,0x3,0x4,0x2,0x3, + 0x70,0x0,0x5,0x0,0x4,0x2,0x5,0x4,0x63,0x0,0x3,0x1,0x1,0x3,0x57,0x0,0x3,0x3,0x1,0x5b,0x0,0x1,0x3,0x1,0x4f,0x1b,0x40,0x28,0x0,0x0, + 0x5,0x4,0x5,0x0,0x4,0x70,0x0,0x2,0x4,0x3,0x4,0x2,0x3,0x70,0x0,0x5,0x0,0x4,0x2,0x5,0x4,0x63,0x0,0x3,0x1,0x1,0x3,0x57,0x0,0x3, + 0x3,0x1,0x5b,0x0,0x1,0x3,0x1,0x4f,0x59,0x40,0x9,0x14,0x33,0x23,0x28,0x26,0x10,0x6,0x7,0x1a,0x2b,0xb1,0x6,0x0,0x44,0x5,0x36,0x16,0x15,0x14, + 0x6,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x16,0x16,0x33,0x32,0x36,0x35,0x34,0x23,0x7,0x22,0x35,0x34,0x37,0x37, + 0x33,0x2,0x3d,0x58,0x5a,0x1c,0x1a,0x45,0x97,0x44,0x7c,0x2e,0x11,0xa,0x9,0x19,0xe,0x7,0x4,0x26,0x64,0x31,0x3a,0x3a,0x67,0x23,0x1d,0x1,0x23,0x87, + 0x72,0x2,0x52,0x40,0x22,0x4f,0x1b,0x4a,0x18,0x18,0x8,0x18,0x15,0x11,0x11,0x15,0x2,0xf,0x13,0x2d,0x24,0x37,0x1,0x1c,0x9,0x5,0xcb,0x0,0x0,0x1, + 0x1,0x86,0x4,0x9,0x4,0x3d,0x5,0x60,0x0,0x19,0x0,0x20,0xb1,0x6,0x64,0x44,0x40,0x15,0x18,0x1,0x2,0x1,0x0,0x1,0x4a,0x0,0x0,0x1,0x0,0x72, + 0x0,0x1,0x1,0x69,0x28,0x2a,0x2,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x0,0x23,0x22,0x26,0x27,0x26,0x35,0x34,0x37,0x25,0x36,0x33,0x32,0x17,0x17,0x16, + 0x15,0x14,0x7,0x6,0x6,0x23,0x22,0x27,0x27,0x5,0x1,0xbd,0x8,0xd,0x16,0x6,0x6,0x14,0x1,0x34,0x1a,0x20,0x21,0x13,0xf6,0xb,0xb,0x8,0x16,0xb, + 0x9,0x9,0xfc,0xfe,0xce,0x4,0xa,0xf,0xc,0xc,0xe,0x17,0x10,0xe8,0x12,0x12,0xe8,0xb,0x12,0x14,0x11,0xc,0xf,0x6,0x9f,0x9f,0x0,0x0,0x0,0x2, + 0x1,0x98,0x4,0x2e,0x4,0x4c,0x5,0x28,0x0,0xd,0x0,0x1b,0x0,0x32,0xb1,0x6,0x64,0x44,0x40,0x27,0x2,0x1,0x0,0x1,0x1,0x0,0x57,0x2,0x1,0x0, + 0x0,0x1,0x5b,0x5,0x3,0x4,0x3,0x1,0x0,0x1,0x4f,0xe,0xe,0x0,0x0,0xe,0x1b,0xe,0x1a,0x15,0x13,0x0,0xd,0x0,0xc,0x25,0x6,0x7,0x15,0x2b, + 0xb1,0x6,0x0,0x44,0x0,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x6,0x6,0x23,0x20,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x6, + 0x6,0x23,0x1,0xd5,0x3d,0x29,0x43,0x25,0x2f,0x3c,0x29,0x42,0x25,0x1,0x89,0x3d,0x29,0x43,0x25,0x2f,0x3c,0x29,0x42,0x25,0x4,0x2e,0x3e,0x2e,0x25,0x42, + 0x27,0x3e,0x2d,0x27,0x42,0x26,0x3e,0x2e,0x25,0x42,0x27,0x3e,0x2d,0x27,0x42,0x26,0x0,0x0,0x0,0x1,0x2,0x67,0x4,0x37,0x3,0x85,0x5,0x51,0x0,0xd, + 0x0,0x26,0xb1,0x6,0x64,0x44,0x40,0x1b,0x0,0x0,0x1,0x1,0x0,0x57,0x0,0x0,0x0,0x1,0x5b,0x2,0x1,0x1,0x0,0x1,0x4f,0x0,0x0,0x0,0xd,0x0, + 0xc,0x25,0x3,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x15,0x14,0x6,0x6,0x23,0x2,0xac,0x45,0x2f,0x4c,0x2a, + 0x34,0x45,0x2e,0x4c,0x2a,0x4,0x37,0x46,0x33,0x2b,0x4a,0x2c,0x46,0x32,0x2c,0x4a,0x2c,0x0,0x0,0x0,0x0,0x1,0x1,0x90,0x4,0xd,0x3,0xc5,0x5,0x5e, + 0x0,0x11,0x0,0x19,0xb1,0x6,0x64,0x44,0x40,0xe,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x0,0x69,0x29,0x13,0x2,0x7,0x16,0x2b,0xb1,0x6,0x0,0x44,0x0, + 0x15,0x14,0x6,0x23,0x22,0x27,0x25,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x32,0x17,0x5,0x3,0xc5,0x1b,0x14,0x4,0x8,0xfe,0x1f,0x19,0x19,0x13,0x21,0x10, + 0xe,0x13,0x1,0xa0,0x4,0x60,0x1b,0x16,0x22,0x2,0xa3,0x8,0x1b,0x1c,0x2c,0x23,0x1e,0xb,0xe6,0x0,0x0,0x0,0x0,0x2,0x1,0xb9,0x4,0x1d,0x4,0xdc, + 0x5,0x69,0x0,0x11,0x0,0x23,0x0,0x26,0xb1,0x6,0x64,0x44,0x40,0x1b,0x1c,0x13,0xa,0x1,0x4,0x0,0x1,0x1,0x4a,0x3,0x1,0x1,0x0,0x1,0x72,0x2, + 0x1,0x0,0x0,0x69,0x27,0x27,0x27,0x25,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x0,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37, + 0x36,0x33,0x32,0x17,0x4,0x15,0x14,0x7,0x5,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x37,0x36,0x33,0x32,0x17,0x3,0x60,0x12,0xfe,0xd3,0x14,0x14,0x16, + 0x14,0x16,0xe,0xf1,0x18,0x1e,0x1d,0x22,0x1,0xaf,0x12,0xfe,0xd3,0x13,0x15,0x16,0x14,0x16,0xe,0xf1,0x18,0x1e,0x1d,0x22,0x5,0x32,0x1a,0x10,0xc,0xd2, + 0xd,0xd,0xd,0x16,0xf,0xe,0xe9,0x16,0x16,0x21,0x1a,0x10,0xc,0xd2,0xd,0xd,0xd,0x16,0xf,0xe,0xe9,0x16,0x16,0x0,0x0,0x1,0x1,0x95,0x4,0x52, + 0x4,0x4a,0x4,0xe2,0x0,0x11,0x0,0x2e,0xb1,0x6,0x64,0x44,0x40,0x23,0xb,0x2,0x2,0x0,0x1,0x1,0x4a,0x2,0x1,0x1,0x0,0x0,0x1,0x55,0x2,0x1, + 0x1,0x1,0x0,0x59,0x0,0x0,0x1,0x0,0x4d,0x0,0x0,0x0,0x11,0x0,0xf,0x36,0x3,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x15,0x14,0x7,0x6, + 0x6,0x23,0x21,0x22,0x26,0x35,0x34,0x37,0x36,0x36,0x33,0x21,0x4,0x30,0x1a,0x3,0x7,0x22,0x22,0xfd,0xce,0x1c,0x19,0x2,0x7,0x23,0x22,0x2,0x32,0x4, + 0xe2,0x16,0x18,0xb,0xf,0x27,0x21,0x16,0x19,0xf,0xa,0x27,0x21,0x0,0x0,0x0,0x0,0x1,0x1,0x25,0xfe,0x28,0x2,0xbd,0x0,0x1c,0x0,0x17,0x0,0x4d, + 0xb1,0x6,0x64,0x44,0x4b,0xb0,0x31,0x50,0x58,0x40,0x17,0x0,0x3,0x0,0x3,0x72,0x1,0x1,0x0,0x2,0x2,0x0,0x57,0x1,0x1,0x0,0x0,0x2,0x5b,0x0, + 0x2,0x0,0x2,0x4f,0x1b,0x40,0x1a,0x0,0x3,0x1,0x3,0x72,0x0,0x1,0x0,0x1,0x72,0x0,0x0,0x2,0x2,0x0,0x57,0x0,0x0,0x0,0x2,0x5b,0x0,0x2, + 0x0,0x2,0x4f,0x59,0xb6,0x15,0x26,0x21,0x24,0x4,0x7,0x18,0x2b,0xb1,0x6,0x0,0x44,0x4,0x6,0x15,0x14,0x16,0x33,0x32,0x37,0x37,0x32,0x15,0x14,0x6, + 0x7,0x6,0x6,0x23,0x22,0x26,0x35,0x34,0x36,0x37,0x33,0x2,0x3b,0x7a,0x22,0x1f,0x33,0x3c,0x8,0x28,0x12,0x13,0x26,0x5e,0x2e,0x4f,0x56,0x78,0x76,0xaa, + 0x47,0x94,0x3a,0x1d,0x1e,0xa,0x1,0x42,0x14,0x19,0x7,0xd,0x10,0x58,0x4a,0x57,0xa5,0x56,0x0,0x2,0x2,0x12,0x4,0x29,0x4,0x1,0x6,0x15,0x0,0xf, + 0x0,0x1d,0x0,0x38,0xb1,0x6,0x64,0x44,0x40,0x2d,0x0,0x0,0x0,0x2,0x3,0x0,0x2,0x63,0x5,0x1,0x3,0x1,0x1,0x3,0x57,0x5,0x1,0x3,0x3,0x1, + 0x5b,0x4,0x1,0x1,0x3,0x1,0x4f,0x10,0x10,0x0,0x0,0x10,0x1d,0x10,0x1c,0x17,0x15,0x0,0xf,0x0,0xe,0x26,0x6,0x7,0x15,0x2b,0xb1,0x6,0x0,0x44, + 0x0,0x26,0x26,0x35,0x34,0x36,0x36,0x33,0x32,0x16,0x16,0x15,0x14,0x6,0x6,0x23,0x3e,0x2,0x35,0x34,0x26,0x23,0x22,0x6,0x6,0x15,0x14,0x16,0x33,0x2, + 0xac,0x62,0x38,0x48,0x80,0x51,0x3c,0x62,0x38,0x48,0x80,0x51,0x31,0x46,0x2b,0x3c,0x2e,0x26,0x46,0x2a,0x3b,0x2e,0x4,0x29,0x3a,0x63,0x3a,0x43,0x81,0x51, + 0x3a,0x63,0x3a,0x45,0x80,0x50,0x78,0x29,0x44,0x27,0x2d,0x3b,0x29,0x45,0x27,0x2d,0x3a,0x0,0x0,0x0,0x0,0x1,0x1,0x96,0x4,0x3e,0x4,0x4c,0x5,0x11, + 0x0,0x23,0x0,0x68,0xb1,0x6,0x64,0x44,0x4b,0xb0,0x22,0x50,0x58,0x40,0x1b,0x0,0x0,0x3,0x2,0x0,0x57,0x6,0x5,0x2,0x1,0x0,0x3,0x2,0x1,0x3, + 0x63,0x0,0x0,0x0,0x2,0x5b,0x4,0x1,0x2,0x0,0x2,0x4f,0x1b,0x40,0x29,0x0,0x1,0x5,0x0,0x5,0x1,0x0,0x70,0x0,0x4,0x3,0x2,0x3,0x4,0x2, + 0x70,0x0,0x0,0x3,0x2,0x0,0x57,0x6,0x1,0x5,0x0,0x3,0x4,0x5,0x3,0x63,0x0,0x0,0x0,0x2,0x5b,0x0,0x2,0x0,0x2,0x4f,0x59,0x40,0xe,0x0, + 0x0,0x0,0x23,0x0,0x22,0x13,0x24,0x26,0x13,0x24,0x7,0x7,0x19,0x2b,0xb1,0x6,0x0,0x44,0x0,0x16,0x17,0x16,0x16,0x33,0x32,0x37,0x36,0x33,0x32,0x17, + 0x16,0x15,0x14,0x7,0x6,0x23,0x22,0x26,0x27,0x26,0x26,0x23,0x22,0x7,0x6,0x23,0x22,0x27,0x26,0x35,0x34,0x37,0x36,0x33,0x2,0x91,0x3b,0x30,0x2d,0x36, + 0x1d,0x41,0x46,0xb,0x9,0x17,0x13,0xb,0x11,0x6d,0x5b,0x22,0x3b,0x30,0x2d,0x36,0x1d,0x40,0x47,0xa,0xa,0x17,0x13,0xb,0x11,0x6d,0x5b,0x5,0x11,0x10, + 0x11,0x10,0xe,0x2a,0x6,0x1f,0x12,0x13,0x18,0xd,0x5b,0x10,0x11,0x10,0xe,0x2a,0x6,0x1f,0x12,0x13,0x18,0xd,0x5b,0x0,0x0,0x0,0x0,0x1,0x0,0x0, + 0x0,0x3,0x4,0x9b,0xed,0xcb,0xa1,0x17,0x5f,0xf,0x3c,0xf5,0x0,0x1,0x8,0x0,0x0,0x0,0x0,0x0,0xd2,0x42,0x4a,0x67,0x0,0x0,0x0,0x0,0xd2,0x42, + 0x4a,0x76,0xfc,0x66,0xfc,0xba,0xc,0x4e,0x7,0x23,0x0,0x2,0x0,0x7,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x5,0x8d,0xfd,0x7d, + 0x0,0x0,0xe,0x64,0xfc,0x66,0xfe,0x2f,0x9,0xcb,0x3,0xe8,0x0,0xb0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x81,0x4,0x6c, + 0x0,0xd3,0x4,0xcc,0x0,0x0,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29, + 0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0x0,0x29,0x4,0xcc,0xff,0xd8,0x4,0xcc,0x0,0x90,0x4,0xcc,0x0,0xaa,0x4,0xcc, + 0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0xaa,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x54,0x4,0xcc,0x0,0x72, + 0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc, + 0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xb6,0x4,0xcc,0x0,0x83,0x4,0xcc,0x0,0x83,0x4,0xcc,0x0,0x83, + 0x4,0xcc,0x0,0x83,0x4,0xcc,0x0,0x83,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x74,0x4,0xcc, + 0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x96, + 0x4,0xcc,0x0,0x96,0x4,0xcc,0x0,0x90,0x4,0xcc,0x0,0x90,0x4,0xcc,0x0,0x98,0x4,0xcc,0x0,0x98,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc, + 0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0xb8,0x4,0xcc,0x0,0x4e,0x4,0xcc,0x0,0x52,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x70, + 0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x70,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x72,0x4,0xcc, + 0x0,0x72,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x3e,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0x6b,0x4,0xcc,0x0,0xac, + 0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0x72,0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0x7f,0x4,0xcc, + 0x0,0x7f,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xeb, + 0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xeb,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc, + 0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xa8,0x4,0xcc,0x0,0xdf,0x4,0xcc,0x0,0x99, + 0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x5d,0x4,0xcc,0x1,0x5,0x4,0xcc,0x1,0x5,0x4,0xcc, + 0x1,0x5,0x4,0xcc,0x1,0x5,0x4,0xcc,0x1,0x5,0x4,0xcc,0x0,0x74,0x4,0xcc,0x0,0x74,0x4,0xcc,0x0,0x74,0x4,0xcc,0x0,0x74,0x4,0xcc,0x0,0x8f, + 0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc, + 0x0,0x8f,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x2c,0x4,0xcc,0x0,0x81,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a, + 0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0x8e,0x4,0xcc,0x0,0x85,0x4,0xcc,0x0,0x9f,0x4,0xcc,0x0,0x9a,0x4,0xcc, + 0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0x9a, + 0x4,0xcc,0x0,0x9a,0x4,0xcc,0x0,0xfb,0x4,0xcc,0x0,0x4c,0x4,0xcc,0x0,0x4c,0x4,0xcc,0x0,0x4c,0x4,0xcc,0x0,0x4c,0x4,0xcc,0x0,0x4c,0x4,0xcc, + 0x0,0x8b,0x4,0xcc,0x0,0x88,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4, + 0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xb3,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc, + 0x0,0x53,0x4,0xcc,0x0,0x53,0x4,0xcc,0x0,0x53,0x4,0xcc,0x0,0xa9,0x4,0xcc,0x0,0xa9,0x4,0xcc,0x1,0x10,0x4,0xcc,0x1,0x10,0x4,0xcc,0x0,0xf2, + 0x4,0xcc,0x1,0x10,0x4,0xcc,0x0,0xf2,0x4,0xcc,0x0,0xf3,0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc, + 0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c, + 0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x1a,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x42,0x4,0xcc,0x0,0x3d,0x4,0xcc, + 0x0,0x3d,0x4,0xcc,0x0,0x8f,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0xf4,0x4,0xcc,0x0,0x88,0x4,0xcc,0x0,0x88, + 0x4,0xcc,0x0,0x88,0x4,0xcc,0x0,0x88,0x4,0xcc,0x0,0x88,0x4,0xcc,0x0,0x88,0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0xb4,0x4,0xcc,0x0,0xb4,0x4,0xcc, + 0x0,0xb4,0x4,0xcc,0x0,0xb4,0x4,0xcc,0x0,0xb4,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2, + 0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xa2,0x4,0xcc,0x0,0xcb,0x4,0xcc, + 0x0,0x8a,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0x6b,0x4,0xcc,0x0,0xc9,0x4,0xcc,0x0,0xc9, + 0x4,0xcc,0x0,0xc9,0x4,0xcc,0x0,0xc9,0x4,0xcc,0x0,0xc9,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0x7f,0x4,0xcc,0x0,0x7f,0x9,0x98, + 0x0,0xfb,0x9,0x98,0x0,0xfb,0x4,0xcc,0x1,0x35,0x4,0xcc,0x1,0x3e,0x4,0xcc,0x0,0x5a,0x4,0xcc,0x0,0x19,0x4,0xcc,0x0,0x57,0x4,0xcc,0x0,0xaf, + 0x4,0xcc,0x0,0xd4,0x4,0xcc,0x0,0xc5,0x4,0xcc,0x0,0x85,0x4,0xcc,0x0,0x93,0x4,0xcc,0x0,0x8b,0x4,0xcc,0x0,0x9d,0x4,0xcc,0x0,0xd7,0x4,0xcc, + 0x1,0x42,0x4,0xcc,0x0,0xc2,0x4,0xcc,0x0,0xba,0x4,0xcc,0x0,0x54,0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0x3a,0x4,0xcc,0x0,0x54,0x4,0xcc,0x1,0x53, + 0x4,0xcc,0x1,0x38,0x4,0xcc,0x1,0x4c,0x4,0xcc,0x1,0x43,0x4,0xcc,0x2,0xcd,0x4,0xcc,0x2,0x35,0x4,0xcc,0x2,0xcd,0x4,0xcc,0x2,0x5d,0x4,0xcc, + 0xfe,0x1d,0xe,0x64,0x2,0xe9,0x4,0xcc,0x0,0xf3,0x4,0xcc,0xfd,0xfb,0xe,0x64,0x2,0xe9,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x1,0x72,0x4,0xcc,0x1,0xee, + 0x4,0xcc,0x1,0x87,0x4,0xcc,0x1,0xa1,0x4,0xcc,0x1,0x9,0x4,0xcc,0x0,0x2e,0x4,0xcc,0x1,0xb1,0x4,0xcc,0x1,0x6e,0x4,0xcc,0x0,0x3b,0x4,0xcc, + 0x1,0xa1,0x4,0xcc,0x1,0x82,0x4,0xcc,0x0,0x9c,0x4,0xcc,0x1,0x7e,0x4,0xcc,0x2,0x62,0x4,0xcc,0x1,0x31,0x4,0xcc,0x0,0x52,0x4,0xcc,0x0,0x1, + 0x4,0xcc,0x0,0xc8,0x4,0xcc,0x0,0x6c,0x4,0xcc,0x0,0xd3,0x4,0xcc,0x0,0xef,0x4,0xcc,0x1,0x30,0x4,0xcc,0x0,0xf9,0x4,0xcc,0x1,0x2b,0x4,0xcc, + 0xfe,0x70,0x9,0x98,0x0,0xd,0x9,0x98,0x1,0x39,0x4,0xcc,0xff,0x38,0x4,0xcc,0xff,0xff,0x4,0xcc,0x0,0xc7,0x4,0xcc,0x0,0xc7,0x4,0xcc,0x0,0xc7, + 0x0,0x0,0x0,0x0,0x4,0xcc,0x0,0xac,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x1,0xa6,0x4,0xcc,0x1,0x7c,0x4,0xcc,0x0,0x52,0x4,0xcc,0x0,0xee,0x4,0xcc, + 0x0,0xfe,0x4,0xcc,0x1,0xe3,0x4,0xcc,0x1,0xf3,0x4,0xcc,0x1,0x47,0x4,0xcc,0x0,0x0,0x4,0xcc,0x0,0xb3,0x4,0xcc,0x0,0x62,0x4,0xcc,0x0,0x98, + 0x4,0xcc,0x0,0x5f,0x4,0xcc,0xff,0xc7,0x4,0xcc,0x0,0x1e,0x4,0xcc,0x0,0xc7,0x4,0xcc,0x0,0x13,0x4,0xcc,0x0,0xa1,0x4,0xcc,0x0,0x90,0x4,0xcc, + 0x0,0xb3,0x4,0xcc,0x0,0xc7,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0x89,0x4,0xcc,0x0,0x81,0x4,0xcc,0x0,0x3b,0x4,0xcc,0xff,0x8d,0x4,0xcc,0x0,0x9b, + 0x4,0xcc,0x0,0x81,0x4,0xcc,0x0,0xcc,0x4,0xcc,0x0,0xc7,0x4,0xcc,0x0,0xe4,0x4,0xcc,0x0,0xa4,0x4,0xcc,0x0,0xa7,0x4,0xcc,0x0,0x42,0x4,0xcc, + 0x0,0x42,0x4,0xcc,0x0,0xc7,0x4,0xcc,0x0,0x81,0x4,0xcc,0x0,0x84,0x4,0xcc,0x0,0x95,0x4,0xcc,0x0,0x69,0x4,0xcc,0x0,0xf0,0x4,0xcc,0x1,0x95, + 0x4,0xcc,0x1,0x95,0x4,0xcc,0x0,0x26,0x4,0xcc,0x0,0x8c,0x4,0xcc,0x0,0xcd,0x4,0xcc,0x0,0x3d,0x4,0xcc,0x0,0x3d,0x4,0xcc,0x0,0xa9,0x4,0xcc, + 0x0,0xd0,0x4,0xcc,0x1,0x51,0x4,0xcc,0x1,0x4,0x4,0xcc,0x1,0x6f,0x4,0xcc,0x1,0x36,0x2,0x58,0x0,0x0,0x2,0x58,0x0,0x0,0x0,0x0,0xfc,0x66, + 0x0,0x0,0xfc,0x66,0x4,0xcc,0x2,0x13,0x1,0x53,0x1,0x8f,0x1,0xab,0x2,0x3b,0x1,0xb8,0x1,0xd3,0x0,0xde,0x1,0xae,0x1,0xc0,0x2,0x8f,0x1,0xb8, + 0x1,0xe1,0x1,0xbd,0x1,0x25,0x2,0x3a,0x1,0xbe,0x0,0xde,0x1,0x86,0x1,0x98,0x2,0x67,0x1,0x90,0x1,0xb9,0x1,0x95,0x1,0x25,0x2,0x12,0x1,0x96, + 0x0,0x0,0x0,0x78,0x0,0x78,0x0,0xc8,0x0,0xda,0x0,0xec,0x0,0xfe,0x1,0x10,0x1,0x22,0x1,0x34,0x1,0xb8,0x1,0xca,0x1,0xdc,0x2,0x78,0x2,0xde, + 0x3,0x38,0x3,0x4a,0x3,0x5c,0x3,0xf2,0x4,0x4,0x4,0x16,0x4,0x66,0x4,0xda,0x4,0xec,0x4,0xfe,0x5,0x5e,0x5,0x70,0x5,0x82,0x5,0x94,0x5,0xa6, + 0x5,0xb8,0x5,0xca,0x5,0xdc,0x5,0xee,0x6,0x90,0x6,0xe4,0x7,0x54,0x7,0x66,0x7,0x78,0x7,0x84,0x7,0x96,0x7,0xf4,0x8,0x98,0x8,0xaa,0x9,0x2, + 0x9,0x86,0x9,0x98,0x9,0xaa,0x9,0xbc,0x9,0xce,0x9,0xe0,0x9,0xf2,0xa,0x4,0xa,0x9c,0xa,0xae,0xb,0x2,0xb,0x14,0xb,0x78,0xb,0x84,0xb,0xc4, + 0xb,0xd6,0xb,0xe8,0xb,0xf4,0xc,0x6,0xc,0x70,0xc,0xd6,0xd,0x40,0xd,0x52,0xd,0x64,0xd,0x70,0xd,0xdc,0xd,0xee,0xe,0x44,0xe,0x56,0xe,0x68, + 0xe,0x7a,0xe,0x8c,0xe,0x9e,0xe,0xb0,0xe,0xc2,0xf,0x5c,0xf,0x6e,0xf,0xe0,0x10,0x34,0x10,0xaa,0x11,0x2c,0x11,0x8c,0x11,0x9e,0x11,0xb0,0x11,0xbc, + 0x12,0x38,0x12,0x4a,0x12,0x5c,0x13,0x18,0x13,0x2a,0x13,0x36,0x13,0x7c,0x13,0xe8,0x13,0xfa,0x14,0x76,0x14,0x82,0x14,0xd2,0x14,0xe4,0x14,0xf6,0x15,0x8, + 0x15,0x1a,0x15,0x2c,0x15,0x3e,0x15,0x50,0x15,0xda,0x15,0xec,0x15,0xfe,0x16,0x3e,0x16,0xaa,0x16,0xbc,0x16,0xce,0x16,0xe0,0x16,0xf2,0x17,0x4c,0x17,0x92, + 0x17,0xa4,0x17,0xb6,0x17,0xc8,0x17,0xda,0x18,0x2c,0x18,0x3e,0x18,0x50,0x18,0x62,0x19,0x34,0x19,0x40,0x19,0x4c,0x19,0x58,0x19,0x64,0x19,0x70,0x19,0x7c, + 0x1a,0x7c,0x1a,0x8e,0x1a,0x9a,0x1b,0x4a,0x1b,0xdc,0x1c,0x3a,0x1c,0x46,0x1c,0x56,0x1c,0xf0,0x1c,0xfc,0x1d,0x8,0x1d,0x8a,0x1e,0x42,0x1f,0x12,0x1f,0xd6, + 0x20,0x38,0x20,0x44,0x20,0x50,0x20,0x60,0x20,0x6c,0x20,0x78,0x20,0x84,0x20,0x90,0x20,0x9c,0x21,0x40,0x21,0xa8,0x22,0x5e,0x22,0x6a,0x22,0x76,0x23,0x56, + 0x23,0x62,0x23,0xc6,0x24,0x64,0x24,0x76,0x25,0x10,0x25,0x68,0x25,0x74,0x25,0x80,0x25,0x8c,0x25,0x98,0x25,0xa4,0x25,0xb0,0x26,0x82,0x26,0x8e,0x27,0x6c, + 0x27,0x78,0x28,0xe,0x28,0x62,0x28,0x6e,0x28,0xc6,0x28,0xd2,0x29,0x2c,0x29,0x3e,0x29,0x4a,0x29,0x56,0x29,0x68,0x29,0xe4,0x2a,0x7e,0x2a,0xf2,0x2a,0xfe, + 0x2b,0xe,0x2b,0x1a,0x2b,0xae,0x2b,0xba,0x2c,0x4,0x2c,0x10,0x2c,0x1c,0x2c,0x28,0x2c,0x34,0x2c,0x40,0x2c,0x4c,0x2c,0x58,0x2c,0xe2,0x2c,0xee,0x2d,0x82, + 0x2e,0x4,0x2e,0x72,0x2e,0xf6,0x2f,0x7c,0x2f,0x88,0x2f,0x98,0x2f,0xa4,0x30,0x1c,0x30,0x28,0x30,0x38,0x30,0xee,0x30,0xfa,0x31,0x6,0x31,0x9c,0x32,0xc, + 0x32,0xa6,0x32,0xb8,0x33,0x6a,0x33,0x76,0x33,0xea,0x33,0xf6,0x34,0x2,0x34,0xe,0x34,0x1a,0x34,0x26,0x34,0x32,0x34,0x3e,0x34,0xd0,0x34,0xdc,0x34,0xe8, + 0x35,0x28,0x35,0x82,0x35,0x8e,0x35,0x9a,0x35,0xa6,0x35,0xb2,0x36,0x8,0x36,0x50,0x36,0x5c,0x36,0x68,0x36,0x74,0x36,0x80,0x36,0xd2,0x36,0xde,0x36,0xea, + 0x36,0xf6,0x37,0x2,0x37,0xe,0x37,0x64,0x37,0x98,0x37,0xca,0x38,0x2a,0x38,0x82,0x38,0xc6,0x39,0x1e,0x39,0x74,0x39,0xd8,0x3a,0x58,0x3a,0xb6,0x3b,0x2a, + 0x3b,0x8a,0x3b,0xce,0x3c,0x46,0x3c,0xa4,0x3c,0xce,0x3d,0x8c,0x3e,0x68,0x3f,0x9a,0x3f,0xd6,0x40,0x1a,0x40,0x6e,0x40,0xac,0x40,0xea,0x40,0xf4,0x40,0xfe, + 0x41,0x3a,0x41,0x4a,0x41,0x5c,0x41,0xac,0x41,0xfc,0x42,0xe,0x42,0x90,0x42,0xce,0x42,0xde,0x43,0x12,0x43,0x68,0x43,0x94,0x44,0x2,0x44,0x54,0x44,0xa8, + 0x45,0x4e,0x45,0x7e,0x45,0xf2,0x46,0x66,0x46,0x74,0x46,0xa4,0x46,0xf6,0x47,0x30,0x47,0x66,0x48,0x30,0x48,0xfa,0x49,0x86,0x4a,0x12,0x4a,0x54,0x4a,0x96, + 0x4a,0xba,0x4a,0xde,0x4b,0x2,0x4b,0x26,0x4b,0x4a,0x4b,0x7e,0x4b,0xb2,0x4b,0xe6,0x4b,0xee,0x4b,0xee,0x4c,0x4e,0x4c,0xae,0x4c,0xe6,0x4d,0x1e,0x4d,0x2c, + 0x4d,0x3a,0x4d,0x48,0x4d,0x78,0x4d,0xa4,0x4d,0xd0,0x4d,0xd0,0x4e,0x4c,0x4e,0xf8,0x4f,0x9c,0x50,0x3e,0x50,0xb6,0x51,0x2e,0x51,0xb0,0x52,0x5a,0x52,0xee, + 0x53,0x6,0x53,0x5c,0x53,0xcc,0x53,0xe4,0x54,0x22,0x54,0x70,0x54,0xca,0x55,0xc,0x55,0x4a,0x55,0x9a,0x55,0xdc,0x56,0x0,0x56,0x6e,0x56,0xca,0x57,0x20, + 0x57,0xc4,0x58,0x9a,0x58,0xf8,0x59,0x7a,0x59,0xb2,0x59,0xea,0x5a,0x40,0x5a,0x7a,0x5a,0xac,0x5b,0x6,0x5b,0xe2,0x5c,0x66,0x5c,0xbe,0x5d,0x6c,0x5e,0x12, + 0x5e,0x96,0x5f,0x4,0x5f,0x4e,0x5f,0x94,0x5f,0xec,0x60,0xbe,0x60,0xbe,0x60,0xbe,0x60,0xee,0x60,0xf6,0x61,0x26,0x61,0x50,0x61,0x96,0x61,0xd2,0x61,0xe2, + 0x61,0xf2,0x62,0x2,0x62,0xa,0x62,0x1a,0x62,0x2a,0x62,0x3a,0x62,0x4a,0x62,0x5a,0x62,0x6a,0x62,0x72,0x62,0x82,0x62,0x92,0x63,0x2,0x63,0x3e,0x63,0x84, + 0x63,0xb2,0x63,0xe0,0x64,0x2c,0x64,0x64,0x64,0xb0,0x64,0xfc,0x65,0x67,0x0,0x1,0x0,0x0,0x1,0x9b,0x0,0x6f,0x0,0xa,0x0,0x6c,0x0,0x4,0x0,0x2, + 0x0,0x26,0x0,0x36,0x0,0x77,0x0,0x0,0x0,0x94,0xb,0xe2,0x0,0x3,0x0,0x1,0x0,0x0,0x0,0x1a,0x1,0x3e,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x26,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x12,0x0,0x26,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x6,0x0,0x38,0x0,0x1, + 0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x22,0x0,0x3e,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x19,0x0,0x60,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x5, + 0x0,0xe,0x0,0x79,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x17,0x0,0x87,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x12,0x0,0x9e,0x0,0x1, + 0x0,0x0,0x0,0x0,0x0,0x9,0x0,0x11,0x0,0xb0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xb,0x0,0x1b,0x0,0xc1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xc, + 0x0,0x16,0x0,0xdc,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xd,0x11,0x3,0x0,0xf2,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xe,0x0,0x1a,0x11,0xf5,0x0,0x3, + 0x0,0x1,0x4,0x9,0x0,0x0,0x0,0x4c,0x12,0xf,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x1,0x0,0x24,0x12,0x5b,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x2, + 0x0,0xc,0x12,0x7f,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x3,0x0,0x44,0x12,0x8b,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x4,0x0,0x32,0x12,0xcf,0x0,0x3, + 0x0,0x1,0x4,0x9,0x0,0x5,0x0,0x1c,0x13,0x1,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x6,0x0,0x2e,0x13,0x1d,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x8, + 0x0,0x24,0x13,0x4b,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0x9,0x0,0x22,0x13,0x6f,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0xb,0x0,0x36,0x13,0x91,0x0,0x3, + 0x0,0x1,0x4,0x9,0x0,0xc,0x0,0x2c,0x13,0xc7,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0xd,0x22,0x6,0x13,0xf3,0x0,0x3,0x0,0x1,0x4,0x9,0x0,0xe, + 0x0,0x34,0x35,0xf9,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x35,0x20,0x51,0x75,0x6f,0x74,0x65,0x2d,0x55, + 0x6e,0x71,0x75,0x6f,0x74,0x65,0x20,0x41,0x70,0x70,0x73,0x2e,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x50,0x72,0x69,0x6d,0x65,0x20,0x43,0x6f,0x64,0x65, + 0x49,0x74,0x61,0x6c,0x69,0x63,0x33,0x2e,0x30,0x31,0x38,0x3b,0x51,0x55,0x51,0x41,0x3b,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x50,0x72,0x69,0x6d,0x65,0x43, + 0x6f,0x64,0x65,0x2d,0x49,0x74,0x61,0x6c,0x69,0x63,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x50,0x72,0x69,0x6d,0x65,0x20,0x43,0x6f,0x64,0x65,0x20,0x49, + 0x74,0x61,0x6c,0x69,0x63,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x33,0x2e,0x30,0x33,0x31,0x38,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x50,0x72,0x69,0x6d, + 0x65,0x43,0x6f,0x64,0x65,0x2d,0x49,0x74,0x61,0x6c,0x69,0x63,0x51,0x75,0x6f,0x74,0x65,0x2d,0x55,0x6e,0x71,0x75,0x6f,0x74,0x65,0x20,0x41,0x70,0x70,0x73, + 0x41,0x6c,0x61,0x6e,0x20,0x44,0x61,0x67,0x75,0x65,0x2d,0x47,0x72,0x65,0x65,0x6e,0x65,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x71,0x75,0x6f,0x74,0x65,0x75, + 0x6e,0x71,0x75,0x6f,0x74,0x65,0x61,0x70,0x70,0x73,0x2e,0x63,0x6f,0x6d,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x62,0x61,0x73,0x69,0x63,0x72,0x65,0x63,0x69, + 0x70,0x65,0x2e,0x63,0x6f,0x6d,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x28,0x63,0x29,0x20,0x32,0x30,0x31,0x35,0xa,0x51,0x75,0x6f,0x74,0x65, + 0x2d,0x55,0x6e,0x71,0x75,0x6f,0x74,0x65,0x20,0x41,0x70,0x70,0x73,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x71,0x75,0x6f,0x74,0x65,0x75,0x6e,0x71, + 0x75,0x6f,0x74,0x65,0x61,0x70,0x70,0x73,0x2e,0x63,0x6f,0x6d,0x29,0xa,0x77,0x69,0x74,0x68,0x20,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x46,0x6f, + 0x6e,0x74,0x20,0x4e,0x61,0x6d,0x65,0x20,0x43,0x6f,0x75,0x72,0x69,0x65,0x72,0x20,0x50,0x72,0x69,0x6d,0x65,0x20,0x43,0x6f,0x64,0x65,0x2e,0xa,0xa,0x54, + 0x68,0x69,0x73,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x64,0x20, + 0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x65,0x20,0x53,0x49,0x4c,0x20,0x4f,0x70,0x65,0x6e,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4c,0x69,0x63,0x65,0x6e,0x73, + 0x65,0xa,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x31,0x2e,0x20,0x54,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x69,0x73, + 0x20,0x63,0x6f,0x70,0x69,0x65,0x64,0x20,0x62,0x65,0x6c,0x6f,0x77,0xa,0x61,0x6e,0x64,0x20,0x69,0x73,0x20,0x61,0x6c,0x73,0x6f,0x20,0x61,0x76,0x61,0x69, + 0x6c,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x20,0x46,0x41,0x51,0x20,0x61,0x74,0x3a,0x20,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x63, + 0x72,0x69,0x70,0x74,0x73,0x2e,0x73,0x69,0x6c,0x2e,0x6f,0x72,0x67,0x2f,0x4f,0x46,0x4c,0xa,0xa,0xa,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0xa,0x53,0x49,0x4c,0x20,0x4f,0x50,0x45,0x4e,0x20,0x46, + 0x4f,0x4e,0x54,0x20,0x4c,0x49,0x43,0x45,0x4e,0x53,0x45,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x2e,0x31,0x20,0x2d,0x20,0x32,0x36,0x20,0x46, + 0x65,0x62,0x72,0x75,0x61,0x72,0x79,0x20,0x32,0x30,0x30,0x37,0xa,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d, + 0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0x2d,0xa,0xa,0x50,0x52,0x45,0x41,0x4d,0x42,0x4c,0x45,0xa,0x54,0x68,0x65,0x20,0x67,0x6f,0x61, + 0x6c,0x73,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x4f,0x70,0x65,0x6e,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x28,0x4f, + 0x46,0x4c,0x29,0x20,0x61,0x72,0x65,0x20,0x74,0x6f,0x20,0x73,0x74,0x69,0x6d,0x75,0x6c,0x61,0x74,0x65,0x20,0x77,0x6f,0x72,0x6c,0x64,0x77,0x69,0x64,0x65, + 0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x6d,0x65,0x6e,0x74,0x20,0x6f,0x66,0x20,0x63,0x6f,0x6c,0x6c,0x61,0x62,0x6f,0x72,0x61,0x74,0x69,0x76,0x65,0x20, + 0x66,0x6f,0x6e,0x74,0x20,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0xa,0x74,0x6f,0x20,0x73,0x75,0x70,0x70,0x6f,0x72,0x74,0x20,0x74,0x68,0x65,0x20,0x66, + 0x6f,0x6e,0x74,0x20,0x63,0x72,0x65,0x61,0x74,0x69,0x6f,0x6e,0x20,0x65,0x66,0x66,0x6f,0x72,0x74,0x73,0x20,0x6f,0x66,0x20,0x61,0x63,0x61,0x64,0x65,0x6d, + 0x69,0x63,0x20,0x61,0x6e,0x64,0x20,0x6c,0x69,0x6e,0x67,0x75,0x69,0x73,0x74,0x69,0x63,0x20,0x63,0x6f,0x6d,0x6d,0x75,0x6e,0x69,0x74,0x69,0x65,0x73,0xa, + 0x61,0x6e,0x64,0x20,0x74,0x6f,0x20,0x70,0x72,0x6f,0x76,0x69,0x64,0x65,0x20,0x61,0x20,0x66,0x72,0x65,0x65,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x6e, + 0x20,0x66,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x20,0x69,0x6e,0x20,0x77,0x68,0x69,0x63,0x68,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x6d,0x61,0x79,0x20, + 0x62,0x65,0x20,0x73,0x68,0x61,0x72,0x65,0x64,0x20,0x61,0x6e,0x64,0x20,0x69,0x6d,0x70,0x72,0x6f,0x76,0x65,0x64,0x20,0x69,0x6e,0x20,0x70,0x61,0x72,0x74, + 0x6e,0x65,0x72,0x73,0x68,0x69,0x70,0x20,0x77,0x69,0x74,0x68,0x20,0x6f,0x74,0x68,0x65,0x72,0x73,0x2e,0xa,0xa,0x54,0x68,0x65,0x20,0x4f,0x46,0x4c,0x20, + 0x61,0x6c,0x6c,0x6f,0x77,0x73,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x64,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x74,0x6f,0x20,0x62, + 0x65,0x20,0x75,0x73,0x65,0x64,0xa,0x73,0x74,0x75,0x64,0x69,0x65,0x64,0xa,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x61,0x6e,0x64,0x20,0x72,0x65, + 0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x66,0x72,0x65,0x65,0x6c,0x79,0x20,0x61,0x73,0x20,0x6c,0x6f,0x6e,0x67,0x20,0x61,0x73,0x20, + 0x74,0x68,0x65,0x79,0x20,0x61,0x72,0x65,0x20,0x6e,0x6f,0x74,0x20,0x73,0x6f,0x6c,0x64,0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x6d,0x73,0x65,0x6c,0x76,0x65, + 0x73,0x2e,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x6e,0x74,0x73,0xa,0x69,0x6e,0x63,0x6c,0x75,0x64,0x69,0x6e,0x67,0x20,0x61,0x6e,0x79,0x20,0x64,0x65,0x72, + 0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x20,0x77,0x6f,0x72,0x6b,0x73,0xa,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x62,0x75,0x6e,0x64,0x6c,0x65,0x64,0xa,0x65, + 0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0xa,0x72,0x65,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x61,0x6e,0x64,0x2f,0x6f,0x72,0x20,0x73, + 0x6f,0x6c,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x6e,0x79,0x20,0x73,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x70,0x72,0x6f,0x76,0x69,0x64,0x65,0x64, + 0x20,0x74,0x68,0x61,0x74,0x20,0x61,0x6e,0x79,0x20,0x72,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x6e,0x61,0x6d,0x65,0x73,0x20,0x61,0x72,0x65,0x20,0x6e, + 0x6f,0x74,0x20,0x75,0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x20,0x77,0x6f,0x72,0x6b,0x73,0x2e,0x20,0x54, + 0x68,0x65,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x61,0x6e,0x64,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x73,0xa,0x68,0x6f,0x77,0x65,0x76, + 0x65,0x72,0xa,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x64,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x61,0x6e, + 0x79,0x20,0x6f,0x74,0x68,0x65,0x72,0x20,0x74,0x79,0x70,0x65,0x20,0x6f,0x66,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x2e,0x20,0x54,0x68,0x65,0x20,0x72, + 0x65,0x71,0x75,0x69,0x72,0x65,0x6d,0x65,0x6e,0x74,0x20,0x66,0x6f,0x72,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e, + 0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x64,0x6f,0x65,0x73,0x20,0x6e,0x6f,0x74,0x20,0x61, + 0x70,0x70,0x6c,0x79,0x20,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x20,0x63,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x75, + 0x73,0x69,0x6e,0x67,0x20,0x74,0x68,0x65,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x6f,0x72,0x20,0x74,0x68,0x65,0x69,0x72,0x20,0x64,0x65,0x72,0x69,0x76,0x61, + 0x74,0x69,0x76,0x65,0x73,0x2e,0xa,0xa,0x44,0x45,0x46,0x49,0x4e,0x49,0x54,0x49,0x4f,0x4e,0x53,0xa,0x22,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74, + 0x77,0x61,0x72,0x65,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x73,0x65,0x74,0x20,0x6f,0x66,0x20,0x66,0x69,0x6c, + 0x65,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48, + 0x6f,0x6c,0x64,0x65,0x72,0x28,0x73,0x29,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x61,0x6e, + 0x64,0x20,0x63,0x6c,0x65,0x61,0x72,0x6c,0x79,0x20,0x6d,0x61,0x72,0x6b,0x65,0x64,0x20,0x61,0x73,0x20,0x73,0x75,0x63,0x68,0x2e,0x20,0x54,0x68,0x69,0x73, + 0x20,0x6d,0x61,0x79,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x66,0x69,0x6c,0x65,0x73,0xa,0x62,0x75,0x69,0x6c, + 0x64,0x20,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x20,0x61,0x6e,0x64,0x20,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e,0x2e,0xa,0xa, + 0x22,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x46,0x6f,0x6e,0x74,0x20,0x4e,0x61,0x6d,0x65,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f, + 0x20,0x61,0x6e,0x79,0x20,0x6e,0x61,0x6d,0x65,0x73,0x20,0x73,0x70,0x65,0x63,0x69,0x66,0x69,0x65,0x64,0x20,0x61,0x73,0x20,0x73,0x75,0x63,0x68,0x20,0x61, + 0x66,0x74,0x65,0x72,0x20,0x74,0x68,0x65,0x20,0x63,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x73,0x74,0x61,0x74,0x65,0x6d,0x65,0x6e,0x74,0x28,0x73, + 0x29,0x2e,0xa,0xa,0x22,0x4f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20, + 0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x63,0x6f,0x6c,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74, + 0x77,0x61,0x72,0x65,0x20,0x63,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0x20,0x61,0x73,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64, + 0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64,0x65,0x72,0x28,0x73,0x29,0x2e,0xa,0xa, + 0x22,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x61, + 0x6e,0x79,0x20,0x64,0x65,0x72,0x69,0x76,0x61,0x74,0x69,0x76,0x65,0x20,0x6d,0x61,0x64,0x65,0x20,0x62,0x79,0x20,0x61,0x64,0x64,0x69,0x6e,0x67,0x20,0x74, + 0x6f,0xa,0x64,0x65,0x6c,0x65,0x74,0x69,0x6e,0x67,0xa,0x6f,0x72,0x20,0x73,0x75,0x62,0x73,0x74,0x69,0x74,0x75,0x74,0x69,0x6e,0x67,0x20,0x2d,0x2d,0x20, + 0x69,0x6e,0x20,0x70,0x61,0x72,0x74,0x20,0x6f,0x72,0x20,0x69,0x6e,0x20,0x77,0x68,0x6f,0x6c,0x65,0x20,0x2d,0x2d,0x20,0x61,0x6e,0x79,0x20,0x6f,0x66,0x20, + 0x74,0x68,0x65,0x20,0x63,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e,0x74,0x73,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x4f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c, + 0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0xa,0x62,0x79,0x20,0x63,0x68,0x61,0x6e,0x67,0x69,0x6e,0x67,0x20,0x66,0x6f,0x72,0x6d,0x61,0x74,0x73,0x20,0x6f, + 0x72,0x20,0x62,0x79,0x20,0x70,0x6f,0x72,0x74,0x69,0x6e,0x67,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65, + 0x20,0x74,0x6f,0x20,0x61,0x20,0x6e,0x65,0x77,0x20,0x65,0x6e,0x76,0x69,0x72,0x6f,0x6e,0x6d,0x65,0x6e,0x74,0x2e,0xa,0xa,0x22,0x41,0x75,0x74,0x68,0x6f, + 0x72,0x22,0x20,0x72,0x65,0x66,0x65,0x72,0x73,0x20,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x64,0x65,0x73,0x69,0x67,0x6e,0x65,0x72,0xa,0x65,0x6e,0x67,0x69, + 0x6e,0x65,0x65,0x72,0xa,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x6d,0x65,0x72,0xa,0x74,0x65,0x63,0x68,0x6e,0x69,0x63,0x61,0x6c,0x20,0x77,0x72,0x69,0x74, + 0x65,0x72,0x20,0x6f,0x72,0x20,0x6f,0x74,0x68,0x65,0x72,0x20,0x70,0x65,0x72,0x73,0x6f,0x6e,0x20,0x77,0x68,0x6f,0x20,0x63,0x6f,0x6e,0x74,0x72,0x69,0x62, + 0x75,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x2e,0xa,0xa,0x50,0x45, + 0x52,0x4d,0x49,0x53,0x53,0x49,0x4f,0x4e,0x20,0x26,0x20,0x43,0x4f,0x4e,0x44,0x49,0x54,0x49,0x4f,0x4e,0x53,0xa,0x50,0x65,0x72,0x6d,0x69,0x73,0x73,0x69, + 0x6f,0x6e,0x20,0x69,0x73,0x20,0x68,0x65,0x72,0x65,0x62,0x79,0x20,0x67,0x72,0x61,0x6e,0x74,0x65,0x64,0xa,0x66,0x72,0x65,0x65,0x20,0x6f,0x66,0x20,0x63, + 0x68,0x61,0x72,0x67,0x65,0xa,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x70,0x65,0x72,0x73,0x6f,0x6e,0x20,0x6f,0x62,0x74,0x61,0x69,0x6e,0x69,0x6e,0x67,0x20, + 0x61,0x20,0x63,0x6f,0x70,0x79,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x74,0x6f, + 0x20,0x75,0x73,0x65,0xa,0x73,0x74,0x75,0x64,0x79,0xa,0x63,0x6f,0x70,0x79,0xa,0x6d,0x65,0x72,0x67,0x65,0xa,0x65,0x6d,0x62,0x65,0x64,0xa,0x6d,0x6f, + 0x64,0x69,0x66,0x79,0xa,0x72,0x65,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0xa,0x61,0x6e,0x64,0x20,0x73,0x65,0x6c,0x6c,0x20,0x6d,0x6f,0x64, + 0x69,0x66,0x69,0x65,0x64,0x20,0x61,0x6e,0x64,0x20,0x75,0x6e,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x63,0x6f,0x70,0x69,0x65,0x73,0x20,0x6f,0x66, + 0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x73,0x75,0x62,0x6a,0x65,0x63,0x74,0x20,0x74,0x6f,0x20, + 0x74,0x68,0x65,0x20,0x66,0x6f,0x6c,0x6c,0x6f,0x77,0x69,0x6e,0x67,0x20,0x63,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x73,0x3a,0xa,0xa,0x31,0x29,0x20, + 0x4e,0x65,0x69,0x74,0x68,0x65,0x72,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x6e,0x6f,0x72,0x20, + 0x61,0x6e,0x79,0x20,0x6f,0x66,0x20,0x69,0x74,0x73,0x20,0x69,0x6e,0x64,0x69,0x76,0x69,0x64,0x75,0x61,0x6c,0x20,0x63,0x6f,0x6d,0x70,0x6f,0x6e,0x65,0x6e, + 0x74,0x73,0xa,0x69,0x6e,0x20,0x4f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x6f,0x72,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72, + 0x73,0x69,0x6f,0x6e,0x73,0xa,0x6d,0x61,0x79,0x20,0x62,0x65,0x20,0x73,0x6f,0x6c,0x64,0x20,0x62,0x79,0x20,0x69,0x74,0x73,0x65,0x6c,0x66,0x2e,0xa,0xa, + 0x32,0x29,0x20,0x4f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x20,0x6f,0x72,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f, + 0x6e,0x73,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x6d,0x61,0x79,0x20,0x62,0x65, + 0x20,0x62,0x75,0x6e,0x64,0x6c,0x65,0x64,0xa,0x72,0x65,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x61,0x6e,0x64,0x2f,0x6f,0x72,0x20, + 0x73,0x6f,0x6c,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x61,0x6e,0x79,0x20,0x73,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa,0x70,0x72,0x6f,0x76,0x69,0x64,0x65, + 0x64,0x20,0x74,0x68,0x61,0x74,0x20,0x65,0x61,0x63,0x68,0x20,0x63,0x6f,0x70,0x79,0x20,0x63,0x6f,0x6e,0x74,0x61,0x69,0x6e,0x73,0x20,0x74,0x68,0x65,0x20, + 0x61,0x62,0x6f,0x76,0x65,0x20,0x63,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x6e,0x6f,0x74,0x69,0x63,0x65,0x20,0x61,0x6e,0x64,0x20,0x74,0x68,0x69, + 0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x2e,0x20,0x54,0x68,0x65,0x73,0x65,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x69,0x6e,0x63,0x6c,0x75,0x64, + 0x65,0x64,0x20,0x65,0x69,0x74,0x68,0x65,0x72,0x20,0x61,0x73,0x20,0x73,0x74,0x61,0x6e,0x64,0x2d,0x61,0x6c,0x6f,0x6e,0x65,0x20,0x74,0x65,0x78,0x74,0x20, + 0x66,0x69,0x6c,0x65,0x73,0xa,0x68,0x75,0x6d,0x61,0x6e,0x2d,0x72,0x65,0x61,0x64,0x61,0x62,0x6c,0x65,0x20,0x68,0x65,0x61,0x64,0x65,0x72,0x73,0x20,0x6f, + 0x72,0x20,0x69,0x6e,0x20,0x74,0x68,0x65,0x20,0x61,0x70,0x70,0x72,0x6f,0x70,0x72,0x69,0x61,0x74,0x65,0x20,0x6d,0x61,0x63,0x68,0x69,0x6e,0x65,0x2d,0x72, + 0x65,0x61,0x64,0x61,0x62,0x6c,0x65,0x20,0x6d,0x65,0x74,0x61,0x64,0x61,0x74,0x61,0x20,0x66,0x69,0x65,0x6c,0x64,0x73,0x20,0x77,0x69,0x74,0x68,0x69,0x6e, + 0x20,0x74,0x65,0x78,0x74,0x20,0x6f,0x72,0x20,0x62,0x69,0x6e,0x61,0x72,0x79,0x20,0x66,0x69,0x6c,0x65,0x73,0x20,0x61,0x73,0x20,0x6c,0x6f,0x6e,0x67,0x20, + 0x61,0x73,0x20,0x74,0x68,0x6f,0x73,0x65,0x20,0x66,0x69,0x65,0x6c,0x64,0x73,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x65,0x61,0x73,0x69,0x6c,0x79,0x20, + 0x76,0x69,0x65,0x77,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68,0x65,0x20,0x75,0x73,0x65,0x72,0x2e,0xa,0xa,0x33,0x29,0x20,0x4e,0x6f,0x20,0x4d,0x6f,0x64, + 0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74, + 0x77,0x61,0x72,0x65,0x20,0x6d,0x61,0x79,0x20,0x75,0x73,0x65,0x20,0x74,0x68,0x65,0x20,0x52,0x65,0x73,0x65,0x72,0x76,0x65,0x64,0x20,0x46,0x6f,0x6e,0x74, + 0x20,0x4e,0x61,0x6d,0x65,0x28,0x73,0x29,0x20,0x75,0x6e,0x6c,0x65,0x73,0x73,0x20,0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,0x20,0x77,0x72,0x69,0x74,0x74, + 0x65,0x6e,0x20,0x70,0x65,0x72,0x6d,0x69,0x73,0x73,0x69,0x6f,0x6e,0x20,0x69,0x73,0x20,0x67,0x72,0x61,0x6e,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x74,0x68, + 0x65,0x20,0x63,0x6f,0x72,0x72,0x65,0x73,0x70,0x6f,0x6e,0x64,0x69,0x6e,0x67,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c,0x64, + 0x65,0x72,0x2e,0x20,0x54,0x68,0x69,0x73,0x20,0x72,0x65,0x73,0x74,0x72,0x69,0x63,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x6e,0x6c,0x79,0x20,0x61,0x70,0x70,0x6c, + 0x69,0x65,0x73,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x70,0x72,0x69,0x6d,0x61,0x72,0x79,0x20,0x66,0x6f,0x6e,0x74,0x20,0x6e,0x61,0x6d,0x65,0x20,0x61, + 0x73,0x20,0x70,0x72,0x65,0x73,0x65,0x6e,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x74,0x68,0x65,0x20,0x75,0x73,0x65,0x72,0x73,0x2e,0xa,0xa,0x34,0x29,0x20, + 0x54,0x68,0x65,0x20,0x6e,0x61,0x6d,0x65,0x28,0x73,0x29,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48, + 0x6f,0x6c,0x64,0x65,0x72,0x28,0x73,0x29,0x20,0x6f,0x72,0x20,0x74,0x68,0x65,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x28,0x73,0x29,0x20,0x6f,0x66,0x20,0x74, + 0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x20,0x73,0x68,0x61,0x6c,0x6c,0x20,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20, + 0x75,0x73,0x65,0x64,0x20,0x74,0x6f,0x20,0x70,0x72,0x6f,0x6d,0x6f,0x74,0x65,0xa,0x65,0x6e,0x64,0x6f,0x72,0x73,0x65,0x20,0x6f,0x72,0x20,0x61,0x64,0x76, + 0x65,0x72,0x74,0x69,0x73,0x65,0x20,0x61,0x6e,0x79,0x20,0x4d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0xa,0x65,0x78, + 0x63,0x65,0x70,0x74,0x20,0x74,0x6f,0x20,0x61,0x63,0x6b,0x6e,0x6f,0x77,0x6c,0x65,0x64,0x67,0x65,0x20,0x74,0x68,0x65,0x20,0x63,0x6f,0x6e,0x74,0x72,0x69, + 0x62,0x75,0x74,0x69,0x6f,0x6e,0x28,0x73,0x29,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0x48,0x6f,0x6c, + 0x64,0x65,0x72,0x28,0x73,0x29,0x20,0x61,0x6e,0x64,0x20,0x74,0x68,0x65,0x20,0x41,0x75,0x74,0x68,0x6f,0x72,0x28,0x73,0x29,0x20,0x6f,0x72,0x20,0x77,0x69, + 0x74,0x68,0x20,0x74,0x68,0x65,0x69,0x72,0x20,0x65,0x78,0x70,0x6c,0x69,0x63,0x69,0x74,0x20,0x77,0x72,0x69,0x74,0x74,0x65,0x6e,0x20,0x70,0x65,0x72,0x6d, + 0x69,0x73,0x73,0x69,0x6f,0x6e,0x2e,0xa,0xa,0x35,0x29,0x20,0x54,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0xa, + 0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0x20,0x6f,0x72,0x20,0x75,0x6e,0x6d,0x6f,0x64,0x69,0x66,0x69,0x65,0x64,0xa,0x69,0x6e,0x20,0x70,0x61,0x72,0x74, + 0x20,0x6f,0x72,0x20,0x69,0x6e,0x20,0x77,0x68,0x6f,0x6c,0x65,0xa,0x6d,0x75,0x73,0x74,0x20,0x62,0x65,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74, + 0x65,0x64,0x20,0x65,0x6e,0x74,0x69,0x72,0x65,0x6c,0x79,0x20,0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65, + 0xa,0x61,0x6e,0x64,0x20,0x6d,0x75,0x73,0x74,0x20,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x75, + 0x6e,0x64,0x65,0x72,0x20,0x61,0x6e,0x79,0x20,0x6f,0x74,0x68,0x65,0x72,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x2e,0x20,0x54,0x68,0x65,0x20,0x72,0x65, + 0x71,0x75,0x69,0x72,0x65,0x6d,0x65,0x6e,0x74,0x20,0x66,0x6f,0x72,0x20,0x66,0x6f,0x6e,0x74,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x6d,0x61,0x69,0x6e,0x20, + 0x75,0x6e,0x64,0x65,0x72,0x20,0x74,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x64,0x6f,0x65,0x73,0x20,0x6e,0x6f,0x74,0x20,0x61,0x70, + 0x70,0x6c,0x79,0x20,0x74,0x6f,0x20,0x61,0x6e,0x79,0x20,0x64,0x6f,0x63,0x75,0x6d,0x65,0x6e,0x74,0x20,0x63,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x75,0x73, + 0x69,0x6e,0x67,0x20,0x74,0x68,0x65,0x20,0x46,0x6f,0x6e,0x74,0x20,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x2e,0xa,0xa,0x54,0x45,0x52,0x4d,0x49,0x4e, + 0x41,0x54,0x49,0x4f,0x4e,0xa,0x54,0x68,0x69,0x73,0x20,0x6c,0x69,0x63,0x65,0x6e,0x73,0x65,0x20,0x62,0x65,0x63,0x6f,0x6d,0x65,0x73,0x20,0x6e,0x75,0x6c, + 0x6c,0x20,0x61,0x6e,0x64,0x20,0x76,0x6f,0x69,0x64,0x20,0x69,0x66,0x20,0x61,0x6e,0x79,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x61,0x62,0x6f,0x76,0x65, + 0x20,0x63,0x6f,0x6e,0x64,0x69,0x74,0x69,0x6f,0x6e,0x73,0x20,0x61,0x72,0x65,0x20,0x6e,0x6f,0x74,0x20,0x6d,0x65,0x74,0x2e,0xa,0xa,0x44,0x49,0x53,0x43, + 0x4c,0x41,0x49,0x4d,0x45,0x52,0xa,0x54,0x48,0x45,0x20,0x46,0x4f,0x4e,0x54,0x20,0x53,0x4f,0x46,0x54,0x57,0x41,0x52,0x45,0x20,0x49,0x53,0x20,0x50,0x52, + 0x4f,0x56,0x49,0x44,0x45,0x44,0x20,0x22,0x41,0x53,0x20,0x49,0x53,0x22,0xa,0x57,0x49,0x54,0x48,0x4f,0x55,0x54,0x20,0x57,0x41,0x52,0x52,0x41,0x4e,0x54, + 0x59,0x20,0x4f,0x46,0x20,0x41,0x4e,0x59,0x20,0x4b,0x49,0x4e,0x44,0xa,0x45,0x58,0x50,0x52,0x45,0x53,0x53,0x20,0x4f,0x52,0x20,0x49,0x4d,0x50,0x4c,0x49, + 0x45,0x44,0xa,0x49,0x4e,0x43,0x4c,0x55,0x44,0x49,0x4e,0x47,0x20,0x42,0x55,0x54,0x20,0x4e,0x4f,0x54,0x20,0x4c,0x49,0x4d,0x49,0x54,0x45,0x44,0x20,0x54, + 0x4f,0x20,0x41,0x4e,0x59,0x20,0x57,0x41,0x52,0x52,0x41,0x4e,0x54,0x49,0x45,0x53,0x20,0x4f,0x46,0x20,0x4d,0x45,0x52,0x43,0x48,0x41,0x4e,0x54,0x41,0x42, + 0x49,0x4c,0x49,0x54,0x59,0xa,0x46,0x49,0x54,0x4e,0x45,0x53,0x53,0x20,0x46,0x4f,0x52,0x20,0x41,0x20,0x50,0x41,0x52,0x54,0x49,0x43,0x55,0x4c,0x41,0x52, + 0x20,0x50,0x55,0x52,0x50,0x4f,0x53,0x45,0x20,0x41,0x4e,0x44,0x20,0x4e,0x4f,0x4e,0x49,0x4e,0x46,0x52,0x49,0x4e,0x47,0x45,0x4d,0x45,0x4e,0x54,0x20,0x4f, + 0x46,0x20,0x43,0x4f,0x50,0x59,0x52,0x49,0x47,0x48,0x54,0xa,0x50,0x41,0x54,0x45,0x4e,0x54,0xa,0x54,0x52,0x41,0x44,0x45,0x4d,0x41,0x52,0x4b,0xa,0x4f, + 0x52,0x20,0x4f,0x54,0x48,0x45,0x52,0x20,0x52,0x49,0x47,0x48,0x54,0x2e,0x20,0x49,0x4e,0x20,0x4e,0x4f,0x20,0x45,0x56,0x45,0x4e,0x54,0x20,0x53,0x48,0x41, + 0x4c,0x4c,0x20,0x54,0x48,0x45,0x20,0x43,0x4f,0x50,0x59,0x52,0x49,0x47,0x48,0x54,0x20,0x48,0x4f,0x4c,0x44,0x45,0x52,0x20,0x42,0x45,0x20,0x4c,0x49,0x41, + 0x42,0x4c,0x45,0x20,0x46,0x4f,0x52,0x20,0x41,0x4e,0x59,0x20,0x43,0x4c,0x41,0x49,0x4d,0xa,0x44,0x41,0x4d,0x41,0x47,0x45,0x53,0x20,0x4f,0x52,0x20,0x4f, + 0x54,0x48,0x45,0x52,0x20,0x4c,0x49,0x41,0x42,0x49,0x4c,0x49,0x54,0x59,0xa,0x49,0x4e,0x43,0x4c,0x55,0x44,0x49,0x4e,0x47,0x20,0x41,0x4e,0x59,0x20,0x47, + 0x45,0x4e,0x45,0x52,0x41,0x4c,0xa,0x53,0x50,0x45,0x43,0x49,0x41,0x4c,0xa,0x49,0x4e,0x44,0x49,0x52,0x45,0x43,0x54,0xa,0x49,0x4e,0x43,0x49,0x44,0x45, + 0x4e,0x54,0x41,0x4c,0xa,0x4f,0x52,0x20,0x43,0x4f,0x4e,0x53,0x45,0x51,0x55,0x45,0x4e,0x54,0x49,0x41,0x4c,0x20,0x44,0x41,0x4d,0x41,0x47,0x45,0x53,0xa, + 0x57,0x48,0x45,0x54,0x48,0x45,0x52,0x20,0x49,0x4e,0x20,0x41,0x4e,0x20,0x41,0x43,0x54,0x49,0x4f,0x4e,0x20,0x4f,0x46,0x20,0x43,0x4f,0x4e,0x54,0x52,0x41, + 0x43,0x54,0xa,0x54,0x4f,0x52,0x54,0x20,0x4f,0x52,0x20,0x4f,0x54,0x48,0x45,0x52,0x57,0x49,0x53,0x45,0xa,0x41,0x52,0x49,0x53,0x49,0x4e,0x47,0x20,0x46, + 0x52,0x4f,0x4d,0xa,0x4f,0x55,0x54,0x20,0x4f,0x46,0x20,0x54,0x48,0x45,0x20,0x55,0x53,0x45,0x20,0x4f,0x52,0x20,0x49,0x4e,0x41,0x42,0x49,0x4c,0x49,0x54, + 0x59,0x20,0x54,0x4f,0x20,0x55,0x53,0x45,0x20,0x54,0x48,0x45,0x20,0x46,0x4f,0x4e,0x54,0x20,0x53,0x4f,0x46,0x54,0x57,0x41,0x52,0x45,0x20,0x4f,0x52,0x20, + 0x46,0x52,0x4f,0x4d,0x20,0x4f,0x54,0x48,0x45,0x52,0x20,0x44,0x45,0x41,0x4c,0x49,0x4e,0x47,0x53,0x20,0x49,0x4e,0x20,0x54,0x48,0x45,0x20,0x46,0x4f,0x4e, + 0x54,0x20,0x53,0x4f,0x46,0x54,0x57,0x41,0x52,0x45,0x2e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x63,0x72,0x69,0x70,0x74,0x73,0x2e,0x73,0x69,0x6c,0x2e, + 0x6f,0x72,0x67,0x2f,0x4f,0x46,0x4c,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x28,0x0, + 0x63,0x0,0x29,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x31,0x0,0x35,0x0,0x20,0x0,0x51,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x2d,0x0,0x55,0x0, + 0x6e,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x41,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x2e,0x0,0x43,0x0,0x6f,0x0,0x75,0x0, + 0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0, + 0x49,0x0,0x74,0x0,0x61,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x33,0x0,0x2e,0x0,0x30,0x0,0x31,0x0,0x38,0x0,0x3b,0x0,0x51,0x0,0x55,0x0,0x51,0x0, + 0x41,0x0,0x3b,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x43,0x0, + 0x6f,0x0,0x64,0x0,0x65,0x0,0x2d,0x0,0x49,0x0,0x74,0x0,0x61,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0, + 0x65,0x0,0x72,0x0,0x20,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0,0x20,0x0,0x49,0x0, + 0x74,0x0,0x61,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x33,0x0,0x2e,0x0, + 0x30,0x0,0x33,0x0,0x31,0x0,0x38,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0, + 0x65,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0,0x2d,0x0,0x49,0x0,0x74,0x0,0x61,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x51,0x0,0x75,0x0,0x6f,0x0, + 0x74,0x0,0x65,0x0,0x2d,0x0,0x55,0x0,0x6e,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x41,0x0,0x70,0x0,0x70,0x0,0x73,0x0, + 0x41,0x0,0x6c,0x0,0x61,0x0,0x6e,0x0,0x20,0x0,0x44,0x0,0x61,0x0,0x67,0x0,0x75,0x0,0x65,0x0,0x2d,0x0,0x47,0x0,0x72,0x0,0x65,0x0,0x65,0x0, + 0x6e,0x0,0x65,0x0,0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x75,0x0, + 0x6e,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x68,0x0, + 0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x62,0x0,0x61,0x0,0x73,0x0,0x69,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x63,0x0,0x69,0x0, + 0x70,0x0,0x65,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0, + 0x20,0x0,0x28,0x0,0x63,0x0,0x29,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x31,0x0,0x35,0x0,0xa,0x0,0x51,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0, + 0x2d,0x0,0x55,0x0,0x6e,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x41,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x20,0x0,0x28,0x0, + 0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x71,0x0,0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x75,0x0,0x6e,0x0,0x71,0x0, + 0x75,0x0,0x6f,0x0,0x74,0x0,0x65,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x73,0x0,0x2e,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x29,0x0,0xa,0x0,0x77,0x0, + 0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x52,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x46,0x0,0x6f,0x0, + 0x6e,0x0,0x74,0x0,0x20,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x75,0x0,0x72,0x0,0x69,0x0,0x65,0x0,0x72,0x0, + 0x20,0x0,0x50,0x0,0x72,0x0,0x69,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x64,0x0,0x65,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x54,0x0, + 0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0, + 0x72,0x0,0x65,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0, + 0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x53,0x0,0x49,0x0,0x4c,0x0,0x20,0x0,0x4f,0x0, + 0x70,0x0,0x65,0x0,0x6e,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x4c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0, + 0x65,0x0,0xa,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x31,0x0,0x2e,0x0,0x31,0x0,0x2e,0x0,0x20,0x0, + 0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x69,0x0,0x73,0x0, + 0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x6c,0x0,0x6f,0x0,0x77,0x0,0xa,0x0,0x61,0x0, + 0x6e,0x0,0x64,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x6c,0x0,0x73,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x76,0x0,0x61,0x0,0x69,0x0, + 0x6c,0x0,0x61,0x0,0x62,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x20,0x0,0x46,0x0,0x41,0x0, + 0x51,0x0,0x20,0x0,0x61,0x0,0x74,0x0,0x3a,0x0,0x20,0x0,0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0,0x3a,0x0,0x2f,0x0,0x2f,0x0,0x73,0x0,0x63,0x0, + 0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x73,0x0,0x2e,0x0,0x73,0x0,0x69,0x0,0x6c,0x0,0x2e,0x0,0x6f,0x0,0x72,0x0,0x67,0x0,0x2f,0x0,0x4f,0x0, + 0x46,0x0,0x4c,0x0,0xa,0x0,0xa,0x0,0xa,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0xa,0x0,0x53,0x0,0x49,0x0,0x4c,0x0,0x20,0x0,0x4f,0x0,0x50,0x0,0x45,0x0,0x4e,0x0,0x20,0x0,0x46,0x0, + 0x4f,0x0,0x4e,0x0,0x54,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x43,0x0,0x45,0x0,0x4e,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0, + 0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x31,0x0,0x2e,0x0,0x31,0x0,0x20,0x0,0x2d,0x0,0x20,0x0,0x32,0x0,0x36,0x0,0x20,0x0,0x46,0x0, + 0x65,0x0,0x62,0x0,0x72,0x0,0x75,0x0,0x61,0x0,0x72,0x0,0x79,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x30,0x0,0x37,0x0,0xa,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0, + 0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0x2d,0x0,0xa,0x0,0xa,0x0,0x50,0x0, + 0x52,0x0,0x45,0x0,0x41,0x0,0x4d,0x0,0x42,0x0,0x4c,0x0,0x45,0x0,0xa,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x67,0x0,0x6f,0x0,0x61,0x0, + 0x6c,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x4f,0x0,0x70,0x0,0x65,0x0,0x6e,0x0,0x20,0x0, + 0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x4c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x28,0x0,0x4f,0x0, + 0x46,0x0,0x4c,0x0,0x29,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x73,0x0,0x74,0x0,0x69,0x0,0x6d,0x0, + 0x75,0x0,0x6c,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6c,0x0,0x64,0x0,0x77,0x0,0x69,0x0,0x64,0x0,0x65,0x0, + 0x20,0x0,0x64,0x0,0x65,0x0,0x76,0x0,0x65,0x0,0x6c,0x0,0x6f,0x0,0x70,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x66,0x0, + 0x20,0x0,0x63,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x61,0x0,0x62,0x0,0x6f,0x0,0x72,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0, + 0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x6a,0x0,0x65,0x0,0x63,0x0,0x74,0x0,0x73,0x0,0xa,0x0,0x74,0x0, + 0x6f,0x0,0x20,0x0,0x73,0x0,0x75,0x0,0x70,0x0,0x70,0x0,0x6f,0x0,0x72,0x0,0x74,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0, + 0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x65,0x0,0x66,0x0, + 0x66,0x0,0x6f,0x0,0x72,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x61,0x0,0x63,0x0,0x61,0x0,0x64,0x0,0x65,0x0,0x6d,0x0, + 0x69,0x0,0x63,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x75,0x0,0x69,0x0,0x73,0x0,0x74,0x0, + 0x69,0x0,0x63,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x6d,0x0,0x75,0x0,0x6e,0x0,0x69,0x0,0x74,0x0,0x69,0x0,0x65,0x0,0x73,0x0,0xa,0x0, + 0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x69,0x0,0x64,0x0,0x65,0x0,0x20,0x0, + 0x61,0x0,0x20,0x0,0x66,0x0,0x72,0x0,0x65,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x6f,0x0,0x70,0x0,0x65,0x0,0x6e,0x0, + 0x20,0x0,0x66,0x0,0x72,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6b,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x77,0x0, + 0x68,0x0,0x69,0x0,0x63,0x0,0x68,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0, + 0x62,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x68,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x69,0x0, + 0x6d,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x61,0x0,0x72,0x0,0x74,0x0, + 0x6e,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x68,0x0,0x69,0x0,0x70,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x6f,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x4c,0x0,0x20,0x0, + 0x61,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x77,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0, + 0x6e,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x62,0x0, + 0x65,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x73,0x0,0x74,0x0,0x75,0x0,0x64,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0xa,0x0, + 0x6d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x72,0x0,0x65,0x0, + 0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x66,0x0,0x72,0x0,0x65,0x0, + 0x65,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x6f,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x73,0x0,0x6f,0x0, + 0x6c,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x6d,0x0,0x73,0x0,0x65,0x0,0x6c,0x0,0x76,0x0,0x65,0x0, + 0x73,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0xa,0x0,0x69,0x0,0x6e,0x0, + 0x63,0x0,0x6c,0x0,0x75,0x0,0x64,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0, + 0x69,0x0,0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6b,0x0,0x73,0x0,0xa,0x0,0x63,0x0, + 0x61,0x0,0x6e,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x62,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x6c,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x65,0x0, + 0x6d,0x0,0x62,0x0,0x65,0x0,0x64,0x0,0x64,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0, + 0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x2f,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x73,0x0, + 0x6f,0x0,0x6c,0x0,0x64,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x73,0x0,0x6f,0x0, + 0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x69,0x0,0x64,0x0,0x65,0x0,0x64,0x0, + 0x20,0x0,0x74,0x0,0x68,0x0,0x61,0x0,0x74,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0, + 0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6e,0x0, + 0x6f,0x0,0x74,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0, + 0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x77,0x0,0x6f,0x0,0x72,0x0,0x6b,0x0,0x73,0x0,0x2e,0x0,0x20,0x0,0x54,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x64,0x0,0x65,0x0, + 0x72,0x0,0x69,0x0,0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x68,0x0,0x6f,0x0,0x77,0x0,0x65,0x0,0x76,0x0, + 0x65,0x0,0x72,0x0,0xa,0x0,0x63,0x0,0x61,0x0,0x6e,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x72,0x0,0x65,0x0, + 0x6c,0x0,0x65,0x0,0x61,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x6e,0x0, + 0x79,0x0,0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x79,0x0,0x70,0x0,0x65,0x0,0x20,0x0,0x6f,0x0,0x66,0x0, + 0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x72,0x0, + 0x65,0x0,0x71,0x0,0x75,0x0,0x69,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x72,0x0,0x20,0x0, + 0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x61,0x0,0x69,0x0,0x6e,0x0, + 0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0, + 0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x61,0x0, + 0x70,0x0,0x70,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x63,0x0, + 0x75,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0, + 0x73,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0, + 0x6f,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x69,0x0,0x72,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0,0x76,0x0,0x61,0x0, + 0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x73,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x44,0x0,0x45,0x0,0x46,0x0,0x49,0x0,0x4e,0x0,0x49,0x0,0x54,0x0, + 0x49,0x0,0x4f,0x0,0x4e,0x0,0x53,0x0,0xa,0x0,0x22,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0, + 0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0, + 0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x65,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x6c,0x0, + 0x65,0x0,0x73,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6c,0x0,0x65,0x0,0x61,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0, + 0x6f,0x0,0x6c,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0, + 0x64,0x0,0x20,0x0,0x63,0x0,0x6c,0x0,0x65,0x0,0x61,0x0,0x72,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x72,0x0,0x6b,0x0,0x65,0x0, + 0x64,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x75,0x0,0x63,0x0,0x68,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0, + 0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x63,0x0,0x6c,0x0,0x75,0x0,0x64,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x6f,0x0, + 0x75,0x0,0x72,0x0,0x63,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x62,0x0,0x75,0x0,0x69,0x0,0x6c,0x0, + 0x64,0x0,0x20,0x0,0x73,0x0,0x63,0x0,0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x64,0x0, + 0x6f,0x0,0x63,0x0,0x75,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x2e,0x0,0xa,0x0,0xa,0x0, + 0x22,0x0,0x52,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0, + 0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0, + 0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x70,0x0,0x65,0x0,0x63,0x0, + 0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x75,0x0,0x63,0x0,0x68,0x0,0x20,0x0,0x61,0x0, + 0x66,0x0,0x74,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0, + 0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x73,0x0,0x74,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x28,0x0,0x73,0x0, + 0x29,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x22,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x56,0x0, + 0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0, + 0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x65,0x0,0x63,0x0,0x74,0x0,0x69,0x0, + 0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0, + 0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x73,0x0, + 0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0, + 0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0, + 0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0,0x6c,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x2e,0x0,0xa,0x0,0xa,0x0, + 0x22,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0, + 0x6f,0x0,0x6e,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0, + 0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x69,0x0,0x76,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x6d,0x0, + 0x61,0x0,0x64,0x0,0x65,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x64,0x0,0x64,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0, + 0x6f,0x0,0xa,0x0,0x64,0x0,0x65,0x0,0x6c,0x0,0x65,0x0,0x74,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0xa,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x73,0x0, + 0x75,0x0,0x62,0x0,0x73,0x0,0x74,0x0,0x69,0x0,0x74,0x0,0x75,0x0,0x74,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x2d,0x0,0x2d,0x0,0x20,0x0, + 0x69,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x61,0x0,0x72,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x77,0x0, + 0x68,0x0,0x6f,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x2d,0x0,0x2d,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0, + 0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0, + 0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0xa,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x63,0x0,0x68,0x0,0x61,0x0, + 0x6e,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x72,0x0,0x6d,0x0,0x61,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x6f,0x0, + 0x72,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x70,0x0,0x6f,0x0,0x72,0x0,0x74,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x68,0x0, + 0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0, + 0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x20,0x0,0x6e,0x0,0x65,0x0,0x77,0x0,0x20,0x0,0x65,0x0,0x6e,0x0,0x76,0x0,0x69,0x0,0x72,0x0, + 0x6f,0x0,0x6e,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x22,0x0,0x41,0x0,0x75,0x0,0x74,0x0,0x68,0x0,0x6f,0x0, + 0x72,0x0,0x22,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x66,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0, + 0x79,0x0,0x20,0x0,0x64,0x0,0x65,0x0,0x73,0x0,0x69,0x0,0x67,0x0,0x6e,0x0,0x65,0x0,0x72,0x0,0xa,0x0,0x65,0x0,0x6e,0x0,0x67,0x0,0x69,0x0, + 0x6e,0x0,0x65,0x0,0x65,0x0,0x72,0x0,0xa,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x67,0x0,0x72,0x0,0x61,0x0,0x6d,0x0,0x6d,0x0,0x65,0x0,0x72,0x0, + 0xa,0x0,0x74,0x0,0x65,0x0,0x63,0x0,0x68,0x0,0x6e,0x0,0x69,0x0,0x63,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x77,0x0,0x72,0x0,0x69,0x0,0x74,0x0, + 0x65,0x0,0x72,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0, + 0x73,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x77,0x0,0x68,0x0,0x6f,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0, + 0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0, + 0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x50,0x0,0x45,0x0, + 0x52,0x0,0x4d,0x0,0x49,0x0,0x53,0x0,0x53,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x20,0x0,0x26,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x4e,0x0,0x44,0x0, + 0x49,0x0,0x54,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x53,0x0,0xa,0x0,0x50,0x0,0x65,0x0,0x72,0x0,0x6d,0x0,0x69,0x0,0x73,0x0,0x73,0x0,0x69,0x0, + 0x6f,0x0,0x6e,0x0,0x20,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x65,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x67,0x0,0x72,0x0, + 0x61,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x66,0x0,0x72,0x0,0x65,0x0,0x65,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x63,0x0, + 0x68,0x0,0x61,0x0,0x72,0x0,0x67,0x0,0x65,0x0,0xa,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x70,0x0,0x65,0x0, + 0x72,0x0,0x73,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0,0x62,0x0,0x74,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0, + 0x61,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0, + 0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0,0x74,0x0,0x6f,0x0, + 0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0xa,0x0,0x73,0x0,0x74,0x0,0x75,0x0,0x64,0x0,0x79,0x0,0xa,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0, + 0xa,0x0,0x6d,0x0,0x65,0x0,0x72,0x0,0x67,0x0,0x65,0x0,0xa,0x0,0x65,0x0,0x6d,0x0,0x62,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x6d,0x0,0x6f,0x0, + 0x64,0x0,0x69,0x0,0x66,0x0,0x79,0x0,0xa,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0, + 0x74,0x0,0x65,0x0,0xa,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x73,0x0,0x65,0x0,0x6c,0x0,0x6c,0x0,0x20,0x0,0x6d,0x0,0x6f,0x0,0x64,0x0, + 0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x6d,0x0,0x6f,0x0,0x64,0x0, + 0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x69,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0, + 0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0, + 0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0,0x73,0x0,0x75,0x0,0x62,0x0,0x6a,0x0,0x65,0x0,0x63,0x0,0x74,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x77,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x63,0x0, + 0x6f,0x0,0x6e,0x0,0x64,0x0,0x69,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x73,0x0,0x3a,0x0,0xa,0x0,0xa,0x0,0x31,0x0,0x29,0x0,0x20,0x0, + 0x4e,0x0,0x65,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0, + 0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x72,0x0,0x20,0x0, + 0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x69,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x64,0x0,0x69,0x0, + 0x76,0x0,0x69,0x0,0x64,0x0,0x75,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x6e,0x0, + 0x74,0x0,0x73,0x0,0xa,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0, + 0x6f,0x0,0x72,0x0,0x20,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0, + 0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x73,0x0,0xa,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x73,0x0,0x6f,0x0, + 0x6c,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x69,0x0,0x74,0x0,0x73,0x0,0x65,0x0,0x6c,0x0,0x66,0x0,0x2e,0x0,0xa,0x0,0xa,0x0, + 0x32,0x0,0x29,0x0,0x20,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0, + 0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0, + 0x6e,0x0,0x73,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0, + 0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x62,0x0,0x65,0x0, + 0x20,0x0,0x62,0x0,0x75,0x0,0x6e,0x0,0x64,0x0,0x6c,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x72,0x0,0x65,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0, + 0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x2f,0x0,0x6f,0x0,0x72,0x0,0x20,0x0, + 0x73,0x0,0x6f,0x0,0x6c,0x0,0x64,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x73,0x0, + 0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x76,0x0,0x69,0x0,0x64,0x0,0x65,0x0, + 0x64,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x61,0x0,0x74,0x0,0x20,0x0,0x65,0x0,0x61,0x0,0x63,0x0,0x68,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0, + 0x79,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0, + 0x61,0x0,0x62,0x0,0x6f,0x0,0x76,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0, + 0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0, + 0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x73,0x0, + 0x65,0x0,0x20,0x0,0x63,0x0,0x61,0x0,0x6e,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x63,0x0,0x6c,0x0,0x75,0x0,0x64,0x0, + 0x65,0x0,0x64,0x0,0x20,0x0,0x65,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x73,0x0,0x74,0x0, + 0x61,0x0,0x6e,0x0,0x64,0x0,0x2d,0x0,0x61,0x0,0x6c,0x0,0x6f,0x0,0x6e,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x65,0x0,0x78,0x0,0x74,0x0,0x20,0x0, + 0x66,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0xa,0x0,0x68,0x0,0x75,0x0,0x6d,0x0,0x61,0x0,0x6e,0x0,0x2d,0x0,0x72,0x0,0x65,0x0,0x61,0x0, + 0x64,0x0,0x61,0x0,0x62,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x68,0x0,0x65,0x0,0x61,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x20,0x0,0x6f,0x0, + 0x72,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x70,0x0, + 0x72,0x0,0x69,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x63,0x0,0x68,0x0,0x69,0x0,0x6e,0x0,0x65,0x0,0x2d,0x0,0x72,0x0, + 0x65,0x0,0x61,0x0,0x64,0x0,0x61,0x0,0x62,0x0,0x6c,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x65,0x0,0x74,0x0,0x61,0x0,0x64,0x0,0x61,0x0,0x74,0x0, + 0x61,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x6c,0x0,0x64,0x0,0x73,0x0,0x20,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x6e,0x0, + 0x20,0x0,0x74,0x0,0x65,0x0,0x78,0x0,0x74,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x62,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x72,0x0,0x79,0x0, + 0x20,0x0,0x66,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x6f,0x0,0x6e,0x0,0x67,0x0,0x20,0x0, + 0x61,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x6c,0x0,0x64,0x0,0x73,0x0, + 0x20,0x0,0x63,0x0,0x61,0x0,0x6e,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x65,0x0,0x61,0x0,0x73,0x0,0x69,0x0,0x6c,0x0,0x79,0x0,0x20,0x0, + 0x76,0x0,0x69,0x0,0x65,0x0,0x77,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x75,0x0, + 0x73,0x0,0x65,0x0,0x72,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x33,0x0,0x29,0x0,0x20,0x0,0x4e,0x0,0x6f,0x0,0x20,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0, + 0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0, + 0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0, + 0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x20,0x0,0x6d,0x0,0x61,0x0,0x79,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x68,0x0, + 0x65,0x0,0x20,0x0,0x52,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x76,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0, + 0x20,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x6c,0x0,0x65,0x0,0x73,0x0,0x73,0x0, + 0x20,0x0,0x65,0x0,0x78,0x0,0x70,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x69,0x0,0x74,0x0,0x20,0x0,0x77,0x0,0x72,0x0,0x69,0x0,0x74,0x0,0x74,0x0, + 0x65,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0,0x6d,0x0,0x69,0x0,0x73,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x69,0x0, + 0x73,0x0,0x20,0x0,0x67,0x0,0x72,0x0,0x61,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x62,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x68,0x0, + 0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x72,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x70,0x0,0x6f,0x0,0x6e,0x0,0x64,0x0,0x69,0x0,0x6e,0x0,0x67,0x0, + 0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0,0x6c,0x0,0x64,0x0, + 0x65,0x0,0x72,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0, + 0x63,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x20,0x0,0x6f,0x0,0x6e,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x61,0x0,0x70,0x0,0x70,0x0,0x6c,0x0, + 0x69,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x69,0x0,0x6d,0x0, + 0x61,0x0,0x72,0x0,0x79,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x20,0x0,0x61,0x0, + 0x73,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x65,0x0,0x73,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x75,0x0,0x73,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x34,0x0,0x29,0x0,0x20,0x0, + 0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0, + 0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0, + 0x6f,0x0,0x6c,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0, + 0x20,0x0,0x41,0x0,0x75,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0, + 0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0, + 0x65,0x0,0x20,0x0,0x73,0x0,0x68,0x0,0x61,0x0,0x6c,0x0,0x6c,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0, + 0x75,0x0,0x73,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x70,0x0,0x72,0x0,0x6f,0x0,0x6d,0x0,0x6f,0x0,0x74,0x0,0x65,0x0, + 0xa,0x0,0x65,0x0,0x6e,0x0,0x64,0x0,0x6f,0x0,0x72,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x64,0x0,0x76,0x0, + 0x65,0x0,0x72,0x0,0x74,0x0,0x69,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x4d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0, + 0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0xa,0x0,0x65,0x0,0x78,0x0, + 0x63,0x0,0x65,0x0,0x70,0x0,0x74,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x63,0x0,0x6b,0x0,0x6e,0x0,0x6f,0x0,0x77,0x0,0x6c,0x0, + 0x65,0x0,0x64,0x0,0x67,0x0,0x65,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x72,0x0,0x69,0x0, + 0x62,0x0,0x75,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0, + 0x65,0x0,0x20,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0x48,0x0,0x6f,0x0,0x6c,0x0, + 0x64,0x0,0x65,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0, + 0x41,0x0,0x75,0x0,0x74,0x0,0x68,0x0,0x6f,0x0,0x72,0x0,0x28,0x0,0x73,0x0,0x29,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x77,0x0,0x69,0x0, + 0x74,0x0,0x68,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x69,0x0,0x72,0x0,0x20,0x0,0x65,0x0,0x78,0x0,0x70,0x0,0x6c,0x0,0x69,0x0,0x63,0x0, + 0x69,0x0,0x74,0x0,0x20,0x0,0x77,0x0,0x72,0x0,0x69,0x0,0x74,0x0,0x74,0x0,0x65,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x65,0x0,0x72,0x0,0x6d,0x0, + 0x69,0x0,0x73,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x35,0x0,0x29,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0, + 0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0,0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0xa,0x0, + 0x6d,0x0,0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x6d,0x0, + 0x6f,0x0,0x64,0x0,0x69,0x0,0x66,0x0,0x69,0x0,0x65,0x0,0x64,0x0,0xa,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x70,0x0,0x61,0x0,0x72,0x0,0x74,0x0, + 0x20,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x69,0x0,0x6e,0x0,0x20,0x0,0x77,0x0,0x68,0x0,0x6f,0x0,0x6c,0x0,0x65,0x0,0xa,0x0,0x6d,0x0,0x75,0x0, + 0x73,0x0,0x74,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x20,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0, + 0x65,0x0,0x64,0x0,0x20,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x69,0x0,0x72,0x0,0x65,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x75,0x0,0x6e,0x0,0x64,0x0, + 0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0, + 0xa,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x6d,0x0,0x75,0x0,0x73,0x0,0x74,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x62,0x0, + 0x65,0x0,0x20,0x0,0x64,0x0,0x69,0x0,0x73,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x62,0x0,0x75,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0, + 0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x72,0x0,0x20,0x0, + 0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0,0x6e,0x0,0x73,0x0,0x65,0x0,0x2e,0x0,0x20,0x0,0x54,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x72,0x0,0x65,0x0, + 0x71,0x0,0x75,0x0,0x69,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x66,0x0,0x6f,0x0,0x72,0x0,0x20,0x0,0x66,0x0, + 0x6f,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x72,0x0,0x65,0x0,0x6d,0x0,0x61,0x0,0x69,0x0,0x6e,0x0,0x20,0x0, + 0x75,0x0,0x6e,0x0,0x64,0x0,0x65,0x0,0x72,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0, + 0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x61,0x0,0x70,0x0, + 0x70,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x74,0x0,0x6f,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x20,0x0,0x64,0x0,0x6f,0x0,0x63,0x0,0x75,0x0, + 0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x63,0x0,0x72,0x0,0x65,0x0,0x61,0x0,0x74,0x0,0x65,0x0,0x64,0x0,0x20,0x0,0x75,0x0,0x73,0x0, + 0x69,0x0,0x6e,0x0,0x67,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x46,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x20,0x0,0x53,0x0,0x6f,0x0, + 0x66,0x0,0x74,0x0,0x77,0x0,0x61,0x0,0x72,0x0,0x65,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x54,0x0,0x45,0x0,0x52,0x0,0x4d,0x0,0x49,0x0,0x4e,0x0, + 0x41,0x0,0x54,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0xa,0x0,0x54,0x0,0x68,0x0,0x69,0x0,0x73,0x0,0x20,0x0,0x6c,0x0,0x69,0x0,0x63,0x0,0x65,0x0, + 0x6e,0x0,0x73,0x0,0x65,0x0,0x20,0x0,0x62,0x0,0x65,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x65,0x0,0x73,0x0,0x20,0x0,0x6e,0x0,0x75,0x0,0x6c,0x0, + 0x6c,0x0,0x20,0x0,0x61,0x0,0x6e,0x0,0x64,0x0,0x20,0x0,0x76,0x0,0x6f,0x0,0x69,0x0,0x64,0x0,0x20,0x0,0x69,0x0,0x66,0x0,0x20,0x0,0x61,0x0, + 0x6e,0x0,0x79,0x0,0x20,0x0,0x6f,0x0,0x66,0x0,0x20,0x0,0x74,0x0,0x68,0x0,0x65,0x0,0x20,0x0,0x61,0x0,0x62,0x0,0x6f,0x0,0x76,0x0,0x65,0x0, + 0x20,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x64,0x0,0x69,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x73,0x0,0x20,0x0,0x61,0x0,0x72,0x0,0x65,0x0, + 0x20,0x0,0x6e,0x0,0x6f,0x0,0x74,0x0,0x20,0x0,0x6d,0x0,0x65,0x0,0x74,0x0,0x2e,0x0,0xa,0x0,0xa,0x0,0x44,0x0,0x49,0x0,0x53,0x0,0x43,0x0, + 0x4c,0x0,0x41,0x0,0x49,0x0,0x4d,0x0,0x45,0x0,0x52,0x0,0xa,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x4e,0x0,0x54,0x0, + 0x20,0x0,0x53,0x0,0x4f,0x0,0x46,0x0,0x54,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x45,0x0,0x20,0x0,0x49,0x0,0x53,0x0,0x20,0x0,0x50,0x0,0x52,0x0, + 0x4f,0x0,0x56,0x0,0x49,0x0,0x44,0x0,0x45,0x0,0x44,0x0,0x20,0x0,0x22,0x0,0x41,0x0,0x53,0x0,0x20,0x0,0x49,0x0,0x53,0x0,0x22,0x0,0xa,0x0, + 0x57,0x0,0x49,0x0,0x54,0x0,0x48,0x0,0x4f,0x0,0x55,0x0,0x54,0x0,0x20,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x52,0x0,0x41,0x0,0x4e,0x0,0x54,0x0, + 0x59,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x4b,0x0,0x49,0x0,0x4e,0x0,0x44,0x0,0xa,0x0,0x45,0x0, + 0x58,0x0,0x50,0x0,0x52,0x0,0x45,0x0,0x53,0x0,0x53,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x49,0x0,0x4d,0x0,0x50,0x0,0x4c,0x0,0x49,0x0, + 0x45,0x0,0x44,0x0,0xa,0x0,0x49,0x0,0x4e,0x0,0x43,0x0,0x4c,0x0,0x55,0x0,0x44,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x20,0x0,0x42,0x0,0x55,0x0, + 0x54,0x0,0x20,0x0,0x4e,0x0,0x4f,0x0,0x54,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x4d,0x0,0x49,0x0,0x54,0x0,0x45,0x0,0x44,0x0,0x20,0x0,0x54,0x0, + 0x4f,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x52,0x0,0x41,0x0,0x4e,0x0,0x54,0x0,0x49,0x0,0x45,0x0, + 0x53,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x4d,0x0,0x45,0x0,0x52,0x0,0x43,0x0,0x48,0x0,0x41,0x0,0x4e,0x0,0x54,0x0,0x41,0x0,0x42,0x0, + 0x49,0x0,0x4c,0x0,0x49,0x0,0x54,0x0,0x59,0x0,0xa,0x0,0x46,0x0,0x49,0x0,0x54,0x0,0x4e,0x0,0x45,0x0,0x53,0x0,0x53,0x0,0x20,0x0,0x46,0x0, + 0x4f,0x0,0x52,0x0,0x20,0x0,0x41,0x0,0x20,0x0,0x50,0x0,0x41,0x0,0x52,0x0,0x54,0x0,0x49,0x0,0x43,0x0,0x55,0x0,0x4c,0x0,0x41,0x0,0x52,0x0, + 0x20,0x0,0x50,0x0,0x55,0x0,0x52,0x0,0x50,0x0,0x4f,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x44,0x0,0x20,0x0,0x4e,0x0,0x4f,0x0, + 0x4e,0x0,0x49,0x0,0x4e,0x0,0x46,0x0,0x52,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x45,0x0,0x4d,0x0,0x45,0x0,0x4e,0x0,0x54,0x0,0x20,0x0,0x4f,0x0, + 0x46,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x50,0x0,0x59,0x0,0x52,0x0,0x49,0x0,0x47,0x0,0x48,0x0,0x54,0x0,0xa,0x0,0x50,0x0,0x41,0x0,0x54,0x0, + 0x45,0x0,0x4e,0x0,0x54,0x0,0xa,0x0,0x54,0x0,0x52,0x0,0x41,0x0,0x44,0x0,0x45,0x0,0x4d,0x0,0x41,0x0,0x52,0x0,0x4b,0x0,0xa,0x0,0x4f,0x0, + 0x52,0x0,0x20,0x0,0x4f,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x52,0x0,0x49,0x0,0x47,0x0,0x48,0x0,0x54,0x0,0x2e,0x0,0x20,0x0, + 0x49,0x0,0x4e,0x0,0x20,0x0,0x4e,0x0,0x4f,0x0,0x20,0x0,0x45,0x0,0x56,0x0,0x45,0x0,0x4e,0x0,0x54,0x0,0x20,0x0,0x53,0x0,0x48,0x0,0x41,0x0, + 0x4c,0x0,0x4c,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x50,0x0,0x59,0x0,0x52,0x0,0x49,0x0,0x47,0x0,0x48,0x0, + 0x54,0x0,0x20,0x0,0x48,0x0,0x4f,0x0,0x4c,0x0,0x44,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x42,0x0,0x45,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x41,0x0, + 0x42,0x0,0x4c,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x43,0x0,0x4c,0x0,0x41,0x0, + 0x49,0x0,0x4d,0x0,0xa,0x0,0x44,0x0,0x41,0x0,0x4d,0x0,0x41,0x0,0x47,0x0,0x45,0x0,0x53,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x4f,0x0, + 0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x4c,0x0,0x49,0x0,0x41,0x0,0x42,0x0,0x49,0x0,0x4c,0x0,0x49,0x0,0x54,0x0,0x59,0x0,0xa,0x0, + 0x49,0x0,0x4e,0x0,0x43,0x0,0x4c,0x0,0x55,0x0,0x44,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x59,0x0,0x20,0x0,0x47,0x0, + 0x45,0x0,0x4e,0x0,0x45,0x0,0x52,0x0,0x41,0x0,0x4c,0x0,0xa,0x0,0x53,0x0,0x50,0x0,0x45,0x0,0x43,0x0,0x49,0x0,0x41,0x0,0x4c,0x0,0xa,0x0, + 0x49,0x0,0x4e,0x0,0x44,0x0,0x49,0x0,0x52,0x0,0x45,0x0,0x43,0x0,0x54,0x0,0xa,0x0,0x49,0x0,0x4e,0x0,0x43,0x0,0x49,0x0,0x44,0x0,0x45,0x0, + 0x4e,0x0,0x54,0x0,0x41,0x0,0x4c,0x0,0xa,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x4e,0x0,0x53,0x0,0x45,0x0,0x51,0x0,0x55,0x0, + 0x45,0x0,0x4e,0x0,0x54,0x0,0x49,0x0,0x41,0x0,0x4c,0x0,0x20,0x0,0x44,0x0,0x41,0x0,0x4d,0x0,0x41,0x0,0x47,0x0,0x45,0x0,0x53,0x0,0xa,0x0, + 0x57,0x0,0x48,0x0,0x45,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x49,0x0,0x4e,0x0,0x20,0x0,0x41,0x0,0x4e,0x0,0x20,0x0,0x41,0x0, + 0x43,0x0,0x54,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x43,0x0,0x4f,0x0,0x4e,0x0,0x54,0x0,0x52,0x0,0x41,0x0, + 0x43,0x0,0x54,0x0,0xa,0x0,0x54,0x0,0x4f,0x0,0x52,0x0,0x54,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x4f,0x0,0x54,0x0,0x48,0x0,0x45,0x0, + 0x52,0x0,0x57,0x0,0x49,0x0,0x53,0x0,0x45,0x0,0xa,0x0,0x41,0x0,0x52,0x0,0x49,0x0,0x53,0x0,0x49,0x0,0x4e,0x0,0x47,0x0,0x20,0x0,0x46,0x0, + 0x52,0x0,0x4f,0x0,0x4d,0x0,0xa,0x0,0x4f,0x0,0x55,0x0,0x54,0x0,0x20,0x0,0x4f,0x0,0x46,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0, + 0x55,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0,0x49,0x0,0x4e,0x0,0x41,0x0,0x42,0x0,0x49,0x0,0x4c,0x0,0x49,0x0,0x54,0x0, + 0x59,0x0,0x20,0x0,0x54,0x0,0x4f,0x0,0x20,0x0,0x55,0x0,0x53,0x0,0x45,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0, + 0x4e,0x0,0x54,0x0,0x20,0x0,0x53,0x0,0x4f,0x0,0x46,0x0,0x54,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x45,0x0,0x20,0x0,0x4f,0x0,0x52,0x0,0x20,0x0, + 0x46,0x0,0x52,0x0,0x4f,0x0,0x4d,0x0,0x20,0x0,0x4f,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x52,0x0,0x20,0x0,0x44,0x0,0x45,0x0,0x41,0x0,0x4c,0x0, + 0x49,0x0,0x4e,0x0,0x47,0x0,0x53,0x0,0x20,0x0,0x49,0x0,0x4e,0x0,0x20,0x0,0x54,0x0,0x48,0x0,0x45,0x0,0x20,0x0,0x46,0x0,0x4f,0x0,0x4e,0x0, + 0x54,0x0,0x20,0x0,0x53,0x0,0x4f,0x0,0x46,0x0,0x54,0x0,0x57,0x0,0x41,0x0,0x52,0x0,0x45,0x0,0x2e,0x0,0x68,0x0,0x74,0x0,0x74,0x0,0x70,0x0, + 0x3a,0x0,0x2f,0x0,0x2f,0x0,0x73,0x0,0x63,0x0,0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x73,0x0,0x2e,0x0,0x73,0x0,0x69,0x0,0x6c,0x0,0x2e,0x0, + 0x6f,0x0,0x72,0x0,0x67,0x0,0x2f,0x0,0x4f,0x0,0x46,0x0,0x4c,0x0,0x0,0x2,0x0,0x0,0xff,0xf6,0x0,0x0,0xff,0x47,0x0,0x82,0x0,0x0,0x0,0x1, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x9b,0x0,0x0,0x0,0x3,0x0,0x24,0x0,0xc9,0x1,0x2,0x0,0xc7, + 0x0,0x62,0x0,0xad,0x1,0x3,0x1,0x4,0x0,0x63,0x0,0xae,0x0,0x90,0x0,0x25,0x0,0x26,0x0,0xfd,0x0,0xff,0x0,0x64,0x1,0x5,0x1,0x6,0x0,0x27, + 0x0,0xe9,0x1,0x7,0x1,0x8,0x0,0x28,0x0,0x65,0x1,0x9,0x1,0xa,0x0,0xc8,0x0,0xca,0x1,0xb,0x0,0xcb,0x1,0xc,0x1,0xd,0x0,0x29,0x0,0x2a, + 0x0,0xf8,0x1,0xe,0x1,0xf,0x1,0x10,0x0,0x2b,0x1,0x11,0x1,0x12,0x0,0x2c,0x1,0x13,0x0,0xcc,0x1,0x14,0x0,0xcd,0x0,0xce,0x0,0xfa,0x0,0xcf, + 0x1,0x15,0x1,0x16,0x1,0x17,0x0,0x2d,0x1,0x18,0x0,0x2e,0x1,0x19,0x0,0x2f,0x1,0x1a,0x1,0x1b,0x1,0x1c,0x1,0x1d,0x0,0xe2,0x0,0x30,0x0,0x31, + 0x1,0x1e,0x1,0x1f,0x1,0x20,0x1,0x21,0x0,0x66,0x0,0x32,0x0,0xd0,0x1,0x22,0x0,0xd1,0x0,0x67,0x0,0xd3,0x1,0x23,0x1,0x24,0x0,0x91,0x0,0xaf, + 0x0,0xb0,0x0,0x33,0x0,0xed,0x0,0x34,0x0,0x35,0x1,0x25,0x1,0x26,0x1,0x27,0x0,0x36,0x1,0x28,0x0,0xe4,0x0,0xfb,0x1,0x29,0x1,0x2a,0x0,0x37, + 0x1,0x2b,0x1,0x2c,0x1,0x2d,0x1,0x2e,0x0,0x38,0x0,0xd4,0x1,0x2f,0x0,0xd5,0x0,0x68,0x0,0xd6,0x1,0x30,0x1,0x31,0x1,0x32,0x1,0x33,0x1,0x34, + 0x0,0x39,0x0,0x3a,0x1,0x35,0x1,0x36,0x1,0x37,0x1,0x38,0x0,0x3b,0x0,0x3c,0x0,0xeb,0x1,0x39,0x0,0xbb,0x1,0x3a,0x0,0x3d,0x1,0x3b,0x0,0xe6, + 0x1,0x3c,0x0,0x44,0x0,0x69,0x1,0x3d,0x0,0x6b,0x0,0x6c,0x0,0x6a,0x1,0x3e,0x1,0x3f,0x0,0x6e,0x0,0x6d,0x0,0xa0,0x0,0x45,0x0,0x46,0x0,0xfe, + 0x1,0x0,0x0,0x6f,0x1,0x40,0x1,0x41,0x0,0x47,0x0,0xea,0x1,0x42,0x1,0x1,0x0,0x48,0x0,0x70,0x1,0x43,0x1,0x44,0x0,0x72,0x0,0x73,0x1,0x45, + 0x0,0x71,0x1,0x46,0x1,0x47,0x0,0x49,0x0,0x4a,0x0,0xf9,0x1,0x48,0x1,0x49,0x1,0x4a,0x0,0x4b,0x1,0x4b,0x1,0x4c,0x0,0x4c,0x0,0xd7,0x0,0x74, + 0x1,0x4d,0x0,0x76,0x0,0x77,0x1,0x4e,0x0,0x75,0x1,0x4f,0x1,0x50,0x1,0x51,0x1,0x52,0x0,0x4d,0x1,0x53,0x1,0x54,0x0,0x4e,0x1,0x55,0x0,0x4f, + 0x1,0x56,0x1,0x57,0x1,0x58,0x1,0x59,0x0,0xe3,0x0,0x50,0x0,0x51,0x1,0x5a,0x1,0x5b,0x1,0x5c,0x1,0x5d,0x0,0x78,0x0,0x52,0x0,0x79,0x1,0x5e, + 0x0,0x7b,0x0,0x7c,0x0,0x7a,0x1,0x5f,0x1,0x60,0x0,0xa1,0x0,0x7d,0x0,0xb1,0x0,0x53,0x0,0xee,0x0,0x54,0x0,0x55,0x1,0x61,0x1,0x62,0x1,0x63, + 0x0,0x56,0x1,0x64,0x0,0xe5,0x0,0xfc,0x1,0x65,0x1,0x66,0x0,0x89,0x0,0x57,0x1,0x67,0x1,0x68,0x1,0x69,0x1,0x6a,0x0,0x58,0x0,0x7e,0x1,0x6b, + 0x0,0x80,0x0,0x81,0x0,0x7f,0x1,0x6c,0x1,0x6d,0x1,0x6e,0x1,0x6f,0x1,0x70,0x0,0x59,0x0,0x5a,0x1,0x71,0x1,0x72,0x1,0x73,0x1,0x74,0x0,0x5b, + 0x0,0x5c,0x0,0xec,0x1,0x75,0x0,0xba,0x1,0x76,0x0,0x5d,0x1,0x77,0x0,0xe7,0x1,0x78,0x0,0xc0,0x0,0xc1,0x0,0x9d,0x0,0x9e,0x1,0x79,0x1,0x7a, + 0x1,0x7b,0x0,0x9b,0x0,0x13,0x0,0x14,0x0,0x15,0x0,0x16,0x0,0x17,0x0,0x18,0x0,0x19,0x0,0x1a,0x0,0x1b,0x0,0x1c,0x0,0xbc,0x0,0xf4,0x0,0xf5, + 0x0,0xf6,0x1,0x7c,0x1,0x7d,0x1,0x7e,0x1,0x7f,0x1,0x80,0x1,0x81,0x1,0x82,0x1,0x83,0x1,0x84,0x1,0x85,0x1,0x86,0x1,0x87,0x1,0x88,0x0,0xd, + 0x0,0x3f,0x0,0xc3,0x0,0x87,0x0,0x1d,0x0,0xf,0x0,0xab,0x0,0x4,0x0,0xa3,0x0,0x6,0x0,0x11,0x0,0x22,0x0,0xa2,0x0,0x5,0x0,0xa,0x0,0x1e, + 0x0,0x12,0x0,0x42,0x0,0x5e,0x0,0x60,0x0,0x3e,0x0,0x40,0x0,0xb,0x0,0xc,0x1,0x89,0x1,0x8a,0x1,0x8b,0x1,0x8c,0x1,0x8d,0x0,0xb3,0x0,0xb2, + 0x0,0x10,0x1,0x8e,0x1,0x8f,0x0,0xa9,0x0,0xaa,0x0,0xbe,0x0,0xbf,0x0,0xc5,0x0,0xb4,0x0,0xb5,0x0,0xb6,0x0,0xb7,0x0,0xc4,0x1,0x90,0x0,0x84, + 0x0,0xbd,0x0,0x7,0x1,0x91,0x0,0xa6,0x0,0xf7,0x0,0x85,0x1,0x92,0x0,0x96,0x0,0xa7,0x0,0x61,0x0,0xb8,0x0,0x20,0x0,0x21,0x0,0x95,0x0,0x92, + 0x0,0x9c,0x0,0x1f,0x0,0x94,0x0,0xa4,0x0,0xef,0x0,0xf0,0x0,0x8f,0x0,0x98,0x0,0x8,0x0,0xc6,0x0,0xe,0x0,0x93,0x0,0x9a,0x0,0xa5,0x0,0x99, + 0x0,0xb9,0x0,0x5f,0x0,0xe8,0x0,0x23,0x0,0x9,0x0,0x88,0x0,0x8b,0x0,0x8a,0x0,0x86,0x0,0x8c,0x0,0x83,0x0,0x41,0x0,0x82,0x0,0xc2,0x1,0x93, + 0x1,0x94,0x1,0x95,0x1,0x96,0x0,0x8d,0x1,0x97,0x0,0xdb,0x0,0xe1,0x1,0x98,0x1,0x99,0x1,0x9a,0x1,0x9b,0x1,0x9c,0x1,0x9d,0x1,0x9e,0x1,0x9f, + 0x1,0xa0,0x1,0xa1,0x1,0xa2,0x1,0xa3,0x1,0xa4,0x0,0xde,0x0,0xd8,0x0,0x8e,0x0,0xdc,0x0,0x43,0x0,0xdf,0x0,0xda,0x0,0xe0,0x0,0xdd,0x0,0xd9, + 0x6,0x41,0x62,0x72,0x65,0x76,0x65,0x7,0x41,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x41,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x43,0x63,0x69,0x72,0x63,0x75, + 0x6d,0x66,0x6c,0x65,0x78,0xa,0x43,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x44,0x63,0x61,0x72,0x6f,0x6e,0x6,0x44,0x63,0x72,0x6f,0x61,0x74, + 0x6,0x45,0x62,0x72,0x65,0x76,0x65,0x6,0x45,0x63,0x61,0x72,0x6f,0x6e,0xa,0x45,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x7,0x45,0x6d,0x61,0x63, + 0x72,0x6f,0x6e,0x7,0x45,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x47,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x47,0x63,0x6f,0x6d,0x6d,0x61, + 0x61,0x63,0x63,0x65,0x6e,0x74,0xa,0x47,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x48,0x62,0x61,0x72,0xb,0x48,0x63,0x69,0x72,0x63,0x75,0x6d, + 0x66,0x6c,0x65,0x78,0x2,0x49,0x4a,0x6,0x49,0x62,0x72,0x65,0x76,0x65,0x7,0x49,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x49,0x6f,0x67,0x6f,0x6e,0x65,0x6b, + 0x6,0x49,0x74,0x69,0x6c,0x64,0x65,0xb,0x4a,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x4b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65, + 0x6e,0x74,0x6,0x4c,0x61,0x63,0x75,0x74,0x65,0x6,0x4c,0x63,0x61,0x72,0x6f,0x6e,0xc,0x4c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x4, + 0x4c,0x64,0x6f,0x74,0x6,0x4e,0x61,0x63,0x75,0x74,0x65,0x6,0x4e,0x63,0x61,0x72,0x6f,0x6e,0xc,0x4e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e, + 0x74,0x3,0x45,0x6e,0x67,0x6,0x4f,0x62,0x72,0x65,0x76,0x65,0xd,0x4f,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x4f,0x6d,0x61, + 0x63,0x72,0x6f,0x6e,0x6,0x52,0x61,0x63,0x75,0x74,0x65,0x6,0x52,0x63,0x61,0x72,0x6f,0x6e,0xc,0x52,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e, + 0x74,0x6,0x53,0x61,0x63,0x75,0x74,0x65,0xb,0x53,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x53,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63, + 0x65,0x6e,0x74,0x4,0x54,0x62,0x61,0x72,0x6,0x54,0x63,0x61,0x72,0x6f,0x6e,0x7,0x75,0x6e,0x69,0x30,0x31,0x36,0x32,0x7,0x75,0x6e,0x69,0x30,0x32,0x31, + 0x41,0x6,0x55,0x62,0x72,0x65,0x76,0x65,0xd,0x55,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x55,0x6d,0x61,0x63,0x72,0x6f,0x6e, + 0x7,0x55,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x5,0x55,0x72,0x69,0x6e,0x67,0x6,0x55,0x74,0x69,0x6c,0x64,0x65,0x6,0x57,0x61,0x63,0x75,0x74,0x65,0xb,0x57, + 0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x9,0x57,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x6,0x57,0x67,0x72,0x61,0x76,0x65,0xb,0x59,0x63, + 0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x6,0x59,0x67,0x72,0x61,0x76,0x65,0x6,0x5a,0x61,0x63,0x75,0x74,0x65,0xa,0x5a,0x64,0x6f,0x74,0x61,0x63, + 0x63,0x65,0x6e,0x74,0x6,0x61,0x62,0x72,0x65,0x76,0x65,0x7,0x61,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x61,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x63,0x63, + 0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xa,0x63,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x64,0x63,0x61,0x72,0x6f,0x6e,0x6,0x65,0x62, + 0x72,0x65,0x76,0x65,0x6,0x65,0x63,0x61,0x72,0x6f,0x6e,0xa,0x65,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x7,0x65,0x6d,0x61,0x63,0x72,0x6f,0x6e, + 0x7,0x65,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0xb,0x67,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0xc,0x67,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63, + 0x65,0x6e,0x74,0xa,0x67,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x68,0x62,0x61,0x72,0xb,0x68,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65, + 0x78,0x6,0x69,0x62,0x72,0x65,0x76,0x65,0x9,0x69,0x2e,0x6c,0x6f,0x63,0x6c,0x54,0x52,0x4b,0x2,0x69,0x6a,0x7,0x69,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7, + 0x69,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x6,0x69,0x74,0x69,0x6c,0x64,0x65,0x7,0x75,0x6e,0x69,0x30,0x32,0x33,0x37,0xb,0x6a,0x63,0x69,0x72,0x63,0x75,0x6d, + 0x66,0x6c,0x65,0x78,0xc,0x6b,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x6c,0x61,0x63,0x75,0x74,0x65,0x6,0x6c,0x63,0x61,0x72,0x6f, + 0x6e,0xc,0x6c,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x6c,0x64,0x6f,0x74,0x6,0x6e,0x61,0x63,0x75,0x74,0x65,0x6,0x6e,0x63,0x61, + 0x72,0x6f,0x6e,0xc,0x6e,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x3,0x65,0x6e,0x67,0x6,0x6f,0x62,0x72,0x65,0x76,0x65,0xd,0x6f,0x68, + 0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x6f,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x6,0x72,0x61,0x63,0x75,0x74,0x65,0x6,0x72,0x63,0x61, + 0x72,0x6f,0x6e,0xc,0x72,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x6,0x73,0x61,0x63,0x75,0x74,0x65,0xb,0x73,0x63,0x69,0x72,0x63,0x75, + 0x6d,0x66,0x6c,0x65,0x78,0xc,0x73,0x63,0x6f,0x6d,0x6d,0x61,0x61,0x63,0x63,0x65,0x6e,0x74,0x4,0x74,0x62,0x61,0x72,0x6,0x74,0x63,0x61,0x72,0x6f,0x6e, + 0x7,0x75,0x6e,0x69,0x30,0x31,0x36,0x33,0x7,0x75,0x6e,0x69,0x30,0x32,0x31,0x42,0x6,0x75,0x62,0x72,0x65,0x76,0x65,0xd,0x75,0x68,0x75,0x6e,0x67,0x61, + 0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x7,0x75,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x7,0x75,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x5,0x75,0x72,0x69,0x6e,0x67,0x6, + 0x75,0x74,0x69,0x6c,0x64,0x65,0x6,0x77,0x61,0x63,0x75,0x74,0x65,0xb,0x77,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x9,0x77,0x64,0x69,0x65, + 0x72,0x65,0x73,0x69,0x73,0x6,0x77,0x67,0x72,0x61,0x76,0x65,0xb,0x79,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x6,0x79,0x67,0x72,0x61,0x76, + 0x65,0x6,0x7a,0x61,0x63,0x75,0x74,0x65,0xa,0x7a,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x7,0x75,0x6e,0x69,0x30,0x33,0x39,0x34,0x7,0x75,0x6e, + 0x69,0x30,0x33,0x41,0x39,0x7,0x75,0x6e,0x69,0x30,0x33,0x42,0x43,0x7,0x75,0x6e,0x69,0x30,0x30,0x42,0x39,0x7,0x75,0x6e,0x69,0x30,0x30,0x42,0x32,0x7, + 0x75,0x6e,0x69,0x30,0x30,0x42,0x33,0x7,0x75,0x6e,0x69,0x32,0x30,0x37,0x34,0x9,0x63,0x6f,0x6c,0x6f,0x6e,0x2e,0x61,0x6c,0x74,0x9,0x63,0x6f,0x6d,0x6d, + 0x61,0x2e,0x61,0x6c,0x74,0xa,0x70,0x65,0x72,0x69,0x6f,0x64,0x2e,0x61,0x6c,0x74,0xd,0x73,0x65,0x6d,0x69,0x63,0x6f,0x6c,0x6f,0x6e,0x2e,0x61,0x6c,0x74, + 0xd,0x65,0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x31,0xd,0x65,0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x32,0xd,0x65, + 0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x33,0xd,0x65,0x6c,0x6c,0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x34,0xd,0x65,0x6c,0x6c, + 0x69,0x70,0x73,0x69,0x73,0x2e,0x61,0x6c,0x74,0x35,0xa,0x68,0x79,0x70,0x68,0x65,0x6e,0x2e,0x61,0x6c,0x74,0xb,0x65,0x6d,0x64,0x61,0x73,0x68,0x2e,0x61, + 0x6c,0x74,0x31,0xb,0x65,0x6d,0x64,0x61,0x73,0x68,0x2e,0x61,0x6c,0x74,0x32,0xb,0x65,0x6d,0x64,0x61,0x73,0x68,0x2e,0x61,0x6c,0x74,0x33,0xb,0x65,0x6d, + 0x64,0x61,0x73,0x68,0x2e,0x61,0x6c,0x74,0x34,0x7,0x75,0x6e,0x69,0x32,0x30,0x31,0x31,0x7,0x75,0x6e,0x69,0x30,0x30,0x41,0x44,0x7,0x75,0x6e,0x69,0x30, + 0x30,0x41,0x30,0x4,0x45,0x75,0x72,0x6f,0x7,0x75,0x6e,0x69,0x32,0x30,0x41,0x39,0x6,0x6d,0x69,0x6e,0x75,0x74,0x65,0x6,0x73,0x65,0x63,0x6f,0x6e,0x64, + 0x7,0x75,0x6e,0x69,0x30,0x33,0x32,0x36,0xc,0x75,0x6e,0x69,0x30,0x33,0x32,0x36,0x2e,0x63,0x61,0x73,0x65,0x9,0x63,0x61,0x72,0x6f,0x6e,0x2e,0x61,0x6c, + 0x74,0xa,0x61,0x63,0x75,0x74,0x65,0x2e,0x63,0x61,0x73,0x65,0xa,0x62,0x72,0x65,0x76,0x65,0x2e,0x63,0x61,0x73,0x65,0xa,0x63,0x61,0x72,0x6f,0x6e,0x2e, + 0x63,0x61,0x73,0x65,0xc,0x63,0x65,0x64,0x69,0x6c,0x6c,0x61,0x2e,0x63,0x61,0x73,0x65,0xf,0x63,0x69,0x72,0x63,0x75,0x6d,0x66,0x6c,0x65,0x78,0x2e,0x63, + 0x61,0x73,0x65,0xd,0x64,0x69,0x65,0x72,0x65,0x73,0x69,0x73,0x2e,0x63,0x61,0x73,0x65,0xe,0x64,0x6f,0x74,0x61,0x63,0x63,0x65,0x6e,0x74,0x2e,0x63,0x61, + 0x73,0x65,0xa,0x67,0x72,0x61,0x76,0x65,0x2e,0x63,0x61,0x73,0x65,0x11,0x68,0x75,0x6e,0x67,0x61,0x72,0x75,0x6d,0x6c,0x61,0x75,0x74,0x2e,0x63,0x61,0x73, + 0x65,0xb,0x6d,0x61,0x63,0x72,0x6f,0x6e,0x2e,0x63,0x61,0x73,0x65,0xb,0x6f,0x67,0x6f,0x6e,0x65,0x6b,0x2e,0x63,0x61,0x73,0x65,0x9,0x72,0x69,0x6e,0x67, + 0x2e,0x63,0x61,0x73,0x65,0xa,0x74,0x69,0x6c,0x64,0x65,0x2e,0x63,0x61,0x73,0x65,0x0,0x1,0x0,0x1,0xff,0xff,0x0,0xf,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x99,0x0,0x99,0x0,0x94,0x0,0x94,0x4,0xa3,0x0,0x0,0x5,0x2a,0x3,0x9c, + 0x0,0x0,0xfe,0x6d,0x7,0x5,0xfc,0xb9,0x4,0xb9,0xff,0xea,0x5,0x2a,0x3,0xb2,0xff,0xea,0xfe,0x6d,0x7,0x5,0xfc,0xb9,0xb0,0x0,0x2c,0x20,0xb0,0x0, + 0x55,0x58,0x45,0x59,0x20,0x20,0x4b,0xb8,0x0,0xe,0x51,0x4b,0xb0,0x6,0x53,0x5a,0x58,0xb0,0x34,0x1b,0xb0,0x28,0x59,0x60,0x66,0x20,0x8a,0x55,0x58,0xb0, + 0x2,0x25,0x61,0xb9,0x8,0x0,0x8,0x0,0x63,0x63,0x23,0x62,0x1b,0x21,0x21,0xb0,0x0,0x59,0xb0,0x0,0x43,0x23,0x44,0xb2,0x0,0x1,0x0,0x43,0x60,0x42, + 0x2d,0xb0,0x1,0x2c,0xb0,0x20,0x60,0x66,0x2d,0xb0,0x2,0x2c,0x20,0x64,0x20,0xb0,0xc0,0x50,0xb0,0x4,0x26,0x5a,0xb2,0x28,0x1,0xa,0x43,0x45,0x63,0x45, + 0xb0,0x6,0x45,0x58,0x21,0xb0,0x3,0x25,0x59,0x52,0x5b,0x58,0x21,0x23,0x21,0x1b,0x8a,0x58,0x20,0xb0,0x50,0x50,0x58,0x21,0xb0,0x40,0x59,0x1b,0x20,0xb0, + 0x38,0x50,0x58,0x21,0xb0,0x38,0x59,0x59,0x20,0xb1,0x1,0xa,0x43,0x45,0x63,0x45,0x61,0x64,0xb0,0x28,0x50,0x58,0x21,0xb1,0x1,0xa,0x43,0x45,0x63,0x45, + 0x20,0xb0,0x30,0x50,0x58,0x21,0xb0,0x30,0x59,0x1b,0x20,0xb0,0xc0,0x50,0x58,0x20,0x66,0x20,0x8a,0x8a,0x61,0x20,0xb0,0xa,0x50,0x58,0x60,0x1b,0x20,0xb0, + 0x20,0x50,0x58,0x21,0xb0,0xa,0x60,0x1b,0x20,0xb0,0x36,0x50,0x58,0x21,0xb0,0x36,0x60,0x1b,0x60,0x59,0x59,0x59,0x1b,0xb0,0x1,0x2b,0x59,0x59,0x23,0xb0, + 0x0,0x50,0x58,0x65,0x59,0x59,0x2d,0xb0,0x3,0x2c,0x20,0x45,0x20,0xb0,0x4,0x25,0x61,0x64,0x20,0xb0,0x5,0x43,0x50,0x58,0xb0,0x5,0x23,0x42,0xb0,0x6, + 0x23,0x42,0x1b,0x21,0x21,0x59,0xb0,0x1,0x60,0x2d,0xb0,0x4,0x2c,0x23,0x21,0x23,0x21,0x20,0x64,0xb1,0x5,0x62,0x42,0x20,0xb0,0x6,0x23,0x42,0xb0,0x6, + 0x45,0x58,0x1b,0xb1,0x1,0xa,0x43,0x45,0x63,0xb1,0x1,0xa,0x43,0xb0,0x1,0x60,0x45,0x63,0xb0,0x3,0x2a,0x21,0x20,0xb0,0x6,0x43,0x20,0x8a,0x20,0x8a, + 0xb0,0x1,0x2b,0xb1,0x30,0x5,0x25,0xb0,0x4,0x26,0x51,0x58,0x60,0x50,0x1b,0x61,0x52,0x59,0x58,0x23,0x59,0x21,0x59,0x20,0xb0,0x40,0x53,0x58,0xb0,0x1, + 0x2b,0x1b,0x21,0xb0,0x40,0x59,0x23,0xb0,0x0,0x50,0x58,0x65,0x59,0x2d,0xb0,0x5,0x2c,0xb0,0x7,0x43,0x2b,0xb2,0x0,0x2,0x0,0x43,0x60,0x42,0x2d,0xb0, + 0x6,0x2c,0xb0,0x7,0x23,0x42,0x23,0x20,0xb0,0x0,0x23,0x42,0x61,0xb0,0x2,0x62,0x66,0xb0,0x1,0x63,0xb0,0x1,0x60,0xb0,0x5,0x2a,0x2d,0xb0,0x7,0x2c, + 0x20,0x20,0x45,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x44,0xb0,0x1,0x60, + 0x2d,0xb0,0x8,0x2c,0xb2,0x7,0xb,0x0,0x43,0x45,0x42,0x2a,0x21,0xb2,0x0,0x1,0x0,0x43,0x60,0x42,0x2d,0xb0,0x9,0x2c,0xb0,0x0,0x43,0x23,0x44,0xb2, + 0x0,0x1,0x0,0x43,0x60,0x42,0x2d,0xb0,0xa,0x2c,0x20,0x20,0x45,0x20,0xb0,0x1,0x2b,0x23,0xb0,0x0,0x43,0xb0,0x4,0x25,0x60,0x20,0x45,0x8a,0x23,0x61, + 0x20,0x64,0x20,0xb0,0x20,0x50,0x58,0x21,0xb0,0x0,0x1b,0xb0,0x30,0x50,0x58,0xb0,0x20,0x1b,0xb0,0x40,0x59,0x59,0x23,0xb0,0x0,0x50,0x58,0x65,0x59,0xb0, + 0x3,0x25,0x23,0x61,0x44,0x44,0xb0,0x1,0x60,0x2d,0xb0,0xb,0x2c,0x20,0x20,0x45,0x20,0xb0,0x1,0x2b,0x23,0xb0,0x0,0x43,0xb0,0x4,0x25,0x60,0x20,0x45, + 0x8a,0x23,0x61,0x20,0x64,0xb0,0x24,0x50,0x58,0xb0,0x0,0x1b,0xb0,0x40,0x59,0x23,0xb0,0x0,0x50,0x58,0x65,0x59,0xb0,0x3,0x25,0x23,0x61,0x44,0x44,0xb0, + 0x1,0x60,0x2d,0xb0,0xc,0x2c,0x20,0xb0,0x0,0x23,0x42,0xb2,0xb,0xa,0x3,0x45,0x58,0x21,0x1b,0x23,0x21,0x59,0x2a,0x21,0x2d,0xb0,0xd,0x2c,0xb1,0x2, + 0x2,0x45,0xb0,0x64,0x61,0x44,0x2d,0xb0,0xe,0x2c,0xb0,0x1,0x60,0x20,0x20,0xb0,0xc,0x43,0x4a,0xb0,0x0,0x50,0x58,0x20,0xb0,0xc,0x23,0x42,0x59,0xb0, + 0xd,0x43,0x4a,0xb0,0x0,0x52,0x58,0x20,0xb0,0xd,0x23,0x42,0x59,0x2d,0xb0,0xf,0x2c,0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0x20,0xb8,0x4,0x0,0x63, + 0x8a,0x23,0x61,0xb0,0xe,0x43,0x60,0x20,0x8a,0x60,0x20,0xb0,0xe,0x23,0x42,0x23,0x2d,0xb0,0x10,0x2c,0x4b,0x54,0x58,0xb1,0x4,0x64,0x44,0x59,0x24,0xb0, + 0xd,0x65,0x23,0x78,0x2d,0xb0,0x11,0x2c,0x4b,0x51,0x58,0x4b,0x53,0x58,0xb1,0x4,0x64,0x44,0x59,0x1b,0x21,0x59,0x24,0xb0,0x13,0x65,0x23,0x78,0x2d,0xb0, + 0x12,0x2c,0xb1,0x0,0xf,0x43,0x55,0x58,0xb1,0xf,0xf,0x43,0xb0,0x1,0x61,0x42,0xb0,0xf,0x2b,0x59,0xb0,0x0,0x43,0xb0,0x2,0x25,0x42,0xb1,0xc,0x2, + 0x25,0x42,0xb1,0xd,0x2,0x25,0x42,0xb0,0x1,0x16,0x23,0x20,0xb0,0x3,0x25,0x50,0x58,0xb1,0x1,0x0,0x43,0x60,0xb0,0x4,0x25,0x42,0x8a,0x8a,0x20,0x8a, + 0x23,0x61,0xb0,0xe,0x2a,0x21,0x23,0xb0,0x1,0x61,0x20,0x8a,0x23,0x61,0xb0,0xe,0x2a,0x21,0x1b,0xb1,0x1,0x0,0x43,0x60,0xb0,0x2,0x25,0x42,0xb0,0x2, + 0x25,0x61,0xb0,0xe,0x2a,0x21,0x59,0xb0,0xc,0x43,0x47,0xb0,0xd,0x43,0x47,0x60,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0, + 0x1,0x63,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0xb1,0x0,0x0,0x13,0x23, + 0x44,0xb0,0x1,0x43,0xb0,0x0,0x3e,0xb2,0x1,0x1,0x1,0x43,0x60,0x42,0x2d,0xb0,0x13,0x2c,0x0,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0xf,0x23,0x42,0x20, + 0x45,0xb0,0xb,0x23,0x42,0xb0,0xa,0x23,0xb0,0x1,0x60,0x42,0x20,0x60,0xb0,0x1,0x61,0xb5,0x10,0x10,0x1,0x0,0xe,0x0,0x42,0x42,0x8a,0x60,0xb1,0x12, + 0x6,0x2b,0xb0,0x75,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x14,0x2c,0xb1,0x0,0x13,0x2b,0x2d,0xb0,0x15,0x2c,0xb1,0x1,0x13,0x2b,0x2d,0xb0,0x16,0x2c,0xb1,0x2, + 0x13,0x2b,0x2d,0xb0,0x17,0x2c,0xb1,0x3,0x13,0x2b,0x2d,0xb0,0x18,0x2c,0xb1,0x4,0x13,0x2b,0x2d,0xb0,0x19,0x2c,0xb1,0x5,0x13,0x2b,0x2d,0xb0,0x1a,0x2c, + 0xb1,0x6,0x13,0x2b,0x2d,0xb0,0x1b,0x2c,0xb1,0x7,0x13,0x2b,0x2d,0xb0,0x1c,0x2c,0xb1,0x8,0x13,0x2b,0x2d,0xb0,0x1d,0x2c,0xb1,0x9,0x13,0x2b,0x2d,0xb0, + 0x29,0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0xb0,0x6,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x1,0x5d,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2a, + 0x2c,0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0xb0,0x16,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x1,0x71,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x2b,0x2c, + 0x23,0x20,0xb0,0x10,0x62,0x66,0xb0,0x1,0x63,0xb0,0x26,0x60,0x4b,0x54,0x58,0x23,0x20,0x2e,0xb0,0x1,0x72,0x1b,0x21,0x21,0x59,0x2d,0xb0,0x1e,0x2c,0x0, + 0xb0,0xd,0x2b,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0xf,0x23,0x42,0x20,0x45,0xb0,0xb,0x23,0x42,0xb0,0xa,0x23,0xb0,0x1,0x60,0x42,0x20,0x60,0xb0,0x1, + 0x61,0xb5,0x10,0x10,0x1,0x0,0xe,0x0,0x42,0x42,0x8a,0x60,0xb1,0x12,0x6,0x2b,0xb0,0x75,0x2b,0x1b,0x22,0x59,0x2d,0xb0,0x1f,0x2c,0xb1,0x0,0x1e,0x2b, + 0x2d,0xb0,0x20,0x2c,0xb1,0x1,0x1e,0x2b,0x2d,0xb0,0x21,0x2c,0xb1,0x2,0x1e,0x2b,0x2d,0xb0,0x22,0x2c,0xb1,0x3,0x1e,0x2b,0x2d,0xb0,0x23,0x2c,0xb1,0x4, + 0x1e,0x2b,0x2d,0xb0,0x24,0x2c,0xb1,0x5,0x1e,0x2b,0x2d,0xb0,0x25,0x2c,0xb1,0x6,0x1e,0x2b,0x2d,0xb0,0x26,0x2c,0xb1,0x7,0x1e,0x2b,0x2d,0xb0,0x27,0x2c, + 0xb1,0x8,0x1e,0x2b,0x2d,0xb0,0x28,0x2c,0xb1,0x9,0x1e,0x2b,0x2d,0xb0,0x2c,0x2c,0x20,0x3c,0xb0,0x1,0x60,0x2d,0xb0,0x2d,0x2c,0x20,0x60,0xb0,0x10,0x60, + 0x20,0x43,0x23,0xb0,0x1,0x60,0x43,0xb0,0x2,0x25,0x61,0xb0,0x1,0x60,0xb0,0x2c,0x2a,0x21,0x2d,0xb0,0x2e,0x2c,0xb0,0x2d,0x2b,0xb0,0x2d,0x2a,0x2d,0xb0, + 0x2f,0x2c,0x20,0x20,0x47,0x20,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x23, + 0x61,0x38,0x23,0x20,0x8a,0x55,0x58,0x20,0x47,0x20,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0, + 0x1,0x63,0x60,0x23,0x61,0x38,0x1b,0x21,0x59,0x2d,0xb0,0x30,0x2c,0x0,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0x1,0x16,0xb0,0x2f,0x2a,0xb1,0x5,0x1,0x15, + 0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x31,0x2c,0x0,0xb0,0xd,0x2b,0xb1,0x0,0x2,0x45,0x54,0x58,0xb0,0x1,0x16,0xb0,0x2f,0x2a,0xb1,0x5,0x1, + 0x15,0x45,0x58,0x30,0x59,0x1b,0x22,0x59,0x2d,0xb0,0x32,0x2c,0x20,0x35,0xb0,0x1,0x60,0x2d,0xb0,0x33,0x2c,0x0,0xb0,0x1,0x45,0x63,0xb8,0x4,0x0,0x62, + 0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0xb0,0x1,0x2b,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0, + 0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0xb0,0x1,0x2b,0xb0,0x0,0x16,0xb4,0x0,0x0,0x0,0x0,0x0,0x44,0x3e,0x23,0x38,0xb1,0x32,0x1,0x15,0x2a,0x2d,0xb0, + 0x34,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0xb0, + 0x0,0x43,0x61,0x38,0x2d,0xb0,0x35,0x2c,0x2e,0x17,0x3c,0x2d,0xb0,0x36,0x2c,0x20,0x3c,0x20,0x47,0x20,0xb0,0xb,0x43,0x63,0xb8,0x4,0x0,0x62,0x20,0xb0, + 0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0xb0,0x0,0x43,0x61,0xb0,0x1,0x43,0x63,0x38,0x2d,0xb0,0x37,0x2c,0xb1,0x2,0x0,0x16,0x25, + 0x20,0x2e,0x20,0x47,0xb0,0x0,0x23,0x42,0xb0,0x2,0x25,0x49,0x8a,0x8a,0x47,0x23,0x47,0x23,0x61,0x20,0x58,0x62,0x1b,0x21,0x59,0xb0,0x1,0x23,0x42,0xb2, + 0x36,0x1,0x1,0x15,0x14,0x2a,0x2d,0xb0,0x38,0x2c,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x25,0x47,0x23,0x47,0x23,0x61,0xb0,0x9,0x43,0x2b,0x65,0x8a, + 0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x39,0x2c,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x4, + 0x23,0x42,0xb0,0x9,0x43,0x2b,0x20,0xb0,0x60,0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x2,0x20,0x3,0x20,0x1b,0xb3,0x2,0x26,0x3,0x1a,0x59,0x42,0x42, + 0x23,0x20,0xb0,0x8,0x43,0x20,0x8a,0x23,0x47,0x23,0x47,0x23,0x61,0x23,0x46,0x60,0xb0,0x4,0x43,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60, + 0x59,0x66,0xb0,0x1,0x63,0x60,0x20,0xb0,0x1,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x2,0x43,0x60,0x64,0x23,0xb0,0x3,0x43,0x61,0x64,0x50,0x58,0xb0,0x2, + 0x43,0x61,0x1b,0xb0,0x3,0x43,0x60,0x59,0xb0,0x3,0x25,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x61,0x23,0x20, + 0x20,0xb0,0x4,0x26,0x23,0x46,0x61,0x38,0x1b,0x23,0xb0,0x8,0x43,0x46,0xb0,0x2,0x25,0xb0,0x8,0x43,0x47,0x23,0x47,0x23,0x61,0x60,0x20,0xb0,0x4,0x43, + 0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x23,0x20,0xb0,0x1,0x2b,0x23,0xb0,0x4,0x43,0x60,0xb0,0x1,0x2b, + 0xb0,0x5,0x25,0x61,0xb0,0x5,0x25,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0xb0,0x4,0x26,0x61,0x20,0xb0,0x4, + 0x25,0x60,0x64,0x23,0xb0,0x3,0x25,0x60,0x64,0x50,0x58,0x21,0x1b,0x23,0x21,0x59,0x23,0x20,0x20,0xb0,0x4,0x26,0x23,0x46,0x61,0x38,0x59,0x2d,0xb0,0x3a, + 0x2c,0xb0,0x0,0x16,0x20,0x20,0x20,0xb0,0x5,0x26,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x23,0x3c,0x38,0x2d,0xb0,0x3b,0x2c,0xb0,0x0,0x16,0x20,0xb0,0x8, + 0x23,0x42,0x20,0x20,0x20,0x46,0x23,0x47,0xb0,0x1,0x2b,0x23,0x61,0x38,0x2d,0xb0,0x3c,0x2c,0xb0,0x0,0x16,0xb0,0x3,0x25,0xb0,0x2,0x25,0x47,0x23,0x47, + 0x23,0x61,0xb0,0x0,0x54,0x58,0x2e,0x20,0x3c,0x23,0x21,0x1b,0xb0,0x2,0x25,0xb0,0x2,0x25,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x5,0x25,0xb0,0x4,0x25, + 0x47,0x23,0x47,0x23,0x61,0xb0,0x6,0x25,0xb0,0x5,0x25,0x49,0xb0,0x2,0x25,0x61,0xb9,0x8,0x0,0x8,0x0,0x63,0x63,0x23,0x20,0x58,0x62,0x1b,0x21,0x59, + 0x63,0xb8,0x4,0x0,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x23,0x2e,0x23,0x20,0x20,0x3c,0x8a,0x38,0x23,0x21,0x59, + 0x2d,0xb0,0x3d,0x2c,0xb0,0x0,0x16,0x20,0xb0,0x8,0x43,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0x60,0xb0,0x20,0x60,0x66,0xb0,0x2,0x62,0x20,0xb0,0x0, + 0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x23,0x20,0x20,0x3c,0x8a,0x38,0x2d,0xb0,0x3e,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58, + 0x20,0x3c,0x59,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x3f,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x50,0x58,0x20,0x3c,0x59,0x2e,0xb1,0x2e,0x1, + 0x14,0x2b,0x2d,0xb0,0x40,0x2c,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x50,0x58,0x20, + 0x3c,0x59,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x41,0x2c,0xb0,0x38,0x2b,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52,0x58,0x20,0x3c,0x59,0x2e,0xb1, + 0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x42,0x2c,0xb0,0x39,0x2b,0x8a,0x20,0x20,0x3c,0xb0,0x4,0x23,0x42,0x8a,0x38,0x23,0x20,0x2e,0x46,0xb0,0x2,0x25,0x46,0x52, + 0x58,0x20,0x3c,0x59,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0xb0,0x4,0x43,0x2e,0xb0,0x2e,0x2b,0x2d,0xb0,0x43,0x2c,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x26, + 0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0xb0,0x9,0x43,0x2b,0x23,0x20,0x3c,0x20,0x2e,0x23,0x38,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x44,0x2c,0xb1,0x8,0x4, + 0x25,0x42,0xb0,0x0,0x16,0xb0,0x4,0x25,0xb0,0x4,0x25,0x20,0x2e,0x47,0x23,0x47,0x23,0x61,0x20,0xb0,0x4,0x23,0x42,0xb0,0x9,0x43,0x2b,0x20,0xb0,0x60, + 0x50,0x58,0x20,0xb0,0x40,0x51,0x58,0xb3,0x2,0x20,0x3,0x20,0x1b,0xb3,0x2,0x26,0x3,0x1a,0x59,0x42,0x42,0x23,0x20,0x47,0xb0,0x4,0x43,0xb0,0x2,0x62, + 0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60,0x59,0x66,0xb0,0x1,0x63,0x60,0x20,0xb0,0x1,0x2b,0x20,0x8a,0x8a,0x61,0x20,0xb0,0x2,0x43,0x60,0x64,0x23,0xb0, + 0x3,0x43,0x61,0x64,0x50,0x58,0xb0,0x2,0x43,0x61,0x1b,0xb0,0x3,0x43,0x60,0x59,0xb0,0x3,0x25,0xb0,0x2,0x62,0x20,0xb0,0x0,0x50,0x58,0xb0,0x40,0x60, + 0x59,0x66,0xb0,0x1,0x63,0x61,0xb0,0x2,0x25,0x46,0x61,0x38,0x23,0x20,0x3c,0x23,0x38,0x1b,0x21,0x20,0x20,0x46,0x23,0x47,0xb0,0x1,0x2b,0x23,0x61,0x38, + 0x21,0x59,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x45,0x2c,0xb0,0x38,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x46,0x2c,0xb0,0x39,0x2b,0x21,0x23,0x20, + 0x20,0x3c,0xb0,0x4,0x23,0x42,0x23,0x38,0xb1,0x2e,0x1,0x14,0x2b,0xb0,0x4,0x43,0x2e,0xb0,0x2e,0x2b,0x2d,0xb0,0x47,0x2c,0xb0,0x0,0x15,0x20,0x47,0xb0, + 0x0,0x23,0x42,0xb2,0x0,0x1,0x1,0x15,0x14,0x13,0x2e,0xb0,0x34,0x2a,0x2d,0xb0,0x48,0x2c,0xb0,0x0,0x15,0x20,0x47,0xb0,0x0,0x23,0x42,0xb2,0x0,0x1, + 0x1,0x15,0x14,0x13,0x2e,0xb0,0x34,0x2a,0x2d,0xb0,0x49,0x2c,0xb1,0x0,0x1,0x14,0x13,0xb0,0x35,0x2a,0x2d,0xb0,0x4a,0x2c,0xb0,0x37,0x2a,0x2d,0xb0,0x4b, + 0x2c,0xb0,0x0,0x16,0x45,0x23,0x20,0x2e,0x20,0x46,0x8a,0x23,0x61,0x38,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x4c,0x2c,0xb0,0x8,0x23,0x42,0xb0,0x4b,0x2b, + 0x2d,0xb0,0x4d,0x2c,0xb2,0x0,0x0,0x44,0x2b,0x2d,0xb0,0x4e,0x2c,0xb2,0x0,0x1,0x44,0x2b,0x2d,0xb0,0x4f,0x2c,0xb2,0x1,0x0,0x44,0x2b,0x2d,0xb0,0x50, + 0x2c,0xb2,0x1,0x1,0x44,0x2b,0x2d,0xb0,0x51,0x2c,0xb2,0x0,0x0,0x45,0x2b,0x2d,0xb0,0x52,0x2c,0xb2,0x0,0x1,0x45,0x2b,0x2d,0xb0,0x53,0x2c,0xb2,0x1, + 0x0,0x45,0x2b,0x2d,0xb0,0x54,0x2c,0xb2,0x1,0x1,0x45,0x2b,0x2d,0xb0,0x55,0x2c,0xb2,0x0,0x0,0x41,0x2b,0x2d,0xb0,0x56,0x2c,0xb2,0x0,0x1,0x41,0x2b, + 0x2d,0xb0,0x57,0x2c,0xb2,0x1,0x0,0x41,0x2b,0x2d,0xb0,0x58,0x2c,0xb2,0x1,0x1,0x41,0x2b,0x2d,0xb0,0x59,0x2c,0xb2,0x0,0x0,0x43,0x2b,0x2d,0xb0,0x5a, + 0x2c,0xb2,0x0,0x1,0x43,0x2b,0x2d,0xb0,0x5b,0x2c,0xb2,0x1,0x0,0x43,0x2b,0x2d,0xb0,0x5c,0x2c,0xb2,0x1,0x1,0x43,0x2b,0x2d,0xb0,0x5d,0x2c,0xb2,0x0, + 0x0,0x46,0x2b,0x2d,0xb0,0x5e,0x2c,0xb2,0x0,0x1,0x46,0x2b,0x2d,0xb0,0x5f,0x2c,0xb2,0x1,0x0,0x46,0x2b,0x2d,0xb0,0x60,0x2c,0xb2,0x1,0x1,0x46,0x2b, + 0x2d,0xb0,0x61,0x2c,0xb2,0x0,0x0,0x42,0x2b,0x2d,0xb0,0x62,0x2c,0xb2,0x0,0x1,0x42,0x2b,0x2d,0xb0,0x63,0x2c,0xb2,0x1,0x0,0x42,0x2b,0x2d,0xb0,0x64, + 0x2c,0xb2,0x1,0x1,0x42,0x2b,0x2d,0xb0,0x65,0x2c,0xb0,0x3a,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x66,0x2c,0xb0,0x3a,0x2b,0xb0,0x3e,0x2b,0x2d, + 0xb0,0x67,0x2c,0xb0,0x3a,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x68,0x2c,0xb0,0x0,0x16,0xb0,0x3a,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x69,0x2c,0xb0,0x3b,0x2b,0x2e, + 0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x6a,0x2c,0xb0,0x3b,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0,0x6b,0x2c,0xb0,0x3b,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x6c,0x2c,0xb0, + 0x3b,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x6d,0x2c,0xb0,0x3c,0x2b,0x2e,0xb1,0x2e,0x1,0x14,0x2b,0x2d,0xb0,0x6e,0x2c,0xb0,0x3c,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0, + 0x6f,0x2c,0xb0,0x3c,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x70,0x2c,0xb0,0x3c,0x2b,0xb0,0x40,0x2b,0x2d,0xb0,0x71,0x2c,0xb0,0x3d,0x2b,0x2e,0xb1,0x2e,0x1,0x14, + 0x2b,0x2d,0xb0,0x72,0x2c,0xb0,0x3d,0x2b,0xb0,0x3e,0x2b,0x2d,0xb0,0x73,0x2c,0xb0,0x3d,0x2b,0xb0,0x3f,0x2b,0x2d,0xb0,0x74,0x2c,0xb0,0x3d,0x2b,0xb0,0x40, + 0x2b,0x2d,0xb0,0x75,0x2c,0xb3,0x9,0x4,0x2,0x3,0x45,0x58,0x21,0x1b,0x23,0x21,0x59,0x42,0x2b,0xb0,0x8,0x65,0xb0,0x3,0x24,0x50,0x78,0xb1,0x5,0x1, + 0x15,0x45,0x58,0x30,0x59,0x2d,0x0,0x0,0x0,0x4b,0xb8,0x0,0xc8,0x52,0x58,0xb1,0x1,0x1,0x8e,0x59,0xb0,0x1,0xb9,0x8,0x0,0x8,0x0,0x63,0x70,0xb1, + 0x0,0x7,0x42,0xb2,0x19,0x1,0x0,0x2a,0xb1,0x0,0x7,0x42,0xb3,0xc,0x8,0x1,0x8,0x2a,0xb1,0x0,0x7,0x42,0xb3,0x16,0x6,0x1,0x8,0x2a,0xb1,0x0, + 0x8,0x42,0xba,0x3,0x40,0x0,0x1,0x0,0x9,0x2a,0xb1,0x0,0x9,0x42,0xba,0x0,0x40,0x0,0x1,0x0,0x9,0x2a,0xb1,0x3,0x0,0x44,0xb1,0x24,0x1,0x88, + 0x51,0x58,0xb0,0x40,0x88,0x58,0xb1,0x3,0x64,0x44,0xb1,0x26,0x1,0x88,0x51,0x58,0xba,0x8,0x80,0x0,0x1,0x4,0x40,0x88,0x63,0x54,0x58,0xb1,0x3,0x0, + 0x44,0x59,0x59,0x59,0x59,0xb3,0xe,0x8,0x1,0xc,0x2a,0xb8,0x1,0xff,0x85,0xb0,0x4,0x8d,0xb1,0x2,0x0,0x44,0xb3,0x5,0x64,0x6,0x0,0x44,0x44,0x0, + 0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0 +}; + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/Geometry.cpp b/thirdparty/RmlUi/Source/Debugger/Geometry.cpp new file mode 100644 index 000000000..f5c60067f --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/Geometry.cpp @@ -0,0 +1,116 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Geometry.h" +#include "../../Include/RmlUi/Core/Context.h" +#include "../../Include/RmlUi/Core/GeometryUtilities.h" +#include "../../Include/RmlUi/Core/RenderInterface.h" + +namespace Rml { +namespace Debugger { + +static Context* context; + +Geometry::Geometry() +{ +} + +void Geometry::SetContext(Context* _context) +{ + context = _context; +} + +// Renders a one-pixel rectangular outline. +void Geometry::RenderOutline(const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour, float width) +{ + if (context == nullptr) + return; + + RenderInterface* render_interface = context->GetRenderInterface(); + + Vertex vertices[4 * 4]; + int indices[6 * 4]; + + GeometryUtilities::GenerateQuad(vertices + 0, indices + 0, Vector2f(0, 0), Vector2f(dimensions.x, width), colour, 0); + GeometryUtilities::GenerateQuad(vertices + 4, indices + 6, Vector2f(0, dimensions.y - width), Vector2f(dimensions.x, width), colour, 4); + GeometryUtilities::GenerateQuad(vertices + 8, indices + 12, Vector2f(0, 0), Vector2f(width, dimensions.y), colour, 8); + GeometryUtilities::GenerateQuad(vertices + 12, indices + 18, Vector2f(dimensions.x - width, 0), Vector2f(width, dimensions.y), colour, 12); + + render_interface->RenderGeometry(vertices, 4 * 4, indices, 6 * 4, 0, origin); +} + +// Renders a box. +void Geometry::RenderBox(const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour) +{ + if (context == nullptr) + return; + + RenderInterface* render_interface = context->GetRenderInterface(); + + Vertex vertices[4]; + int indices[6]; + + GeometryUtilities::GenerateQuad(vertices, indices, Vector2f(0, 0), Vector2f(dimensions.x, dimensions.y), colour, 0); + + render_interface->RenderGeometry(vertices, 4, indices, 6, 0, origin); +} + +// Renders a box with a hole in the middle. +void Geometry::RenderBox(const Vector2f& origin, const Vector2f& dimensions, const Vector2f& hole_origin, const Vector2f& hole_dimensions, const Colourb& colour) +{ + // Top box. + float top_y_dimensions = hole_origin.y - origin.y; + if (top_y_dimensions > 0) + { + RenderBox(origin, Vector2f(dimensions.x, top_y_dimensions), colour); + } + + // Bottom box. + float bottom_y_dimensions = (origin.y + dimensions.y) - (hole_origin.y + hole_dimensions.y); + if (bottom_y_dimensions > 0) + { + RenderBox(Vector2f(origin.x, hole_origin.y + hole_dimensions.y), Vector2f(dimensions.x, bottom_y_dimensions), colour); + } + + // Left box. + float left_x_dimensions = hole_origin.x - origin.x; + if (left_x_dimensions > 0) + { + RenderBox(Vector2f(origin.x, hole_origin.y), Vector2f(left_x_dimensions, hole_dimensions.y), colour); + } + + // Right box. + float right_x_dimensions = (origin.x + dimensions.x) - (hole_origin.x + hole_dimensions.x); + if (right_x_dimensions > 0) + { + RenderBox(Vector2f(hole_origin.x + hole_dimensions.x, hole_origin.y), Vector2f(right_x_dimensions, hole_dimensions.y), colour); + } +} + +} +} diff --git a/thirdparty/RmlUi/Source/Debugger/Geometry.h b/thirdparty/RmlUi/Source/Debugger/Geometry.h new file mode 100644 index 000000000..5c6751242 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/Geometry.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_DEBUGGER_GEOMETRY_H +#define RMLUI_DEBUGGER_GEOMETRY_H + +#include "../../Include/RmlUi/Core/Types.h" + +namespace Rml { + +class Context; + +namespace Debugger { + +/** + Helper class for generating geometry for the debugger. + + @author Peter Curry + */ + +class Geometry +{ +public: + // Set the context to render through. + static void SetContext(Context* context); + + // Renders a one-pixel rectangular outline. + static void RenderOutline(const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour, float width); + // Renders a box. + static void RenderBox(const Vector2f& origin, const Vector2f& dimensions, const Colourb& colour); + // Renders a box with a hole in the middle. + static void RenderBox(const Vector2f& origin, const Vector2f& dimensions, const Vector2f& hole_origin, const Vector2f& hole_dimensions, const Colourb& colour); + +private: + Geometry(); +}; + +} +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Debugger/InfoSource.h b/thirdparty/RmlUi/Source/Debugger/InfoSource.h new file mode 100644 index 000000000..98f9f8278 --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/InfoSource.h @@ -0,0 +1,170 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +static const char* info_rcss = R"RCSS( +body +{ + width: 320dp; + min-width: 320dp; + min-height: 150dp; + margin-top: 42dp; + margin-right: 20dp; + margin-left: auto; +} +div#content +{ + height: auto; + max-height: 650dp; +} +div#content div h2 +{ + padding-left: 5dp; +} +div#content div div +{ + font-size: 12dp; + padding-left: 10dp; +} +div#content .name +{ + color: #610; +} +div#ancestors p:hover, +div#children p:hover +{ + background-color: #ddd; +} +scrollbarvertical +{ + scrollbar-margin: 0px; +} +h3.strong +{ + margin-top: 1.0em; + padding: 2dp; + color: #900; + background-color: #eee; +} +#pseudo pseudo +{ + padding: 0 8dp 0 3dp; + background-color: #ddd; + border: 2px #aaa; + display: inline-block; +} +#pseudo pseudo.active +{ + border-color: #8af; + background-color: #eef; +} +div.header_button +{ + font-size: 0.9em; + margin-left: 3dp; + z-index: 1; + float: right; + width: 18dp; + color: #999; + background-color: #666; + border-width: 1px; + border-color: #666; + text-align: center; +} +div.header_button.active +{ + border-color: #ccc; + color: #fff; +} +div.header_button:hover +{ + background-color: #555; +} +div.header_button:active +{ + background-color: #444; +} +div#title-content { + width: 220dp; +} +div#title-content em { + font-size: 14dp; +} +p.non_dom { + font-style: italic; +} +)RCSS"; + +static const char* info_rml = R"RML( +

+ +
X
+
U
+
D
+
*
+
Element Information
+

+
+
+ :hover + :active + :focus + :checked + +
+
+

Attributes

+
+
+
+
+

Properties

+
+
+
+
+

Events

+
+
+
+
+

Position

+
+
+
+
+

Ancestors

+
+
+
+
+

Children

+
+
+
+
+)RML"; diff --git a/thirdparty/RmlUi/Source/Debugger/LogSource.h b/thirdparty/RmlUi/Source/Debugger/LogSource.h new file mode 100644 index 000000000..826e6406b --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/LogSource.h @@ -0,0 +1,110 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +static const char* log_rcss = R"RCSS(body +{ + width: 400dp; + height: 300dp; + min-width: 230dp; + min-height: 150dp; + top: 42dp; + left: 20dp; +} +div#tools +{ + float: right; + width: 200dp; +} +div.log-entry +{ + margin: 3dp 2dp; +} +div.log-entry div.icon +{ + float: left; + display: block; + width: 18dp; + height: 18dp; + text-align: center; + border-width: 1px; + margin-right: 5dp; +} +div.button +{ + display: inline-block; + width: 32dp; + font-size: 13dp; + line-height: 20dp; + text-align: center; + border-width: 1px; + margin-right: 3dp; +} +div.button.clear +{ + border-color: #666; + background-color: #aaa; + color: #111; +} +div.button:hover +{ + border-color: #ddd; +} +div.button:active +{ + border-color: #fff; +} +div.button.last +{ + margin-right: 0px; +} +div.log-entry p.message +{ + display: block; + white-space: pre-wrap; + margin-left: 20dp; +} +)RCSS"; + +static const char* log_rml = R"RML( +

+ +
X
+
+
Clear
+
On
+
On
+
Off
+
On
+
+
Event Log
+

+
+ No messages in log. +
+ +)RML"; diff --git a/thirdparty/RmlUi/Source/Debugger/MenuSource.h b/thirdparty/RmlUi/Source/Debugger/MenuSource.h new file mode 100644 index 000000000..49149205a --- /dev/null +++ b/thirdparty/RmlUi/Source/Debugger/MenuSource.h @@ -0,0 +1,93 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +static const char* menu_rcss = R"RCSS( +body +{ + width: 100%; + height: 32dp; + position: absolute; + z-index: 1000000; + background: #888; + font-family: rmlui-debugger-font; + font-size: 14dp; + color: black; +} +div +{ + display: block; +} +div#button-group +{ + margin-top: 3dp; +} +button +{ + border-width: 1px; + border-color: #666; + background: #ddd; + margin-left: 6dp; + display: inline-block; + width: 130dp; + line-height: 24dp; + text-align: center; +} +button:hover +{ + background: #eee; +} +button:active +{ + background: #fff; +} +div#version-info +{ + padding: 0px; + margin-top: 0px; + font-size: 20dp; + float: right; + margin-right: 20dp; + width: 200dp; + text-align: right; + color: white; +} +span#version-number +{ + font-size: 15dp; +} +)RCSS"; + + +static const char* menu_rml = R"RML( +
RmlUi
+
+ + + +
+)RML"; diff --git a/thirdparty/RmlUi/Source/Lua/Colourb.cpp b/thirdparty/RmlUi/Source/Lua/Colourb.cpp new file mode 100644 index 000000000..cda03f19a --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Colourb.cpp @@ -0,0 +1,235 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Colourb.h" + + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,Colourbnew); + lua_setfield(L,metatable_index-1,"new"); + + lua_pushcfunction(L,Colourb__eq); + lua_setfield(L,metatable_index,"__eq"); + + lua_pushcfunction(L,Colourb__add); + lua_setfield(L,metatable_index,"__add"); + + lua_pushcfunction(L,Colourb__mul); + lua_setfield(L,metatable_index,"__mul"); + + return; +} +int Colourbnew(lua_State* L) +{ + byte red = (byte)luaL_checkinteger(L,1); + byte green = (byte)luaL_checkinteger(L,2); + byte blue = (byte)luaL_checkinteger(L,3); + byte alpha = (byte)luaL_checkinteger(L,4); + + Colourb* col = new Colourb(red,green,blue,alpha); + + LuaType::push(L,col,true); + return 1; +} + +int Colourb__eq(lua_State* L) +{ + Colourb* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Colourb* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + lua_pushboolean(L, (*lhs) == (*rhs) ? 1 : 0); + return 1; +} + +int Colourb__add(lua_State* L) +{ + Colourb* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Colourb* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + Colourb* res = new Colourb((*lhs) + (*rhs)); + + LuaType::push(L,res,true); + return 1; +} + +int Colourb__mul(lua_State* L) +{ + Colourb* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + float rhs = (float)luaL_checknumber(L,2); + + Colourb* res = new Colourb((*lhs) * rhs); + + LuaType::push(L,res,true); + return 1; +} + + +//getters +int ColourbGetAttrred(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->red); + return 1; +} + +int ColourbGetAttrgreen(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->green); + return 1; +} + +int ColourbGetAttrblue(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->blue); + return 1; +} + +int ColourbGetAttralpha(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->alpha); + return 1; +} + +int ColourbGetAttrrgba(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->red); + lua_pushinteger(L,obj->green); + lua_pushinteger(L,obj->blue); + lua_pushinteger(L,obj->alpha); + return 4; +} + + +//setters +int ColourbSetAttrred(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + byte red = (byte)luaL_checkinteger(L,2); + obj->red = red; + return 0; +} + +int ColourbSetAttrgreen(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + byte green = (byte)luaL_checkinteger(L,2); + obj->green = green; + return 0; +} + +int ColourbSetAttrblue(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + byte blue = (byte)luaL_checkinteger(L,2); + obj->blue = blue; + return 0; +} + +int ColourbSetAttralpha(lua_State* L) +{ + Colourb* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + byte alpha = (byte)luaL_checkinteger(L,2); + obj->alpha = alpha; + return 0; +} + +int ColourbSetAttrrgba(lua_State* L) +{ + Colourb* obj = nullptr; + int top = lua_gettop(L); + //each of the items are optional. + if(top > 0) + { + obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + if(top > 1) + { + if(top > 2) + { + if(top > 3) + obj->alpha = (byte)luaL_checkinteger(L,4); + obj->blue = (byte)luaL_checkinteger(L,3); + } + obj->green = (byte)luaL_checkinteger(L,2); + } + obj->red = (byte)luaL_checkinteger(L,1); + } + return 0; +} + + +RegType ColourbMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ColourbGetters[] = +{ + RMLUI_LUAGETTER(Colourb,red) + RMLUI_LUAGETTER(Colourb,green) + RMLUI_LUAGETTER(Colourb,blue) + RMLUI_LUAGETTER(Colourb,alpha) + RMLUI_LUAGETTER(Colourb,rgba) + { nullptr, nullptr }, +}; + +luaL_Reg ColourbSetters[] = +{ + RMLUI_LUASETTER(Colourb,red) + RMLUI_LUASETTER(Colourb,green) + RMLUI_LUASETTER(Colourb,blue) + RMLUI_LUASETTER(Colourb,alpha) + RMLUI_LUASETTER(Colourb,rgba) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Colourb) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Colourb.h b/thirdparty/RmlUi/Source/Lua/Colourb.h new file mode 100644 index 000000000..a2e9fc217 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Colourb.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_COLOURB_H +#define RMLUI_LUA_COLOURB_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); +int Colourbnew(lua_State* L); +int Colourb__eq(lua_State* L); +int Colourb__add(lua_State* L); +int Colourb__mul(lua_State* L); + + +//getters +int ColourbGetAttrred(lua_State* L); +int ColourbGetAttrgreen(lua_State* L); +int ColourbGetAttrblue(lua_State* L); +int ColourbGetAttralpha(lua_State* L); +int ColourbGetAttrrgba(lua_State* L); + +//setters +int ColourbSetAttrred(lua_State* L); +int ColourbSetAttrgreen(lua_State* L); +int ColourbSetAttrblue(lua_State* L); +int ColourbSetAttralpha(lua_State* L); +int ColourbSetAttrrgba(lua_State* L); + +extern RegType ColourbMethods[]; +extern luaL_Reg ColourbGetters[]; +extern luaL_Reg ColourbSetters[]; + +RMLUI_LUATYPE_DECLARE(Colourb) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Colourf.cpp b/thirdparty/RmlUi/Source/Lua/Colourf.cpp new file mode 100644 index 000000000..ebe1b13b2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Colourf.cpp @@ -0,0 +1,208 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Colourf.h" + + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,Colourfnew); + lua_setfield(L,metatable_index-1,"new"); + + lua_pushcfunction(L,Colourf__eq); + lua_setfield(L,metatable_index,"__eq"); + + return; +} + +//metamethods +int Colourfnew(lua_State* L) +{ + float red = (float)luaL_checknumber(L,1); + float green = (float)luaL_checknumber(L,2); + float blue = (float)luaL_checknumber(L,3); + float alpha = (float)luaL_checknumber(L,4); + + Colourf* col = new Colourf(red,green,blue,alpha); + + LuaType::push(L,col,true); + return 1; +} + +int Colourf__eq(lua_State* L) +{ + Colourf* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Colourf* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + lua_pushboolean(L, (*lhs) == (*rhs) ? 1 : 0); + return 1; +} + + +//getters +int ColourfGetAttrred(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushnumber(L,obj->red); + return 1; +} + +int ColourfGetAttrgreen(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushnumber(L,obj->green); + return 1; +} + +int ColourfGetAttrblue(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushnumber(L,obj->blue); + return 1; +} + +int ColourfGetAttralpha(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushnumber(L,obj->alpha); + return 1; +} + +int ColourfGetAttrrgba(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushnumber(L,obj->red); + lua_pushnumber(L,obj->green); + lua_pushnumber(L,obj->blue); + lua_pushnumber(L,obj->alpha); + return 4; +} + + +//setters +int ColourfSetAttrred(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + float red = (float)luaL_checknumber(L,2); + obj->red = red; + return 0; +} + +int ColourfSetAttrgreen(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + float green = (float)luaL_checknumber(L,2); + obj->green = green; + return 0; +} + +int ColourfSetAttrblue(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + float blue = (float)luaL_checknumber(L,2); + obj->blue = blue; + return 0; +} + +int ColourfSetAttralpha(lua_State* L) +{ + Colourf* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + float alpha = (float)luaL_checknumber(L,2); + obj->alpha = alpha; + return 0; +} + +int ColourfSetAttrrgba(lua_State* L) +{ + Colourf* obj = nullptr; + int top = lua_gettop(L); + //each of the items are optional. + if(top > 0) + { + obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + if(top > 1) + { + if(top > 2) + { + if(top > 3) + obj->alpha = (float)luaL_checknumber(L,4); + obj->blue = (float)luaL_checknumber(L,3); + } + obj->green = (float)luaL_checknumber(L,2); + } + obj->red = (float)luaL_checknumber(L,1); + } + return 0; +} + + +RegType ColourfMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ColourfGetters[] = +{ + RMLUI_LUAGETTER(Colourf,red) + RMLUI_LUAGETTER(Colourf,green) + RMLUI_LUAGETTER(Colourf,blue) + RMLUI_LUAGETTER(Colourf,alpha) + RMLUI_LUAGETTER(Colourf,rgba) + { nullptr, nullptr }, +}; + +luaL_Reg ColourfSetters[] = +{ + RMLUI_LUASETTER(Colourf,red) + RMLUI_LUASETTER(Colourf,green) + RMLUI_LUASETTER(Colourf,blue) + RMLUI_LUASETTER(Colourf,alpha) + RMLUI_LUASETTER(Colourf,rgba) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Colourf) + + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Colourf.h b/thirdparty/RmlUi/Source/Lua/Colourf.h new file mode 100644 index 000000000..809ecb2dd --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Colourf.h @@ -0,0 +1,64 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_COLOURF_H +#define RMLUI_LUA_COLOURF_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); +//metamethods +int Colourfnew(lua_State* L); +int Colourf__eq(lua_State* L); + +//getters +int ColourfGetAttrred(lua_State* L); +int ColourfGetAttrgreen(lua_State* L); +int ColourfGetAttrblue(lua_State* L); +int ColourfGetAttralpha(lua_State* L); +int ColourfGetAttrrgba(lua_State* L); + +//setters +int ColourfSetAttrred(lua_State* L); +int ColourfSetAttrgreen(lua_State* L); +int ColourfSetAttrblue(lua_State* L); +int ColourfSetAttralpha(lua_State* L); +int ColourfSetAttrrgba(lua_State* L); + +extern RegType ColourfMethods[]; +extern luaL_Reg ColourfGetters[]; +extern luaL_Reg ColourfSetters[]; + +RMLUI_LUATYPE_DECLARE(Colourf) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Context.cpp b/thirdparty/RmlUi/Source/Lua/Context.cpp new file mode 100644 index 000000000..b324d6cfb --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Context.cpp @@ -0,0 +1,222 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Context.h" +#include +#include +#include +#include "LuaEventListener.h" +#include "ContextDocumentsProxy.h" + +namespace Rml { +namespace Lua { +typedef ElementDocument Document; +template<> void ExtraInit(lua_State* /*L*/, int /*metatable_index*/) { return; } + +//methods +int ContextAddEventListener(lua_State* L, Context* obj) +{ + //need to make an EventListener for Lua before I can do anything else + const char* evt = luaL_checkstring(L,1); //event + Element* element = nullptr; + bool capturephase = false; + //get the rest of the stuff needed to construct the listener + if(lua_gettop(L) > 2) + { + if(!lua_isnoneornil(L,3)) + element = LuaType::check(L,3); + if(!lua_isnoneornil(L,4)) + capturephase = RMLUI_CHECK_BOOL(L,4); + + } + int type = lua_type(L,2); + if(type == LUA_TFUNCTION) + { + if(element) + element->AddEventListener(evt, new LuaEventListener(L,2,element), capturephase); + else + obj->AddEventListener(evt, new LuaEventListener(L,2,nullptr), capturephase); + } + else if(type == LUA_TSTRING) + { + if(element) + element->AddEventListener(evt, new LuaEventListener(luaL_checkstring(L,2),element), capturephase); + else + obj->AddEventListener(evt, new LuaEventListener(luaL_checkstring(L,2),nullptr), capturephase); + } + else + { + Log::Message(Log::LT_WARNING, "Lua Context:AddEventLisener's 2nd argument can only be a Lua function or a string, you passed in a %s", lua_typename(L,type)); + } + return 0; +} + +int ContextCreateDocument(lua_State* L, Context* obj) +{ + const char* tag; + if(lua_gettop(L) < 1) + tag = "body"; + else + tag = luaL_checkstring(L,1); + Document* doc = obj->CreateDocument(tag); + LuaType::push(L,doc,false); + return 1; +} + +int ContextLoadDocument(lua_State* L, Context* obj) +{ + const char* path = luaL_checkstring(L,1); + Document* doc = obj->LoadDocument(path); + LuaType::push(L,doc,false); + return 1; +} + +int ContextRender(lua_State* L, Context* obj) +{ + lua_pushboolean(L,obj->Render()); + return 1; +} + +int ContextUnloadAllDocuments(lua_State* /*L*/, Context* obj) +{ + obj->UnloadAllDocuments(); + return 0; +} + +int ContextUnloadDocument(lua_State* L, Context* obj) +{ + Document* doc = LuaType::check(L,1); + obj->UnloadDocument(doc); + return 0; +} + +int ContextUpdate(lua_State* L, Context* obj) +{ + lua_pushboolean(L,obj->Update()); + return 1; +} + + +//getters +int ContextGetAttrdimensions(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + const Vector2i* dim = &cont->GetDimensions(); + //const_cast-ing so that the user can do dimensions.x = 3 and it will actually change the dimensions + //of the context + LuaType::push(L,const_cast(dim)); + return 1; +} + +//returns a table of everything +int ContextGetAttrdocuments(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + RMLUI_CHECK_OBJ(cont); + ContextDocumentsProxy* cdp = new ContextDocumentsProxy(); + cdp->owner = cont; + LuaType::push(L,cdp,true); //does get garbage collected (deleted) + return 1; +} + +int ContextGetAttrfocus_element(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + RMLUI_CHECK_OBJ(cont); + LuaType::push(L,cont->GetFocusElement()); + return 1; +} + +int ContextGetAttrhover_element(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + RMLUI_CHECK_OBJ(cont); + LuaType::push(L,cont->GetHoverElement()); + return 1; +} + +int ContextGetAttrname(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + RMLUI_CHECK_OBJ(cont); + lua_pushstring(L,cont->GetName().c_str()); + return 1; +} + +int ContextGetAttrroot_element(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + RMLUI_CHECK_OBJ(cont); + LuaType::push(L,cont->GetRootElement()); + return 1; +} + + +//setters +int ContextSetAttrdimensions(lua_State* L) +{ + Context* cont = LuaType::check(L,1); + RMLUI_CHECK_OBJ(cont); + Vector2i* dim = LuaType::check(L,2); + cont->SetDimensions(*dim); + return 0; +} + + +RegType ContextMethods[] = +{ + RMLUI_LUAMETHOD(Context,AddEventListener) + RMLUI_LUAMETHOD(Context,CreateDocument) + RMLUI_LUAMETHOD(Context,LoadDocument) + RMLUI_LUAMETHOD(Context,Render) + RMLUI_LUAMETHOD(Context,UnloadAllDocuments) + RMLUI_LUAMETHOD(Context,UnloadDocument) + RMLUI_LUAMETHOD(Context,Update) + { nullptr, nullptr }, +}; + +luaL_Reg ContextGetters[] = +{ + RMLUI_LUAGETTER(Context,dimensions) + RMLUI_LUAGETTER(Context,documents) + RMLUI_LUAGETTER(Context,focus_element) + RMLUI_LUAGETTER(Context,hover_element) + RMLUI_LUAGETTER(Context,name) + RMLUI_LUAGETTER(Context,root_element) + { nullptr, nullptr }, +}; + +luaL_Reg ContextSetters[] = +{ + RMLUI_LUASETTER(Context,dimensions) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Context) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Context.h b/thirdparty/RmlUi/Source/Lua/Context.h new file mode 100644 index 000000000..7ff598971 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Context.h @@ -0,0 +1,69 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_CONTEXT_H +#define RMLUI_LUA_CONTEXT_H + +#include +#include +#include + + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); + +//methods +int ContextAddEventListener(lua_State* L, Context* obj); +int ContextCreateDocument(lua_State* L, Context* obj); +int ContextLoadDocument(lua_State* L, Context* obj); +int ContextRender(lua_State* L, Context* obj); +int ContextUnloadAllDocuments(lua_State* L, Context* obj); +int ContextUnloadDocument(lua_State* L, Context* obj); +int ContextUpdate(lua_State* L, Context* obj); + +//getters +int ContextGetAttrdimensions(lua_State* L); +int ContextGetAttrdocuments(lua_State* L); +int ContextGetAttrfocus_element(lua_State* L); +int ContextGetAttrhover_element(lua_State* L); +int ContextGetAttrname(lua_State* L); +int ContextGetAttrroot_element(lua_State* L); + +//setters +int ContextSetAttrdimensions(lua_State* L); + + +extern RegType ContextMethods[]; +extern luaL_Reg ContextGetters[]; +extern luaL_Reg ContextSetters[]; + +RMLUI_LUATYPE_DECLARE(Context) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/ContextDocumentsProxy.cpp b/thirdparty/RmlUi/Source/Lua/ContextDocumentsProxy.cpp new file mode 100644 index 000000000..9ca84f919 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ContextDocumentsProxy.cpp @@ -0,0 +1,152 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ContextDocumentsProxy.h" +#include + +namespace Rml { +namespace Lua { +typedef ElementDocument Document; +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,ContextDocumentsProxy__index); + lua_setfield(L,metatable_index,"__index"); + lua_pushcfunction(L,ContextDocumentsProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + lua_pushcfunction(L,ContextDocumentsProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +int ContextDocumentsProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int type = lua_type(L,2); + if(type == LUA_TNUMBER || type == LUA_TSTRING) //only valid key types + { + ContextDocumentsProxy* proxy = LuaType::check(L,1); + Document* ret = nullptr; + if(type == LUA_TSTRING) + ret = proxy->owner->GetDocument(luaL_checkstring(L,2)); + else + ret = proxy->owner->GetDocument((int)luaL_checkinteger(L,2)); + LuaType::push(L,ret,false); + return 1; + } + else + return LuaType::index(L); + +} + +//[1] is the object, [2] is the last used key, [3] is the userdata +int ContextDocumentsProxy__pairs(lua_State* L) +{ + Document* doc = nullptr; + ContextDocumentsProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int* pindex = (int*)lua_touserdata(L,3); + if((*pindex) == -1) + *pindex = 0; + + int num_docs = obj->owner->GetNumDocuments(); + //because there can be missing indexes, make sure to continue until there + //is actually a document at the index + while((*pindex) < num_docs) + { + doc = obj->owner->GetDocument((*pindex)++); + if(doc != nullptr) + break; + } + + //If we found a document + if(doc != nullptr) + { + lua_pushstring(L,doc->GetId().c_str()); + LuaType::push(L,doc); + } + else //if we were at the end and didn't find a document + { + lua_pushnil(L); + lua_pushnil(L); + } + return 2; +} + +//same as __pairs, but putting an integer key instead of a string key +int ContextDocumentsProxy__ipairs(lua_State* L) +{ + Document* doc = nullptr; + ContextDocumentsProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int* pindex = (int*)lua_touserdata(L,3); + if((*pindex) == -1) + *pindex = 0; + + int num_docs = obj->owner->GetNumDocuments(); + //because there can be missing indexes, make sure to continue until there + //is actually a document at the index + while((*pindex) < num_docs) + { + doc = obj->owner->GetDocument((*pindex)++); + if(doc != nullptr) + break; + } + + //we found a document + if(doc != nullptr) + { + lua_pushinteger(L,(*pindex)-1); + LuaType::push(L,doc); + } + else //we got to the end and didn't find another document + { + lua_pushnil(L); + lua_pushnil(L); + } + return 2; +} + + +RegType ContextDocumentsProxyMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ContextDocumentsProxyGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ContextDocumentsProxySetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ContextDocumentsProxy) + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/ContextDocumentsProxy.h b/thirdparty/RmlUi/Source/Lua/ContextDocumentsProxy.h new file mode 100644 index 000000000..c5f23962e --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ContextDocumentsProxy.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_CONTEXTDOCUMENTSPROXY_H +#define RMLUI_LUA_CONTEXTDOCUMENTSPROXY_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +//where owner is the context that we should look information from +struct ContextDocumentsProxy { Context* owner; }; + +template<> void ExtraInit(lua_State* L, int metatable_index); +int ContextDocumentsProxy__index(lua_State* L); +int ContextDocumentsProxy__pairs(lua_State* L); +int ContextDocumentsProxy__ipairs(lua_State* L); + +extern RegType ContextDocumentsProxyMethods[]; +extern luaL_Reg ContextDocumentsProxyGetters[]; +extern luaL_Reg ContextDocumentsProxySetters[]; + +RMLUI_LUATYPE_DECLARE(ContextDocumentsProxy) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Document.cpp b/thirdparty/RmlUi/Source/Lua/Document.cpp new file mode 100644 index 000000000..9f3f8da07 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Document.cpp @@ -0,0 +1,196 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Document.h" +#include +#include +#include "Element.h" +#include + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + //we will inherit from Element + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index - 1); + AddTypeToElementAsTable(L); + + //create the DocumentFocus table + lua_getglobal(L,"DocumentModal"); + if(lua_isnoneornil(L,-1)) + { + lua_pop(L,1); //pop unsucessful getglobal + lua_newtable(L); //create a table for holding the enum + lua_pushinteger(L,(int)ModalFlag::None); + lua_setfield(L,-2,"None"); + lua_pushinteger(L,(int)ModalFlag::Modal); + lua_setfield(L,-2,"Modal"); + lua_pushinteger(L, (int)ModalFlag::Keep); + lua_setfield(L,-2,"Keep"); + lua_setglobal(L,"DocumentModal"); + } + + //create the DocumentFocus table + lua_getglobal(L, "DocumentFocus"); + if (lua_isnoneornil(L, -1)) + { + lua_pop(L, 1); //pop unsucessful getglobal + lua_newtable(L); //create a table for holding the enum + lua_pushinteger(L, (int)FocusFlag::None); + lua_setfield(L, -2, "None"); + lua_pushinteger(L, (int)FocusFlag::Document); + lua_setfield(L, -2, "Document"); + lua_pushinteger(L, (int)FocusFlag::Keep); + lua_setfield(L, -2, "Keep"); + lua_pushinteger(L, (int)FocusFlag::Auto); + lua_setfield(L, -2, "Auto"); + lua_setglobal(L, "DocumentFocus"); + } +} + +//methods +int DocumentPullToFront(lua_State* /*L*/, Document* obj) +{ + obj->PullToFront(); + return 0; +} + +int DocumentPushToBack(lua_State* /*L*/, Document* obj) +{ + obj->PushToBack(); + return 0; +} + +int DocumentShow(lua_State* L, Document* obj) +{ + int top = lua_gettop(L); + if(top == 0) + obj->Show(); + else if(top == 1) + { + ModalFlag modal = (ModalFlag)luaL_checkinteger(L,1); + obj->Show(modal); + } + else + { + ModalFlag modal = (ModalFlag)luaL_checkinteger(L,1); + FocusFlag focus = (FocusFlag)luaL_checkinteger(L,2); + obj->Show(modal, focus); + } + return 0; +} + +int DocumentHide(lua_State* /*L*/, Document* obj) +{ + obj->Hide(); + return 0; +} + +int DocumentClose(lua_State* /*L*/, Document* obj) +{ + obj->Close(); + return 0; +} + +int DocumentCreateElement(lua_State* L, Document* obj) +{ + const char* tag = luaL_checkstring(L,1); + ElementPtr* ele = new ElementPtr( obj->CreateElement(tag) ); + LuaType::push(L,ele,true); + return 1; +} + +int DocumentCreateTextNode(lua_State* L, Document* obj) +{ + //need ElementText object first + const char* text = luaL_checkstring(L,1); + ElementPtr* et = new ElementPtr( obj->CreateTextNode(text) ); + LuaType::push(L, et, true); + return 1; +} + + +//getters +int DocumentGetAttrtitle(lua_State* L) +{ + Document* doc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(doc); + lua_pushstring(L,doc->GetTitle().c_str()); + return 1; +} + +int DocumentGetAttrcontext(lua_State* L) +{ + Document* doc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(doc); + LuaType::push(L,doc->GetContext(),false); + return 1; +} + + +//setters +int DocumentSetAttrtitle(lua_State* L) +{ + Document* doc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(doc); + const char* title = luaL_checkstring(L,2); + doc->SetTitle(title); + return 0; +} + + +RegType DocumentMethods[] = +{ + RMLUI_LUAMETHOD(Document,PullToFront) + RMLUI_LUAMETHOD(Document,PushToBack) + RMLUI_LUAMETHOD(Document,Show) + RMLUI_LUAMETHOD(Document,Hide) + RMLUI_LUAMETHOD(Document,Close) + RMLUI_LUAMETHOD(Document,CreateElement) + RMLUI_LUAMETHOD(Document,CreateTextNode) + { nullptr, nullptr }, +}; + +luaL_Reg DocumentGetters[] = +{ + RMLUI_LUAGETTER(Document,title) + RMLUI_LUAGETTER(Document,context) + { nullptr, nullptr }, +}; + +luaL_Reg DocumentSetters[] = +{ + RMLUI_LUASETTER(Document,title) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Document) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Document.h b/thirdparty/RmlUi/Source/Lua/Document.h new file mode 100644 index 000000000..a5ccddcee --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Document.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_DOCUMENT_H +#define RMLUI_LUA_DOCUMENT_H + +#include +#include +#include + + +namespace Rml { +namespace Lua { +typedef ElementDocument Document; + +template<> void ExtraInit(lua_State* L, int metatable_index); + +//methods +int DocumentPullToFront(lua_State* L, Document* obj); +int DocumentPushToBack(lua_State* L, Document* obj); +int DocumentShow(lua_State* L, Document* obj); +int DocumentHide(lua_State* L, Document* obj); +int DocumentClose(lua_State* L, Document* obj); +int DocumentCreateElement(lua_State* L, Document* obj); +int DocumentCreateTextNode(lua_State* L, Document* obj); + +//getters +int DocumentGetAttrtitle(lua_State* L); +int DocumentGetAttrcontext(lua_State* L); + +//setters +int DocumentSetAttrtitle(lua_State* L); + +extern RegType DocumentMethods[]; +extern luaL_Reg DocumentGetters[]; +extern luaL_Reg DocumentSetters[]; + +RMLUI_LUATYPE_DECLARE(Document) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Element.cpp b/thirdparty/RmlUi/Source/Lua/Element.cpp new file mode 100644 index 000000000..4efa81811 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Element.cpp @@ -0,0 +1,648 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Element.h" +#include "ElementStyleProxy.h" +#include "LuaEventListener.h" +#include "ElementAttributesProxy.h" +#include "ElementChildNodesProxy.h" +#include + + +namespace Rml { +namespace Lua { +typedef ElementDocument Document; + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + int top = lua_gettop(L); + //guarantee the "Element.As" table exists + lua_getfield(L,metatable_index-1,"As"); + if(lua_isnoneornil(L,-1)) //if it doesn't exist, create it + { + lua_newtable(L); + lua_setfield(L,metatable_index-1,"As"); + } + lua_pop(L,1); //pop the result of lua_getfield + lua_pushcfunction(L,Elementnew); + lua_setfield(L,metatable_index-1,"new"); + lua_settop(L,top); +} + +int Elementnew(lua_State* L) +{ + const char* tag = luaL_checkstring(L,1); + Element* ele = new Element(tag); + LuaType::push(L,ele,true); + return 1; +} + +//methods +int ElementAddEventListener(lua_State* L, Element* obj) +{ + int top = lua_gettop(L); + bool capture = false; + //default false if they didn't pass it in + if (top > 2) + capture = RMLUI_CHECK_BOOL(L,3); + + const char* event = luaL_checkstring(L,1); + + LuaEventListener* listener = nullptr; + int type = lua_type(L,2); + if(type == LUA_TFUNCTION) + { + listener = new LuaEventListener(L,2,obj); + } + else if(type == LUA_TSTRING) + { + const char* code = luaL_checkstring(L,2); + listener = new LuaEventListener(code,obj); + } + else + { + Log::Message(Log::LT_WARNING, "Lua Context:AddEventLisener's 2nd argument can only be a Lua function or a string, you passed in a %s", lua_typename(L,type)); + } + + if(listener != nullptr) + { + obj->AddEventListener(event,listener,capture); + } + return 0; +} + +int ElementAppendChild(lua_State* L, Element* obj) +{ + ElementPtr* element = LuaType::check(L, 1); + if (*element) + obj->AppendChild(std::move(*element)); + else + Log::Message(Log::LT_WARNING, "Could not append child to element '%s', as the child was null. Was it already moved from?", obj->GetAddress().c_str()); + return 0; +} + +int ElementBlur(lua_State* /*L*/, Element* obj) +{ + obj->Blur(); + return 0; +} + +int ElementClick(lua_State* /*L*/, Element* obj) +{ + obj->Click(); + return 0; +} + +int ElementDispatchEvent(lua_State* L, Element* obj) +{ + const char* event = luaL_checkstring(L,1); + Dictionary params; + lua_pushnil(L); //becauase lua_next pops a key from the stack first, we don't want to pop the table + while(lua_next(L,2) != 0) + { + //[-1] is value, [-2] is key + int type = lua_type(L,-1); + const char* key = luaL_checkstring(L,-2); //key HAS to be a string, or things will go bad + switch(type) + { + case LUA_TNUMBER: + params[key] = (float)lua_tonumber(L,-1); + break; + case LUA_TBOOLEAN: + params[key] = RMLUI_CHECK_BOOL(L,-1); + break; + case LUA_TSTRING: + params[key] = luaL_checkstring(L,-1); + break; + case LUA_TUSERDATA: + case LUA_TLIGHTUSERDATA: + params[key] = lua_touserdata(L,-1); + break; + default: + break; + } + } + obj->DispatchEvent(event, params); + return 0; +} + +int ElementFocus(lua_State* /*L*/, Element* obj) +{ + obj->Focus(); + return 0; +} + +int ElementGetAttribute(lua_State* L, Element* obj) +{ + const char* name = luaL_checkstring(L,1); + Variant* var = obj->GetAttribute(name); + PushVariant(L,var); + return 1; +} + +int ElementGetElementById(lua_State* L, Element* obj) +{ + const char* id = luaL_checkstring(L,1); + Element* ele = obj->GetElementById(id); + LuaType::push(L,ele,false); + return 1; +} + +int ElementGetElementsByTagName(lua_State* L, Element* obj) +{ + const char* tag = luaL_checkstring(L,1); + ElementList list; + obj->GetElementsByTagName(list,tag); + lua_newtable(L); + for(unsigned int i = 0; i < list.size(); i++) + { + lua_pushinteger(L,i); + LuaType::push(L,list[i],false); + lua_settable(L,-3); //-3 is the table + } + return 1; +} + +int ElementHasAttribute(lua_State* L, Element* obj) +{ + const char* name = luaL_checkstring(L,1); + lua_pushboolean(L,obj->HasAttribute(name)); + return 1; +} + +int ElementHasChildNodes(lua_State* L, Element* obj) +{ + lua_pushboolean(L,obj->HasChildNodes()); + return 1; +} + +int ElementInsertBefore(lua_State* L, Element* obj) +{ + ElementPtr* element = LuaType::check(L,1); + Element* adjacent = LuaType::check(L,2); + if(*element) + obj->InsertBefore(std::move(*element), adjacent); + else + Log::Message(Log::LT_WARNING, "Could not insert child to element '%s', as the child was null. Was it already moved from?", obj->GetAddress().c_str()); + return 0; +} + +int ElementIsClassSet(lua_State* L, Element* obj) +{ + const char* name = luaL_checkstring(L,1); + lua_pushboolean(L,obj->IsClassSet(name)); + return 1; +} + +int ElementRemoveAttribute(lua_State* L, Element* obj) +{ + const char* name = luaL_checkstring(L,1); + obj->RemoveAttribute(name); + return 0; +} + +int ElementRemoveChild(lua_State* L, Element* obj) +{ + Element* element = LuaType::check(L,1); + lua_pushboolean(L,static_cast(obj->RemoveChild(element))); + return 1; +} + +int ElementReplaceChild(lua_State* L, Element* obj) +{ + ElementPtr* inserted = LuaType::check(L,1); + Element* replaced = LuaType::check(L,2); + if(*inserted) + lua_pushboolean(L, static_cast(obj->ReplaceChild(std::move(*inserted),replaced))); + else + Log::Message(Log::LT_WARNING, "Could not replace child in element '%s', as the child was null. Was it already moved from?", obj->GetAddress().c_str()); + return 1; +} + +int ElementScrollIntoView(lua_State* L, Element* obj) +{ + bool align = RMLUI_CHECK_BOOL(L,1); + obj->ScrollIntoView(align); + return 0; +} + +int ElementSetAttribute(lua_State* L, Element* obj) +{ + const char* name = luaL_checkstring(L,1); + const char* value = luaL_checkstring(L,2); + obj->SetAttribute(name,String(value)); + return 0; +} + +int ElementSetClass(lua_State* L, Element* obj) +{ + const char* name = luaL_checkstring(L,1); + bool value = RMLUI_CHECK_BOOL(L,2); + obj->SetClass(name,value); + return 0; +} + +//getters +int ElementGetAttrattributes(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + ElementAttributesProxy* proxy = new ElementAttributesProxy(); + proxy->owner = ele; + LuaType::push(L,proxy,true); + return 1; +} + +int ElementGetAttrchild_nodes(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + ElementChildNodesProxy* ecnp = new ElementChildNodesProxy(); + ecnp->owner = ele; + LuaType::push(L,ecnp,true); + return 1; +} + +int ElementGetAttrclass_name(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + String classnames = ele->GetClassNames(); + lua_pushstring(L,classnames.c_str()); + return 1; +} + +int ElementGetAttrclient_left(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetClientLeft()); + return 1; +} + +int ElementGetAttrclient_height(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetClientHeight()); + return 1; +} + +int ElementGetAttrclient_top(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetClientTop()); + return 1; +} + +int ElementGetAttrclient_width(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetClientWidth()); + return 1; +} + +int ElementGetAttrfirst_child(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Element* child = ele->GetFirstChild(); + if(child == nullptr) + lua_pushnil(L); + else + LuaType::push(L,child,false); + return 1; +} + +int ElementGetAttrid(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushstring(L,ele->GetId().c_str()); + return 1; +} + +int ElementGetAttrinner_rml(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushstring(L,ele->GetInnerRML().c_str()); + return 1; +} + +int ElementGetAttrlast_child(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Element* child = ele->GetLastChild(); + if(child == nullptr) + lua_pushnil(L); + else + LuaType::push(L,child,false); + return 1; +} + +int ElementGetAttrnext_sibling(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Element* sibling = ele->GetNextSibling(); + if(sibling == nullptr) + lua_pushnil(L); + else + LuaType::push(L,sibling,false); + return 1; +} + +int ElementGetAttroffset_height(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetOffsetHeight()); + return 1; +} + +int ElementGetAttroffset_left(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetOffsetLeft()); + return 1; +} + +int ElementGetAttroffset_parent(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Element* parent = ele->GetOffsetParent(); + LuaType::push(L,parent,false); + return 1; +} + +int ElementGetAttroffset_top(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L, ele->GetOffsetTop()); + return 1; +} + +int ElementGetAttroffset_width(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetOffsetWidth()); + return 1; +} + +int ElementGetAttrowner_document(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Document* doc = ele->GetOwnerDocument(); + LuaType::push(L,doc,false); + return 1; +} + +int ElementGetAttrparent_node(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Element* parent = ele->GetParentNode(); + if(parent == nullptr) + lua_pushnil(L); + else + LuaType::push(L,parent,false); + return 1; +} + +int ElementGetAttrprevious_sibling(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + Element* sibling = ele->GetPreviousSibling(); + if(sibling == nullptr) + lua_pushnil(L); + else + LuaType::push(L,sibling,false); + return 1; +} + +int ElementGetAttrscroll_height(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetScrollHeight()); + return 1; +} + +int ElementGetAttrscroll_left(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetScrollLeft()); + return 1; +} + +int ElementGetAttrscroll_top(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetScrollTop()); + return 1; +} + +int ElementGetAttrscroll_width(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushnumber(L,ele->GetScrollWidth()); + return 1; +} + +int ElementGetAttrstyle(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + ElementStyleProxy* prox = new ElementStyleProxy(); + prox->owner = ele; + LuaType::push(L,prox,true); + return 1; +} + +int ElementGetAttrtag_name(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + lua_pushstring(L,ele->GetTagName().c_str()); + return 1; +} + + +//setters +int ElementSetAttrclass_name(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + const char* name = luaL_checkstring(L,2); + ele->SetClassNames(name); + return 0; +} + +int ElementSetAttrid(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + const char* id = luaL_checkstring(L,2); + ele->SetId(id); + return 0; +} + +int ElementSetAttrinner_rml(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + const char* rml = luaL_checkstring(L,2); + ele->SetInnerRML(rml); + return 0; +} + +int ElementSetAttrscroll_left(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + float scroll = (float)luaL_checknumber(L,2); + ele->SetScrollLeft(scroll); + return 0; +} + +int ElementSetAttrscroll_top(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + float scroll = (float)luaL_checknumber(L,2); + ele->SetScrollTop(scroll); + return 0; +} + + +RegType ElementMethods[] = +{ + RMLUI_LUAMETHOD(Element,AddEventListener) + RMLUI_LUAMETHOD(Element,AppendChild) + RMLUI_LUAMETHOD(Element,Blur) + RMLUI_LUAMETHOD(Element,Click) + RMLUI_LUAMETHOD(Element,DispatchEvent) + RMLUI_LUAMETHOD(Element,Focus) + RMLUI_LUAMETHOD(Element,GetAttribute) + RMLUI_LUAMETHOD(Element,GetElementById) + RMLUI_LUAMETHOD(Element,GetElementsByTagName) + RMLUI_LUAMETHOD(Element,HasAttribute) + RMLUI_LUAMETHOD(Element,HasChildNodes) + RMLUI_LUAMETHOD(Element,InsertBefore) + RMLUI_LUAMETHOD(Element,IsClassSet) + RMLUI_LUAMETHOD(Element,RemoveAttribute) + RMLUI_LUAMETHOD(Element,RemoveChild) + RMLUI_LUAMETHOD(Element,ReplaceChild) + RMLUI_LUAMETHOD(Element,ScrollIntoView) + RMLUI_LUAMETHOD(Element,SetAttribute) + RMLUI_LUAMETHOD(Element,SetClass) + { nullptr, nullptr }, +}; + +luaL_Reg ElementGetters[] = +{ + RMLUI_LUAGETTER(Element,attributes) + RMLUI_LUAGETTER(Element,child_nodes) + RMLUI_LUAGETTER(Element,class_name) + RMLUI_LUAGETTER(Element,client_left) + RMLUI_LUAGETTER(Element,client_height) + RMLUI_LUAGETTER(Element,client_top) + RMLUI_LUAGETTER(Element,client_width) + RMLUI_LUAGETTER(Element,first_child) + RMLUI_LUAGETTER(Element,id) + RMLUI_LUAGETTER(Element,inner_rml) + RMLUI_LUAGETTER(Element,last_child) + RMLUI_LUAGETTER(Element,next_sibling) + RMLUI_LUAGETTER(Element,offset_height) + RMLUI_LUAGETTER(Element,offset_left) + RMLUI_LUAGETTER(Element,offset_parent) + RMLUI_LUAGETTER(Element,offset_top) + RMLUI_LUAGETTER(Element,offset_width) + RMLUI_LUAGETTER(Element,owner_document) + RMLUI_LUAGETTER(Element,parent_node) + RMLUI_LUAGETTER(Element,previous_sibling) + RMLUI_LUAGETTER(Element,scroll_height) + RMLUI_LUAGETTER(Element,scroll_left) + RMLUI_LUAGETTER(Element,scroll_top) + RMLUI_LUAGETTER(Element,scroll_width) + RMLUI_LUAGETTER(Element,style) + RMLUI_LUAGETTER(Element,tag_name) + { nullptr, nullptr }, +}; + +luaL_Reg ElementSetters[] = +{ + RMLUI_LUASETTER(Element,class_name) + RMLUI_LUASETTER(Element,id) + RMLUI_LUASETTER(Element,inner_rml) + RMLUI_LUASETTER(Element,scroll_left) + RMLUI_LUASETTER(Element,scroll_top) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Element) + + +template<> void ExtraInit(lua_State* /*L*/, int /*metatable_index*/) +{ + return; +} + +RegType ElementPtrMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementPtrGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementPtrSetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ElementPtr) + + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Element.h b/thirdparty/RmlUi/Source/Lua/Element.h new file mode 100644 index 000000000..711b0e4f9 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Element.h @@ -0,0 +1,116 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENT_H +#define RMLUI_LUA_ELEMENT_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +template<> RMLUILUA_API void ExtraInit(lua_State* L, int metatable_index); + +int Elementnew(lua_State* L); +//methods +int ElementAddEventListener(lua_State* L, Element* obj); +int ElementAppendChild(lua_State* L, Element* obj); +int ElementBlur(lua_State* L, Element* obj); +int ElementClick(lua_State* L, Element* obj); +int ElementDispatchEvent(lua_State* L, Element* obj); +int ElementFocus(lua_State* L, Element* obj); +int ElementGetAttribute(lua_State* L, Element* obj); +int ElementGetElementById(lua_State* L, Element* obj); +int ElementGetElementsByTagName(lua_State* L, Element* obj); +int ElementHasAttribute(lua_State* L, Element* obj); +int ElementHasChildNodes(lua_State* L, Element* obj); +int ElementInsertBefore(lua_State* L, Element* obj); +int ElementIsClassSet(lua_State* L, Element* obj); +int ElementRemoveAttribute(lua_State* L, Element* obj); +int ElementRemoveChild(lua_State* L, Element* obj); +int ElementReplaceChild(lua_State* L, Element* obj); +int ElementScrollIntoView(lua_State* L, Element* obj); +int ElementSetAttribute(lua_State* L, Element* obj); +int ElementSetClass(lua_State* L, Element* obj); + +//getters +int ElementGetAttrattributes(lua_State* L); +int ElementGetAttrchild_nodes(lua_State* L); +int ElementGetAttrclass_name(lua_State* L); +int ElementGetAttrclient_left(lua_State* L); +int ElementGetAttrclient_height(lua_State* L); +int ElementGetAttrclient_top(lua_State* L); +int ElementGetAttrclient_width(lua_State* L); +int ElementGetAttrfirst_child(lua_State* L); +int ElementGetAttrid(lua_State* L); +int ElementGetAttrinner_rml(lua_State* L); +int ElementGetAttrlast_child(lua_State* L); +int ElementGetAttrnext_sibling(lua_State* L); +int ElementGetAttroffset_height(lua_State* L); +int ElementGetAttroffset_left(lua_State* L); +int ElementGetAttroffset_parent(lua_State* L); +int ElementGetAttroffset_top(lua_State* L); +int ElementGetAttroffset_width(lua_State* L); +int ElementGetAttrowner_document(lua_State* L); +int ElementGetAttrparent_node(lua_State* L); +int ElementGetAttrprevious_sibling(lua_State* L); +int ElementGetAttrscroll_height(lua_State* L); +int ElementGetAttrscroll_left(lua_State* L); +int ElementGetAttrscroll_top(lua_State* L); +int ElementGetAttrscroll_width(lua_State* L); +int ElementGetAttrstyle(lua_State* L); +int ElementGetAttrtag_name(lua_State* L); + +//setters +int ElementSetAttrclass_name(lua_State* L); +int ElementSetAttrid(lua_State* L); +int ElementSetAttrinner_rml(lua_State* L); +int ElementSetAttrscroll_left(lua_State* L); +int ElementSetAttrscroll_top(lua_State* L); + + +extern RegType ElementMethods[]; +extern luaL_Reg ElementGetters[]; +extern luaL_Reg ElementSetters[]; + +RMLUI_LUATYPE_DECLARE(Element) + + +template<> void ExtraInit(lua_State* L, int metatable_index); +int LogMessage(lua_State* L); + +extern RegType ElementPtrMethods[]; +extern luaL_Reg ElementPtrGetters[]; +extern luaL_Reg ElementPtrSetters[]; + +RMLUI_LUATYPE_DECLARE(ElementPtr) + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/ElementAttributesProxy.cpp b/thirdparty/RmlUi/Source/Lua/ElementAttributesProxy.cpp new file mode 100644 index 000000000..c2da5a0e3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementAttributesProxy.cpp @@ -0,0 +1,114 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementAttributesProxy.h" +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,ElementAttributesProxy__index); + lua_setfield(L,metatable_index,"__index"); + lua_pushcfunction(L,ElementAttributesProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + lua_pushcfunction(L,ElementAttributesProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +int ElementAttributesProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int keytype = lua_type(L,2); + if(keytype == LUA_TSTRING) //only valid key types + { + ElementAttributesProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + const char* key = lua_tostring(L,2); + Variant* attr = obj->owner->GetAttribute(key); + PushVariant(L,attr); //Utilities.h + return 1; + } + else + return LuaType::index(L); +} + +//[1] is the object, [2] is the key that was used previously, [3] is the userdata +int ElementAttributesProxy__pairs(lua_State* L) +{ + ElementAttributesProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int& pindex = *(int*)lua_touserdata(L,3); + if ((pindex) == -1) + pindex = 0; + const ElementAttributes& attributes = obj->owner->GetAttributes(); + + if(pindex >= 0 && pindex < (int)attributes.size()) + { + auto it = attributes.begin(); + for (int i = 0; i < pindex; ++i) + ++it; + const String& key = it->first; + const Variant* value = &it->second; + lua_pushstring(L,key.c_str()); + PushVariant(L,value); + } + else + { + lua_pushnil(L); + lua_pushnil(L); + } + return 2; +} + +//Doesn't index by integer, so don't return anything +int ElementAttributesProxy__ipairs(lua_State* L) +{ + lua_pushnil(L); + lua_pushnil(L); + return 2; +} + +RegType ElementAttributesProxyMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementAttributesProxyGetters[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg ElementAttributesProxySetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ElementAttributesProxy) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/ElementAttributesProxy.h b/thirdparty/RmlUi/Source/Lua/ElementAttributesProxy.h new file mode 100644 index 000000000..dd577695b --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementAttributesProxy.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTATTRIBUTESPROXY_H +#define RMLUI_LUA_ELEMENTATTRIBUTESPROXY_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +//where owner is the Element that we should look up information from +struct ElementAttributesProxy { Element* owner; }; + +template<> void ExtraInit(lua_State* L, int metatable_index); +int ElementAttributesProxy__index(lua_State* L); +int ElementAttributesProxy__pairs(lua_State* L); +int ElementAttributesProxy__ipairs(lua_State* L); + +extern RegType ElementAttributesProxyMethods[]; +extern luaL_Reg ElementAttributesProxyGetters[]; +extern luaL_Reg ElementAttributesProxySetters[]; + +RMLUI_LUATYPE_DECLARE(ElementAttributesProxy) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/ElementChildNodesProxy.cpp b/thirdparty/RmlUi/Source/Lua/ElementChildNodesProxy.cpp new file mode 100644 index 000000000..9d20a396e --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementChildNodesProxy.cpp @@ -0,0 +1,107 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementChildNodesProxy.h" +#include "Element.h" + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,ElementChildNodesProxy__index); + lua_setfield(L,metatable_index,"__index"); + lua_pushcfunction(L,ElementChildNodesProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + lua_pushcfunction(L,ElementChildNodesProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +int ElementChildNodesProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int keytype = lua_type(L,2); + if(keytype == LUA_TNUMBER) //only valid key types + { + ElementChildNodesProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int key = (int)luaL_checkinteger(L,2); + Element* child = obj->owner->GetChild(key); + LuaType::push(L,child,false); + return 1; + } + else + return LuaType::index(L); +} + +int ElementChildNodesProxy__pairs(lua_State* L) +{ + //because it is only indexed by integer, just go through ipairs + return ElementChildNodesProxy__ipairs(L); +} + + +//[1] is the object, [2] is the key that was just used, [3] is the userdata +int ElementChildNodesProxy__ipairs(lua_State* L) +{ + ElementChildNodesProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int* pindex = (int*)lua_touserdata(L,3); + if((*pindex) == -1) //initial value + (*pindex) = 0; + int num_children = obj->owner->GetNumChildren(); + if((*pindex) < num_children) + { + lua_pushinteger(L,*pindex); //key + LuaType::push(L,obj->owner->GetChild(*pindex)); //value + (*pindex) += 1; + } + else + { + lua_pushnil(L); + lua_pushnil(L); + } + return 2; +} + +RegType ElementChildNodesProxyMethods[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg ElementChildNodesProxyGetters[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg ElementChildNodesProxySetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ElementChildNodesProxy) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/ElementChildNodesProxy.h b/thirdparty/RmlUi/Source/Lua/ElementChildNodesProxy.h new file mode 100644 index 000000000..70dbbadd5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementChildNodesProxy.h @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#ifndef RMLUI_LUA_ELEMENTCHILDNODESPROXY_H +#define RMLUI_LUA_ELEMENTCHILDNODESPROXY_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +//where owner is the Element that we should look up information from +struct ElementChildNodesProxy { Element* owner; }; + +template<> void ExtraInit(lua_State* L, int metatable_index); +int ElementChildNodesProxy__index(lua_State* L); +int ElementChildNodesProxy__pairs(lua_State* L); +int ElementChildNodesProxy__ipairs(lua_State* L); + +extern RegType ElementChildNodesProxyMethods[]; +extern luaL_Reg ElementChildNodesProxyGetters[]; +extern luaL_Reg ElementChildNodesProxySetters[]; + +RMLUI_LUATYPE_DECLARE(ElementChildNodesProxy) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/ElementInstancer.cpp b/thirdparty/RmlUi/Source/Lua/ElementInstancer.cpp new file mode 100644 index 000000000..642395d9f --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementInstancer.cpp @@ -0,0 +1,85 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "ElementInstancer.h" + + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,ElementInstancernew); + lua_setfield(L,metatable_index-1,"new"); +} + +//method +int ElementInstancernew(lua_State* L) +{ + LuaElementInstancer* lei = new LuaElementInstancer(L); + LuaType::push(L,lei,true); + return 1; +} + +//setter +int ElementInstancerSetAttrInstanceElement(lua_State* L) +{ + LuaElementInstancer* lei = (LuaElementInstancer*)LuaType::check(L,1); + RMLUI_CHECK_OBJ(lei); + + if(lua_type(L,2) != LUA_TFUNCTION) + { + Log::Message(Log::LT_ERROR, "The argument to ElementInstancer.InstanceElement must be a function. You passed in a %s.", luaL_typename(L,2)); + return 0; + } + lei->PushFunctionsTable(L); //top of the stack is now ELEMENTINSTANCERFUNCTIONS table + lua_pushvalue(L,2); //copy of the function + lei->ref_InstanceElement = luaL_ref(L,-2); + lua_pop(L,1); //pop the ELEMENTINSTANCERFUNCTIONS table + return 0; +} + +RegType ElementInstancerMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementInstancerGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementInstancerSetters[] = +{ + RMLUI_LUASETTER(ElementInstancer,InstanceElement) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ElementInstancer) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/ElementInstancer.h b/thirdparty/RmlUi/Source/Lua/ElementInstancer.h new file mode 100644 index 000000000..11fe77eda --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementInstancer.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTINSTANCER_H +#define RMLUI_LUA_ELEMENTINSTANCER_H + +#include +#include +#include "LuaElementInstancer.h" + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); +//method +int ElementInstancernew(lua_State* L); +//setter +int ElementInstancerSetAttrInstanceElement(lua_State* L); + +extern RegType ElementInstancerMethods[]; +extern luaL_Reg ElementInstancerGetters[]; +extern luaL_Reg ElementInstancerSetters[]; + +RMLUI_LUATYPE_DECLARE(ElementInstancer) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/ElementStyleProxy.cpp b/thirdparty/RmlUi/Source/Lua/ElementStyleProxy.cpp new file mode 100644 index 000000000..9f53d93cf --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementStyleProxy.cpp @@ -0,0 +1,163 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementStyleProxy.h" +#include +#include +#include +#include +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,ElementStyleProxy__index); + lua_setfield(L,metatable_index,"__index"); + + lua_pushcfunction(L,ElementStyleProxy__newindex); + lua_setfield(L,metatable_index,"__newindex"); + + lua_pushcfunction(L,ElementStyleProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + + lua_pushcfunction(L,ElementStyleProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +int ElementStyleProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int keytype = lua_type(L,2); + if(keytype == LUA_TSTRING) //if we are trying to access a string, then we will assume that it is a property + { + ElementStyleProxy* es = LuaType::check(L,1); + RMLUI_CHECK_OBJ(es); + const Property* prop = es->owner->GetProperty(lua_tostring(L,2)); + RMLUI_CHECK_OBJ(prop) + lua_pushstring(L,prop->ToString().c_str()); + return 1; + } + else //if it wasn't trying to get a string + { + lua_settop(L,2); + return LuaType::index(L); + } +} + +int ElementStyleProxy__newindex(lua_State* L) +{ + //[1] = obj, [2] = key, [3] = value + ElementStyleProxy* es = LuaType::check(L,1); + RMLUI_CHECK_OBJ(es); + int keytype = lua_type(L,2); + int valuetype = lua_type(L,3); + if(keytype == LUA_TSTRING ) + { + const char* key = lua_tostring(L,2); + if(valuetype == LUA_TSTRING) + { + const char* value = lua_tostring(L,3); + lua_pushboolean(L,es->owner->SetProperty(key,value)); + return 1; + } + else if (valuetype == LUA_TNIL) + { + es->owner->RemoveProperty(key); + return 0; + } + } + //everything else returns when it needs to, so we are safe to pass it + //on if needed + + lua_settop(L,3); + return LuaType::newindex(L); + +} + +//[1] is the object, [2] is the last used key, [3] is the userdata +int ElementStyleProxy__pairs(lua_State* L) +{ + ElementStyleProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int* pindex = (int*)lua_touserdata(L,3); + if ((*pindex) == -1) + *pindex = 0; + + int i = 0; + auto it = obj->owner->IterateLocalProperties(); + while (i < (*pindex) && !it.AtEnd()) + { + ++it; + ++i; + } + + if(!it.AtEnd()) + { + const String& key = it.GetName(); + const Property& property = it.GetProperty(); + String val; + property.definition->GetValue(val, property); + lua_pushstring(L,key.c_str()); + lua_pushstring(L,val.c_str()); + } + else + { + lua_pushnil(L); + lua_pushnil(L); + } + return 2; +} + +//only indexed by string +int ElementStyleProxy__ipairs(lua_State* L) +{ + lua_pushnil(L); + lua_pushnil(L); + return 2; +} + +RegType ElementStyleProxyMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementStyleProxyGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementStyleProxySetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ElementStyleProxy) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/ElementStyleProxy.h b/thirdparty/RmlUi/Source/Lua/ElementStyleProxy.h new file mode 100644 index 000000000..66e585b94 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementStyleProxy.h @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTSTYLEPROXY_H +#define RMLUI_LUA_ELEMENTSTYLEPROXY_H + +#include +#include + +namespace Rml { +class Element; + +namespace Lua { +struct ElementStyleProxy { Element* owner; }; + +template<> void ExtraInit(lua_State* L, int metatable_index); +int ElementStyleProxy__index(lua_State* L); +int ElementStyleProxy__newindex(lua_State* L); +int ElementStyleProxy__pairs(lua_State* L); +int ElementStyleProxy__ipairs(lua_State* L); + +extern RegType ElementStyleProxyMethods[]; +extern luaL_Reg ElementStyleProxyGetters[]; +extern luaL_Reg ElementStyleProxySetters[]; + +RMLUI_LUATYPE_DECLARE(ElementStyleProxy) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/ElementText.cpp b/thirdparty/RmlUi/Source/Lua/ElementText.cpp new file mode 100644 index 000000000..ba9a8b30c --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementText.cpp @@ -0,0 +1,79 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementText.h" +#include "Element.h" +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + //inherit from Element + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} + +int ElementTextGetAttrtext(lua_State* L) +{ + ElementText* obj = LuaType::check(L, 1); + RMLUI_CHECK_OBJ(obj); + lua_pushstring(L, obj->GetText().c_str()); + return 1; +} + +int ElementTextSetAttrtext(lua_State* L) +{ + ElementText* obj = LuaType::check(L, 1); + RMLUI_CHECK_OBJ(obj); + const char* text = luaL_checkstring(L,2); + obj->SetText(text); + return 0; +} + +RegType ElementTextMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementTextGetters[] = +{ + RMLUI_LUAGETTER(ElementText,text) + { nullptr, nullptr }, +}; + +luaL_Reg ElementTextSetters[] = +{ + RMLUI_LUASETTER(ElementText,text) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(ElementText) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/ElementText.h b/thirdparty/RmlUi/Source/Lua/ElementText.h new file mode 100644 index 000000000..d3c656834 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/ElementText.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTTEXT_H +#define RMLUI_LUA_ELEMENTTEXT_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +//will inherit from Element +template<> void ExtraInit(lua_State* L, int metatable_index); + +int ElementTextGetAttrtext(lua_State* L); +int ElementTextSetAttrtext(lua_State* L); + +extern RegType ElementTextMethods[]; +extern luaL_Reg ElementTextGetters[]; +extern luaL_Reg ElementTextSetters[]; + +RMLUI_LUATYPE_DECLARE(ElementText) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/As.h b/thirdparty/RmlUi/Source/Lua/Elements/As.h new file mode 100644 index 000000000..22a9efc8f --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/As.h @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_AS_H +#define RMLUI_LUA_ELEMENTS_AS_H +/* + These are helper functions to fill up the Element.As table with types that are able to be casted +*/ + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//Helper function for the controls, so that the types don't have to define individual functions themselves +// to fill the Elements.As table +template +int CastFromElementTo(lua_State* L) +{ + Element* ele = LuaType::check(L,1); + RMLUI_CHECK_OBJ(ele); + LuaType::push(L,(ToType*)ele,false); + return 1; +} + +//Adds to the Element.As table the name of the type, and the function to use to cast +template +void AddCastFunctionToElementAsTable(lua_State* L) +{ + int top = lua_gettop(L); + lua_getglobal(L,"Element"); + lua_getfield(L,-1,"As"); + if(!lua_isnoneornil(L,-1)) + { + lua_pushcfunction(L,CastFromElementTo); + lua_setfield(L,-2,GetTClassName()); + } + lua_settop(L,top); //pop "As" and "Element" +} + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/DataFormatter.cpp b/thirdparty/RmlUi/Source/Lua/Elements/DataFormatter.cpp new file mode 100644 index 000000000..4dee61b37 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/DataFormatter.cpp @@ -0,0 +1,112 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DataFormatter.h" +#include + + +namespace Rml { +namespace Lua { +//method +int DataFormatternew(lua_State* L) +{ + DataFormatter* df = nullptr; + int ref = LUA_NOREF; + int top = lua_gettop(L); + if(top == 0) + df = new DataFormatter(); + else if (top > 0) //at least one element means at least a name + { + if(top > 1) //if a function as well + { + if(lua_type(L,2) != LUA_TFUNCTION) + { + Log::Message(Log::LT_ERROR, "Lua: In DataFormatter.new, the second argument MUST be a function (or not exist). You passed in a %s.", lua_typename(L,lua_type(L,2))); + } + else //if it is a function + { + LuaDataFormatter::PushDataFormatterFunctionTable(L); + lua_pushvalue(L,2); //re-push the function so it is on the top of the stack + ref = luaL_ref(L,-2); + lua_pop(L,1); //pop the function table + } + } + df = new DataFormatter(luaL_checkstring(L,1)); + df->ref_FormatData = ref; //will either be valid or LUA_NOREF + } + LuaType::push(L,df,true); + return 1; +} + +//setter +int DataFormatterSetAttrFormatData(lua_State* L) +{ + DataFormatter* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int ref = LUA_NOREF; + if(lua_type(L,2) != LUA_TFUNCTION) + { + Log::Message(Log::LT_ERROR, "Lua: Setting DataFormatter.FormatData, the value must be a function. You passed in a %s.", lua_typename(L,lua_type(L,2))); + } + else //if it is a function + { + LuaDataFormatter::PushDataFormatterFunctionTable(L); + lua_pushvalue(L,2); //re-push the function so it is on the top of the stack + ref = luaL_ref(L,-2); + lua_pop(L,1); //pop the function table + } + obj->ref_FormatData = ref; + return 0; +} + +RegType DataFormatterMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg DataFormatterGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg DataFormatterSetters[] = +{ + RMLUI_LUASETTER(DataFormatter,FormatData) + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,DataFormatternew); + lua_setfield(L,metatable_index-1,"new"); + return; +} +RMLUI_LUATYPE_DEFINE(DataFormatter) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/DataFormatter.h b/thirdparty/RmlUi/Source/Lua/Elements/DataFormatter.h new file mode 100644 index 000000000..debcb72d2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/DataFormatter.h @@ -0,0 +1,56 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_DATAFORMATTER_H +#define RMLUI_LUA_ELEMENTS_DATAFORMATTER_H + + +#include +#include +#include "LuaDataFormatter.h" + +namespace Rml { +namespace Lua { +typedef LuaDataFormatter DataFormatter; +//method +int DataFormatternew(lua_State* L); + +//setter +int DataFormatterSetAttrFormatData(lua_State* L); + +extern RegType DataFormatterMethods[]; +extern luaL_Reg DataFormatterGetters[]; +extern luaL_Reg DataFormatterSetters[]; + + +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(DataFormatter) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/DataSource.cpp b/thirdparty/RmlUi/Source/Lua/Elements/DataSource.cpp new file mode 100644 index 000000000..9bd9d551a --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/DataSource.cpp @@ -0,0 +1,139 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "DataSource.h" +#include + +namespace Rml { +namespace Lua { +typedef LuaDataSource DataSource; + +int DataSourcenew(lua_State* L) +{ + const char* name = luaL_checkstring(L,1); + LuaDataSource* ds = new LuaDataSource(name); + LuaType::push(L,ds,true); + return 1; +} + +int DataSourceNotifyRowAdd(lua_State* L, DataSource* obj) +{ + RMLUI_CHECK_OBJ(obj); + const char* table_name = luaL_checkstring(L,1); + int first_row_added = (int)luaL_checkinteger(L,2); + int num_rows_added = (int)luaL_checkinteger(L,3); + obj->NotifyRowAdd(table_name,first_row_added,num_rows_added); + return 0; +} + +int DataSourceNotifyRowRemove(lua_State* L, DataSource* obj) +{ + RMLUI_CHECK_OBJ(obj); + const char* table_name = luaL_checkstring(L,1); + int first_row_removed = (int)luaL_checkinteger(L,2); + int num_rows_removed = (int)luaL_checkinteger(L,3); + obj->NotifyRowRemove(table_name,first_row_removed,num_rows_removed); + return 0; +} + +int DataSourceNotifyRowChange(lua_State* L, DataSource* obj) +{ + RMLUI_CHECK_OBJ(obj); + const char* table_name = luaL_checkstring(L,1); + if(lua_gettop(L) < 2) + { + obj->NotifyRowChange(table_name); + } + else + { + int first_row_changed = (int)luaL_checkinteger(L,2); + int num_rows_changed = (int)luaL_checkinteger(L,3); + obj->NotifyRowChange(table_name,first_row_changed,num_rows_changed); + } + return 0; +} + +int DataSourceSetAttrGetNumRows(lua_State* L) +{ + DataSource* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + if(lua_type(L,2) == LUA_TFUNCTION) + { + lua_pushvalue(L,2); //copy of the function, so it is for sure at the top of the stack + obj->getNumRowsRef = luaL_ref(L, LUA_REGISTRYINDEX); + } + else + Log::Message(Log::LT_WARNING, "Lua: Must assign DataSource.GetNumRows as a function, value received was of %s type", lua_typename(L,2)); + return 0; +} + +int DataSourceSetAttrGetRow(lua_State* L) +{ + DataSource* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + if(lua_type(L,2) == LUA_TFUNCTION) + { + lua_pushvalue(L,2); //copy of the functions, so it is for sure at the top of the stack + obj->getRowRef = luaL_ref(L, LUA_REGISTRYINDEX); + } + else + Log::Message(Log::LT_WARNING, "Lua: Must assign DataSource.GetRow as a function, value received was of %s type", lua_typename(L,2)); + return 0; +} + + +RegType DataSourceMethods[] = +{ + RMLUI_LUAMETHOD(DataSource,NotifyRowAdd) + RMLUI_LUAMETHOD(DataSource,NotifyRowRemove) + RMLUI_LUAMETHOD(DataSource,NotifyRowChange) + { nullptr, nullptr }, +}; + +luaL_Reg DataSourceGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg DataSourceSetters[] = +{ + RMLUI_LUASETTER(DataSource,GetNumRows) + RMLUI_LUASETTER(DataSource,GetRow) + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,DataSourcenew); + lua_setfield(L,metatable_index-1,"new"); + return; +} +RMLUI_LUATYPE_DEFINE(DataSource) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/DataSource.h b/thirdparty/RmlUi/Source/Lua/Elements/DataSource.h new file mode 100644 index 000000000..a4caf97e5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/DataSource.h @@ -0,0 +1,59 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_DATASOURCE_H +#define RMLUI_LUA_ELEMENTS_DATASOURCE_H + +#include +#include +#include "LuaDataSource.h" + +namespace Rml { +namespace Lua { +typedef LuaDataSource DataSource; + +int DataSourcenew(lua_State* L); + +int DataSourceNotifyRowAdd(lua_State* L, DataSource* obj); +int DataSourceNotifyRowRemove(lua_State* L, DataSource* obj); +int DataSourceNotifyRowChange(lua_State* L, DataSource* obj); + +int DataSourceSetAttrGetNumRows(lua_State* L); +int DataSourceSetAttrGetRow(lua_State* L); + +extern RegType DataSourceMethods[]; +extern luaL_Reg DataSourceGetters[]; +extern luaL_Reg DataSourceSetters[]; + + +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(DataSource) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGrid.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGrid.cpp new file mode 100644 index 000000000..62a773a08 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGrid.cpp @@ -0,0 +1,109 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementDataGrid.h" +#include +#include +#include + + +namespace Rml { +namespace Lua { + + +//methods +int ElementDataGridAddColumn(lua_State* L, ElementDataGrid* obj) +{ + RMLUI_CHECK_OBJ(obj); + const char* fields = luaL_checkstring(L,1); + const char* formatter = luaL_checkstring(L,2); + float width = (float)luaL_checknumber(L,3); + const char* rml = luaL_checkstring(L,4); + + obj->AddColumn(fields,formatter,width,rml); + return 0; +} + +int ElementDataGridSetDataSource(lua_State* L, ElementDataGrid* obj) +{ + RMLUI_CHECK_OBJ(obj); + const char* source = luaL_checkstring(L,1); + + obj->SetDataSource(source); + return 0; +} + + +//getter +int ElementDataGridGetAttrrows(lua_State* L) +{ + ElementDataGrid* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + + lua_newtable(L); + int tbl = lua_gettop(L); + int numrows = obj->GetNumRows(); + ElementDataGridRow* row; + for(int i = 0; i < numrows; i++) + { + row = obj->GetRow(i); + LuaType::push(L,row,false); + lua_rawseti(L,tbl,i); + } + return 1; +} + + +RegType ElementDataGridMethods[] = +{ + RMLUI_LUAMETHOD(ElementDataGrid,AddColumn) + RMLUI_LUAMETHOD(ElementDataGrid,SetDataSource) + { nullptr, nullptr }, +}; + +luaL_Reg ElementDataGridGetters[] = +{ + RMLUI_LUAGETTER(ElementDataGrid,rows) + { nullptr, nullptr }, +}; + +luaL_Reg ElementDataGridSetters[] = +{ + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} +RMLUI_LUATYPE_DEFINE(ElementDataGrid) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGrid.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGrid.h new file mode 100644 index 000000000..e08d0342c --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGrid.h @@ -0,0 +1,59 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTDATAGRID_H +#define RMLUI_LUA_ELEMENTS_ELEMENTDATAGRID_H + + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//methods +int ElementDataGridAddColumn(lua_State* L, ElementDataGrid* obj); +int ElementDataGridSetDataSource(lua_State* L, ElementDataGrid* obj); + +//getter +int ElementDataGridGetAttrrows(lua_State* L); + + +extern RegType ElementDataGridMethods[]; +extern luaL_Reg ElementDataGridGetters[]; +extern luaL_Reg ElementDataGridSetters[]; + + +//this will be used to "inherit" from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementDataGrid) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGridRow.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGridRow.cpp new file mode 100644 index 000000000..49dfffe71 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGridRow.cpp @@ -0,0 +1,124 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementDataGridRow.h" +#include +#include + + +namespace Rml { +namespace Lua { + + +//getters +int ElementDataGridRowGetAttrrow_expanded(lua_State* L) +{ + ElementDataGridRow* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushboolean(L,obj->IsRowExpanded()); + return 1; +} + +int ElementDataGridRowGetAttrparent_relative_index(lua_State* L) +{ + ElementDataGridRow* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetParentRelativeIndex()); + return 1; +} + +int ElementDataGridRowGetAttrtable_relative_index(lua_State* L) +{ + ElementDataGridRow* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetTableRelativeIndex()); + return 1; +} + +int ElementDataGridRowGetAttrparent_row(lua_State* L) +{ + ElementDataGridRow* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + LuaType::push(L,obj->GetParentRow(),false); + return 1; +} + +int ElementDataGridRowGetAttrparent_grid(lua_State* L) +{ + ElementDataGridRow* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + LuaType::push(L,obj->GetParentGrid(),false); + return 1; +} + + +//setter +int ElementDataGridRowSetAttrrow_expanded(lua_State* L) +{ + ElementDataGridRow* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + bool expanded = RMLUI_CHECK_BOOL(L,2); + if(expanded) + obj->ExpandRow(); + else + obj->CollapseRow(); + return 0; +} + + +RegType ElementDataGridRowMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementDataGridRowGetters[] = +{ + RMLUI_LUAGETTER(ElementDataGridRow,row_expanded) + RMLUI_LUAGETTER(ElementDataGridRow,parent_relative_index) + RMLUI_LUAGETTER(ElementDataGridRow,table_relative_index) + RMLUI_LUAGETTER(ElementDataGridRow,parent_row) + RMLUI_LUAGETTER(ElementDataGridRow,parent_grid) + { nullptr, nullptr }, +}; + +luaL_Reg ElementDataGridRowSetters[] = +{ + RMLUI_LUASETTER(ElementDataGridRow,row_expanded) + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} +RMLUI_LUATYPE_DEFINE(ElementDataGridRow) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGridRow.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGridRow.h new file mode 100644 index 000000000..f91ec1471 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementDataGridRow.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTDATAGRIDROW_H +#define RMLUI_LUA_ELEMENTS_ELEMENTDATAGRIDROW_H + + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//getters +int ElementDataGridRowGetAttrrow_expanded(lua_State* L); +int ElementDataGridRowGetAttrparent_relative_index(lua_State* L); +int ElementDataGridRowGetAttrtable_relative_index(lua_State* L); +int ElementDataGridRowGetAttrparent_row(lua_State* L); +int ElementDataGridRowGetAttrparent_grid(lua_State* L); + +//setter +int ElementDataGridRowSetAttrrow_expanded(lua_State* L); + + +extern RegType ElementDataGridRowMethods[]; +extern luaL_Reg ElementDataGridRowGetters[]; +extern luaL_Reg ElementDataGridRowSetters[]; + + +//this will be used to "inherit" from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementDataGridRow) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementForm.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementForm.cpp new file mode 100644 index 000000000..7ce5da23d --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementForm.cpp @@ -0,0 +1,79 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementForm.h" +#include +#include +#include + +namespace Rml { +namespace Lua { + +//method +int ElementFormSubmit(lua_State* L, ElementForm* obj) +{ + int top = lua_gettop(L); + const char* name = ""; + const char* value = ""; + if(top > 0) + { + name = luaL_checkstring(L,1); + if(top > 1) + value = luaL_checkstring(L,2); + } + obj->Submit(name,value); + return 0; +} + +RegType ElementFormMethods[] = +{ + RMLUI_LUAMETHOD(ElementForm,Submit) + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormSetters[] = +{ + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + //inherit from Element + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} +RMLUI_LUATYPE_DEFINE(ElementForm) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementForm.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementForm.h new file mode 100644 index 000000000..d35480631 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementForm.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTFORM_H +#define RMLUI_LUA_ELEMENTS_ELEMENTFORM_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//method +int ElementFormSubmit(lua_State* L, ElementForm* obj); + +extern RegType ElementFormMethods[]; +extern luaL_Reg ElementFormGetters[]; +extern luaL_Reg ElementFormSetters[]; + + +//this will be used to "inherit" from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementForm) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControl.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControl.cpp new file mode 100644 index 000000000..f0bae1375 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControl.cpp @@ -0,0 +1,123 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "../Element.h" +#include "ElementFormControl.h" +#include +#include +#include + + +namespace Rml { +namespace Lua { + +//getters +int ElementFormControlGetAttrdisabled(lua_State* L) +{ + ElementFormControl* efc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(efc); + lua_pushboolean(L,efc->IsDisabled()); + return 1; +} + +int ElementFormControlGetAttrname(lua_State* L) +{ + ElementFormControl* efc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(efc); + lua_pushstring(L,efc->GetName().c_str()); + return 1; +} + +int ElementFormControlGetAttrvalue(lua_State* L) +{ + ElementFormControl* efc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(efc); + lua_pushstring(L,efc->GetValue().c_str()); + return 1; +} + + +//setters +int ElementFormControlSetAttrdisabled(lua_State* L) +{ + ElementFormControl* efc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(efc); + efc->SetDisabled(RMLUI_CHECK_BOOL(L,2)); + return 0; +} + +int ElementFormControlSetAttrname(lua_State* L) +{ + ElementFormControl* efc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(efc); + const char* name = luaL_checkstring(L,2); + efc->SetName(name); + return 0; +} + +int ElementFormControlSetAttrvalue(lua_State* L) +{ + ElementFormControl* efc = LuaType::check(L,1); + RMLUI_CHECK_OBJ(efc); + const char* value = luaL_checkstring(L,2); + efc->SetValue(value); + return 0; +} + + +RegType ElementFormControlMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlGetters[] = +{ + RMLUI_LUAGETTER(ElementFormControl,disabled) + RMLUI_LUAGETTER(ElementFormControl,name) + RMLUI_LUAGETTER(ElementFormControl,value) + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlSetters[] = +{ + RMLUI_LUASETTER(ElementFormControl,disabled) + RMLUI_LUASETTER(ElementFormControl,name) + RMLUI_LUASETTER(ElementFormControl,value) + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} +RMLUI_LUATYPE_DEFINE(ElementFormControl) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControl.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControl.h new file mode 100644 index 000000000..06d7a9b18 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControl.h @@ -0,0 +1,59 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROL_H +#define RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROL_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//getters +int ElementFormControlGetAttrdisabled(lua_State* L); +int ElementFormControlGetAttrname(lua_State* L); +int ElementFormControlGetAttrvalue(lua_State* L); + +//setters +int ElementFormControlSetAttrdisabled(lua_State* L); +int ElementFormControlSetAttrname(lua_State* L); +int ElementFormControlSetAttrvalue(lua_State* L); + +extern RegType ElementFormControlMethods[]; +extern luaL_Reg ElementFormControlGetters[]; +extern luaL_Reg ElementFormControlSetters[]; + + +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementFormControl) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlDataSelect.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlDataSelect.cpp new file mode 100644 index 000000000..8d7cd6926 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlDataSelect.cpp @@ -0,0 +1,74 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementFormControlDataSelect.h" +#include +#include "ElementFormControlSelect.h" +#include + +namespace Rml { +namespace Lua { + +//method +int ElementFormControlDataSelectSetDataSource(lua_State* L, ElementFormControlDataSelect* obj) +{ + const char* source = luaL_checkstring(L,1); + obj->SetDataSource(source); + return 0; +} + +RegType ElementFormControlDataSelectMethods[] = +{ + RMLUI_LUAMETHOD(ElementFormControlDataSelect,SetDataSource) + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlDataSelectGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlDataSelectSetters[] = +{ + { nullptr, nullptr }, +}; + + +//inherits from ElementFormControl which inherits from Element +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + //do whatever ElementFormControlSelect did as far as inheritance + ExtraInit(L,metatable_index); + //then inherit from ElementFromControlSelect + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} + +RMLUI_LUATYPE_DEFINE(ElementFormControlDataSelect) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlDataSelect.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlDataSelect.h new file mode 100644 index 000000000..1d1efefc7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlDataSelect.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLDATASELECT_H +#define RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLDATASELECT_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//method +int ElementFormControlDataSelectSetDataSource(lua_State* L, ElementFormControlDataSelect* obj); + +extern RegType ElementFormControlDataSelectMethods[]; +extern luaL_Reg ElementFormControlDataSelectGetters[]; +extern luaL_Reg ElementFormControlDataSelectSetters[]; + + +//inherits from ElementFormControl which inherits from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementFormControlDataSelect) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlInput.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlInput.cpp new file mode 100644 index 000000000..7c40cc3c7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlInput.cpp @@ -0,0 +1,183 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementFormControlInput.h" +#include +#include "ElementFormControl.h" +#include + +namespace Rml { +namespace Lua { + + +//getters +int ElementFormControlInputGetAttrchecked(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushboolean(L,obj->HasAttribute("checked")); + return 1; +} + +int ElementFormControlInputGetAttrmaxlength(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetAttribute("maxlength",-1)); + return 1; +} + +int ElementFormControlInputGetAttrsize(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetAttribute("size",20)); + return 1; +} + +int ElementFormControlInputGetAttrmax(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetAttribute("max",100)); + return 1; +} + +int ElementFormControlInputGetAttrmin(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetAttribute("min",0)); + return 1; +} + +int ElementFormControlInputGetAttrstep(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetAttribute("step",1)); + return 1; +} + + +//setters +int ElementFormControlInputSetAttrchecked(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + bool checked = RMLUI_CHECK_BOOL(L,2); + if(checked) + obj->SetAttribute("checked",true); + else + obj->RemoveAttribute("checked"); + return 0; +} + +int ElementFormControlInputSetAttrmaxlength(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int maxlength = (int)luaL_checkinteger(L,2); + obj->SetAttribute("maxlength",maxlength); + return 0; +} + +int ElementFormControlInputSetAttrsize(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int size = (int)luaL_checkinteger(L,2); + obj->SetAttribute("size",size); + return 0; +} + +int ElementFormControlInputSetAttrmax(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int max = (int)luaL_checkinteger(L,2); + obj->SetAttribute("max",max); + return 0; +} + +int ElementFormControlInputSetAttrmin(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int min = (int)luaL_checkinteger(L,2); + obj->SetAttribute("min",min); + return 0; +} + +int ElementFormControlInputSetAttrstep(lua_State* L) +{ + ElementFormControlInput* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int step = (int)luaL_checkinteger(L,2); + obj->SetAttribute("step",step); + return 0; +} + + +RegType ElementFormControlInputMethods[] = +{ + {nullptr,nullptr}, +}; + +luaL_Reg ElementFormControlInputGetters[] = +{ + RMLUI_LUAGETTER(ElementFormControlInput,checked) + RMLUI_LUAGETTER(ElementFormControlInput,maxlength) + RMLUI_LUAGETTER(ElementFormControlInput,size) + RMLUI_LUAGETTER(ElementFormControlInput,max) + RMLUI_LUAGETTER(ElementFormControlInput,min) + RMLUI_LUAGETTER(ElementFormControlInput,step) + {nullptr,nullptr}, +}; + +luaL_Reg ElementFormControlInputSetters[] = +{ + RMLUI_LUASETTER(ElementFormControlInput,checked) + RMLUI_LUASETTER(ElementFormControlInput,maxlength) + RMLUI_LUASETTER(ElementFormControlInput,size) + RMLUI_LUASETTER(ElementFormControlInput,max) + RMLUI_LUASETTER(ElementFormControlInput,min) + RMLUI_LUASETTER(ElementFormControlInput,step) + {nullptr,nullptr}, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} +RMLUI_LUATYPE_DEFINE(ElementFormControlInput) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlInput.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlInput.h new file mode 100644 index 000000000..95699ee20 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlInput.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLINPUT_H +#define RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLINPUT_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//getters +int ElementFormControlInputGetAttrchecked(lua_State* L); +int ElementFormControlInputGetAttrmaxlength(lua_State* L); +int ElementFormControlInputGetAttrsize(lua_State* L); +int ElementFormControlInputGetAttrmax(lua_State* L); +int ElementFormControlInputGetAttrmin(lua_State* L); +int ElementFormControlInputGetAttrstep(lua_State* L); + +//setters +int ElementFormControlInputSetAttrchecked(lua_State* L); +int ElementFormControlInputSetAttrmaxlength(lua_State* L); +int ElementFormControlInputSetAttrsize(lua_State* L); +int ElementFormControlInputSetAttrmax(lua_State* L); +int ElementFormControlInputSetAttrmin(lua_State* L); +int ElementFormControlInputSetAttrstep(lua_State* L); + +extern RegType ElementFormControlInputMethods[]; +extern luaL_Reg ElementFormControlInputGetters[]; +extern luaL_Reg ElementFormControlInputSetters[]; + + +//inherits from ElementFormControl which inherits from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementFormControlInput) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlSelect.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlSelect.cpp new file mode 100644 index 000000000..90a8a0b5a --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlSelect.cpp @@ -0,0 +1,133 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementFormControlSelect.h" +#include "SelectOptionsProxy.h" +#include +#include +#include +#include "ElementFormControl.h" +#include + + +namespace Rml { +namespace Lua { + +//methods +int ElementFormControlSelectAdd(lua_State* L, ElementFormControlSelect* obj) +{ + const char* rml = luaL_checkstring(L,1); + const char* value = luaL_checkstring(L,2); + int before = -1; //default + if(lua_gettop(L) >= 3) + before = (int)luaL_checkinteger(L,3); + + int index = obj->Add(rml,value,before); + lua_pushinteger(L,index); + return 1; +} + +int ElementFormControlSelectRemove(lua_State* L, ElementFormControlSelect* obj) +{ + int index = (int)luaL_checkinteger(L,1); + obj->Remove(index); + return 0; +} + +int ElementFormControlSelectRemoveAll(lua_State* /*L*/, ElementFormControlSelect* obj) +{ + obj->RemoveAll(); + return 0; +} + +//getters +int ElementFormControlSelectGetAttroptions(lua_State* L) +{ + ElementFormControlSelect* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + SelectOptionsProxy* proxy = new SelectOptionsProxy(); + proxy->owner = obj; + LuaType::push(L,proxy,true); + return 1; +} + +int ElementFormControlSelectGetAttrselection(lua_State* L) +{ + ElementFormControlSelect* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int selection = obj->GetSelection(); + lua_pushinteger(L,selection); + return 1; +} + + +//setter +int ElementFormControlSelectSetAttrselection(lua_State* L) +{ + ElementFormControlSelect* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int selection = (int)luaL_checkinteger(L,2); + obj->SetSelection(selection); + return 0; +} + + +RegType ElementFormControlSelectMethods[] = +{ + RMLUI_LUAMETHOD(ElementFormControlSelect,Add) + RMLUI_LUAMETHOD(ElementFormControlSelect,Remove) + RMLUI_LUAMETHOD(ElementFormControlSelect,RemoveAll) + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlSelectGetters[] = +{ + RMLUI_LUAGETTER(ElementFormControlSelect,options) + RMLUI_LUAGETTER(ElementFormControlSelect,selection) + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlSelectSetters[] = +{ + RMLUI_LUASETTER(ElementFormControlSelect,selection) + { nullptr, nullptr }, +}; + + +//inherits from ElementFormControl which inherits from Element +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + //init whatever elementformcontrol did extra, like inheritance + ExtraInit(L,metatable_index); + //then inherit from elementformcontrol + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} +RMLUI_LUATYPE_DEFINE(ElementFormControlSelect) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlSelect.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlSelect.h new file mode 100644 index 000000000..d4e0c48ad --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlSelect.h @@ -0,0 +1,61 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLSELECT_H +#define RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLSELECT_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//methods +int ElementFormControlSelectAdd(lua_State* L, ElementFormControlSelect* obj); +int ElementFormControlSelectRemove(lua_State* L, ElementFormControlSelect* obj); + +//getters +int ElementFormControlSelectGetAttroptions(lua_State* L); +int ElementFormControlSelectGetAttrselection(lua_State* L); + +//setter +int ElementFormControlSelectSetAttrselection(lua_State* L); + +extern RegType ElementFormControlSelectMethods[]; +extern luaL_Reg ElementFormControlSelectGetters[]; +extern luaL_Reg ElementFormControlSelectSetters[]; + + +//inherits from ElementFormControl which inherits from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementFormControlSelect) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlTextArea.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlTextArea.cpp new file mode 100644 index 000000000..74accbbdb --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlTextArea.cpp @@ -0,0 +1,142 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementFormControlTextArea.h" +#include +#include "ElementFormControl.h" +#include + +namespace Rml { +namespace Lua { + +//getters +int ElementFormControlTextAreaGetAttrcols(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetNumColumns()); + return 1; +} + +int ElementFormControlTextAreaGetAttrmaxlength(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetMaxLength()); + return 1; +} + +int ElementFormControlTextAreaGetAttrrows(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushinteger(L,obj->GetNumRows()); + return 1; +} + +int ElementFormControlTextAreaGetAttrwordwrap(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + lua_pushboolean(L,obj->GetWordWrap()); + return 1; +} + + +//setters +int ElementFormControlTextAreaSetAttrcols(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int cols = (int)luaL_checkinteger(L,2); + obj->SetNumColumns(cols); + return 0; +} + +int ElementFormControlTextAreaSetAttrmaxlength(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int ml = (int)luaL_checkinteger(L,2); + obj->SetMaxLength(ml); + return 0; +} + +int ElementFormControlTextAreaSetAttrrows(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int rows = (int)luaL_checkinteger(L,2); + obj->SetNumRows(rows); + return 0; +} + +int ElementFormControlTextAreaSetAttrwordwrap(lua_State* L) +{ + ElementFormControlTextArea* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + bool ww = RMLUI_CHECK_BOOL(L,2); + obj->SetWordWrap(ww); + return 0; +} + + +RegType ElementFormControlTextAreaMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlTextAreaGetters[] = +{ + RMLUI_LUAGETTER(ElementFormControlTextArea,cols) + RMLUI_LUAGETTER(ElementFormControlTextArea,maxlength) + RMLUI_LUAGETTER(ElementFormControlTextArea,rows) + RMLUI_LUAGETTER(ElementFormControlTextArea,wordwrap) + { nullptr, nullptr }, +}; + +luaL_Reg ElementFormControlTextAreaSetters[] = +{ + RMLUI_LUASETTER(ElementFormControlTextArea,cols) + RMLUI_LUASETTER(ElementFormControlTextArea,maxlength) + RMLUI_LUASETTER(ElementFormControlTextArea,rows) + RMLUI_LUASETTER(ElementFormControlTextArea,wordwrap) + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} + +RMLUI_LUATYPE_DEFINE(ElementFormControlTextArea) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlTextArea.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlTextArea.h new file mode 100644 index 000000000..08e97259c --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementFormControlTextArea.h @@ -0,0 +1,62 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLTEXTAREA_H +#define RMLUI_LUA_ELEMENTS_ELEMENTFORMCONTROLTEXTAREA_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//getters +int ElementFormControlTextAreaGetAttrcols(lua_State* L); +int ElementFormControlTextAreaGetAttrmaxlength(lua_State* L); +int ElementFormControlTextAreaGetAttrrows(lua_State* L); +int ElementFormControlTextAreaGetAttrwordwrap(lua_State* L); + +//setters +int ElementFormControlTextAreaSetAttrcols(lua_State* L); +int ElementFormControlTextAreaSetAttrmaxlength(lua_State* L); +int ElementFormControlTextAreaSetAttrrows(lua_State* L); +int ElementFormControlTextAreaSetAttrwordwrap(lua_State* L); + +extern RegType ElementFormControlTextAreaMethods[]; +extern luaL_Reg ElementFormControlTextAreaGetters[]; +extern luaL_Reg ElementFormControlTextAreaSetters[]; + + +//inherits from ElementFormControl which inherits from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementFormControlTextArea) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementTabSet.cpp b/thirdparty/RmlUi/Source/Lua/Elements/ElementTabSet.cpp new file mode 100644 index 000000000..b4f5a903f --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementTabSet.cpp @@ -0,0 +1,121 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "ElementTabSet.h" +#include +#include + + +namespace Rml { +namespace Lua { + +//methods +int ElementTabSetSetPanel(lua_State* L, ElementTabSet* obj) +{ + RMLUI_CHECK_OBJ(obj); + int index = (int)luaL_checkinteger(L,1); + const char* rml = luaL_checkstring(L,2); + + obj->SetPanel(index,rml); + return 0; +} + +int ElementTabSetSetTab(lua_State* L, ElementTabSet* obj) +{ + RMLUI_CHECK_OBJ(obj); + int index = (int)luaL_checkinteger(L,1); + const char* rml = luaL_checkstring(L,2); + + obj->SetTab(index,rml); + return 0; +} + + +//getters +int ElementTabSetGetAttractive_tab(lua_State* L) +{ + ElementTabSet* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int tab = obj->GetActiveTab(); + lua_pushinteger(L,tab); + return 1; +} + +int ElementTabSetGetAttrnum_tabs(lua_State* L) +{ + ElementTabSet* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int num = obj->GetNumTabs(); + lua_pushinteger(L,num); + return 1; +} + + +//setter +int ElementTabSetSetAttractive_tab(lua_State* L) +{ + ElementTabSet* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int tab = (int)luaL_checkinteger(L,2); + obj->SetActiveTab(tab); + return 0; +} + + +RegType ElementTabSetMethods[] = +{ + RMLUI_LUAMETHOD(ElementTabSet,SetPanel) + RMLUI_LUAMETHOD(ElementTabSet,SetTab) + { nullptr, nullptr }, +}; + +luaL_Reg ElementTabSetGetters[] = +{ + RMLUI_LUAGETTER(ElementTabSet,active_tab) + RMLUI_LUAGETTER(ElementTabSet,num_tabs) + { nullptr, nullptr }, +}; + +luaL_Reg ElementTabSetSetters[] = +{ + RMLUI_LUASETTER(ElementTabSet,active_tab) + { nullptr, nullptr }, +}; + + +//this will be used to "inherit" from Element +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + ExtraInit(L,metatable_index); + LuaType::_regfunctions(L,metatable_index,metatable_index-1); + AddTypeToElementAsTable(L); +} + +RMLUI_LUATYPE_DEFINE(ElementTabSet) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/ElementTabSet.h b/thirdparty/RmlUi/Source/Lua/Elements/ElementTabSet.h new file mode 100644 index 000000000..15119547e --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/ElementTabSet.h @@ -0,0 +1,61 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_ELEMENTTABSET_H +#define RMLUI_LUA_ELEMENTS_ELEMENTTABSET_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +//methods +int ElementTabSetSetPanel(lua_State* L, ElementTabSet* obj); +int ElementTabSetSetTab(lua_State* L, ElementTabSet* obj); + +//getters +int ElementTabSetGetAttractive_tab(lua_State* L); +int ElementTabSetGetAttrnum_tabs(lua_State* L); + +//setter +int ElementTabSetSetAttractive_tab(lua_State* L); + +extern RegType ElementTabSetMethods[]; +extern luaL_Reg ElementTabSetGetters[]; +extern luaL_Reg ElementTabSetSetters[]; + + +//this will be used to "inherit" from Element +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(ElementTabSet) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/LuaDataFormatter.cpp b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataFormatter.cpp new file mode 100644 index 000000000..05676cd8d --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataFormatter.cpp @@ -0,0 +1,93 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaDataFormatter.h" +#include +#include + +namespace Rml { +namespace Lua { + + +LuaDataFormatter::LuaDataFormatter(const String& name) : DataFormatter(name), ref_FormatData(LUA_NOREF) +{} + +LuaDataFormatter::~LuaDataFormatter() +{} + +void LuaDataFormatter::FormatData(String& formatted_data, const StringList& raw_data) +{ + if(ref_FormatData == LUA_NOREF || ref_FormatData == LUA_REFNIL) + { + Log::Message(Log::LT_ERROR, "In LuaDataFormatter: There is no value assigned to the \"FormatData\" variable."); + return; + } + lua_State* L = Interpreter::GetLuaState(); + int top = lua_gettop(L); + PushDataFormatterFunctionTable(L); // push the table where the function resides + lua_rawgeti(L,-1,ref_FormatData); //push the function + if(lua_type(L,-1) != LUA_TFUNCTION) + { + Log::Message(Log::LT_ERROR, "In LuaDataFormatter: The value for the FormatData variable must be a function. You passed in a %s.", lua_typename(L,lua_type(L,-1))); + lua_settop(L,top); + return; + } + lua_newtable(L); //to hold raw_data + int tbl = lua_gettop(L); + for(unsigned int i = 0; i < raw_data.size(); i++) + { + lua_pushstring(L,raw_data[i].c_str()); + lua_rawseti(L,tbl,i); + } + Interpreter::ExecuteCall(1,1); //1 parameter (the table), 1 result (a string) + + //top of the stack should be the return value + if(lua_type(L,-1) != LUA_TSTRING) + { + Log::Message(Log::LT_ERROR, "In LuaDataFormatter: the return value of FormatData must be a string. You returned a %s.", lua_typename(L,lua_type(L,-1))); + lua_settop(L,top); + return; + } + formatted_data = String(lua_tostring(L,-1)); + lua_settop(L,top); +} + +void LuaDataFormatter::PushDataFormatterFunctionTable(lua_State* L) +{ + lua_getglobal(L,"LUADATAFORMATTERFUNCTIONS"); + if(lua_isnoneornil(L,-1)) + { + lua_newtable(L); + lua_setglobal(L,"LUADATAFORMATTERFUNCTIONS"); + lua_pop(L,1); //pop the unsucessful getglobal + lua_getglobal(L,"LUADATAFORMATTERFUNCTIONS"); + } +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/LuaDataFormatter.h b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataFormatter.h new file mode 100644 index 000000000..c416d7dd2 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataFormatter.h @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_LUADATAFORMATTER_H +#define RMLUI_LUA_ELEMENTS_LUADATAFORMATTER_H + +#include +#include + +namespace Rml { +namespace Lua { + +class LuaDataFormatter : public ::Rml::DataFormatter +{ +public: + LuaDataFormatter(const String& name = ""); + ~LuaDataFormatter(); + + void FormatData(String& formatted_data, const StringList& raw_data) override; + + //Helper function used to push on to the stack the table where the function ref should be stored + static void PushDataFormatterFunctionTable(lua_State* L); + + int ref_FormatData; //the lua reference to the FormatData function +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/LuaDataSource.cpp b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataSource.cpp new file mode 100644 index 000000000..06d43ac43 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataSource.cpp @@ -0,0 +1,106 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaDataSource.h" +#include +#include + +namespace Rml { +namespace Lua { + +LuaDataSource::LuaDataSource(const String& name) : DataSource(name), getRowRef(LUA_NOREF), getNumRowsRef(LUA_NOREF) +{} + +/// Fetches the contents of one row of a table within the data source. +/// @param[out] row The list of values in the table. +/// @param[in] table The name of the table to query. +/// @param[in] row_index The index of the desired row. +/// @param[in] columns The list of desired columns within the row. +void LuaDataSource::GetRow(StringList& row, const String& table, int row_index, const StringList& columns) +{ + if(getRowRef == LUA_NOREF || getRowRef == LUA_REFNIL) return; + + //setup the call + Interpreter::BeginCall(getRowRef); + lua_State* L = Interpreter::GetLuaState(); + lua_pushstring(L,table.c_str()); + lua_pushinteger(L,row_index); + lua_newtable(L); + int index = 0; + for(StringList::const_iterator itr = columns.begin(); itr != columns.end(); ++itr) + { + lua_pushstring(L,itr->c_str()); + lua_rawseti(L,-2,index++); + } + Interpreter::ExecuteCall(3,1); //3 parameters, 1 return. After here, the top of the stack contains the return value + + int res = lua_gettop(L); + if(lua_type(L,res) == LUA_TTABLE) + { + lua_pushnil(L); + while(lua_next(L,res) != 0) + { + //key at -2, value at -1 + row.push_back(luaL_checkstring(L,-1)); + lua_pop(L,1); //pops value, leaves key for next iteration + } + lua_pop(L,1); //pop key + } + else + Log::Message(Log::LT_WARNING, "Lua: DataSource.GetRow must return a table, the function it called returned a %s", lua_typename(L,res)); + + Interpreter::EndCall(1); +} + +/// Fetches the number of rows within one of this data source's tables. +/// @param[in] table The name of the table to query. +/// @return The number of rows within the specified table. Returns -1 in case of an incorrect Lua function. +int LuaDataSource::GetNumRows(const String& table) +{ + if(getNumRowsRef == LUA_NOREF || getNumRowsRef == LUA_REFNIL) return -1; + + lua_State* L = Interpreter::GetLuaState(); + Interpreter::BeginCall(getNumRowsRef); + lua_pushstring(L,table.c_str()); + Interpreter::ExecuteCall(1,1); //1 parameter, 1 return. After this, the top of the stack contains the return value + + int res = lua_gettop(L); + if(lua_type(L,res) == LUA_TNUMBER) + { + return (int)luaL_checkinteger(L,res); + } + else + { + Log::Message(Log::LT_WARNING, "Lua: DataSource.GetNumRows must return an integer, the function it called returned a %s", lua_typename(L,res)); + return -1; + } + +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/LuaDataSource.h b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataSource.h new file mode 100644 index 000000000..7edef0707 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/LuaDataSource.h @@ -0,0 +1,69 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_LUADATASOURCE_H +#define RMLUI_LUA_ELEMENTS_LUADATASOURCE_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +class LuaDataSource : public ::Rml::DataSource +{ +public: + //default initilialize the lua func references to -1 + LuaDataSource(const String& name = ""); + + /// Fetches the contents of one row of a table within the data source. + /// @param[out] row The list of values in the table. + /// @param[in] table The name of the table to query. + /// @param[in] row_index The index of the desired row. + /// @param[in] columns The list of desired columns within the row. + void GetRow(StringList& row, const String& table, int row_index, const StringList& columns) override; + /// Fetches the number of rows within one of this data source's tables. + /// @param[in] table The name of the table to query. + /// @return The number of rows within the specified table. Returns -1 in case of an incorrect Lua function. + int GetNumRows(const String& table) override; + + //make the protected members of DataSource public + using DataSource::NotifyRowAdd; + using DataSource::NotifyRowRemove; + using DataSource::NotifyRowChange; + + //lua reference to DataSource.GetRow + int getRowRef; + //lua reference to DataSource.GetNumRows + int getNumRowsRef; +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Elements/SelectOptionsProxy.cpp b/thirdparty/RmlUi/Source/Lua/Elements/SelectOptionsProxy.cpp new file mode 100644 index 000000000..df84937fe --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/SelectOptionsProxy.cpp @@ -0,0 +1,127 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "SelectOptionsProxy.h" +#include + + +namespace Rml { +namespace Lua { + + +int SelectOptionsProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int keytype = lua_type(L,2); + if(keytype == LUA_TNUMBER) //only valid key types + { + SelectOptionsProxy* proxy = LuaType::check(L,1); + RMLUI_CHECK_OBJ(proxy); + int index = (int)luaL_checkinteger(L,2); + SelectOption* opt = proxy->owner->GetOption(index); + RMLUI_CHECK_OBJ(opt); + lua_newtable(L); + LuaType::push(L,opt->GetElement(),false); + lua_setfield(L,-2,"element"); + lua_pushstring(L,opt->GetValue().c_str()); + lua_setfield(L,-2,"value"); + return 1; + } + else + return LuaType::index(L); +} + +//since there are no string keys, just use __ipairs +int SelectOptionsProxy__pairs(lua_State* L) +{ + return SelectOptionsProxy__ipairs(L); +} + +//[1] is the object, [2] is the previous key, [3] is the userdata +int SelectOptionsProxy__ipairs(lua_State* L) +{ + SelectOptionsProxy* proxy = LuaType::check(L,1); + RMLUI_CHECK_OBJ(proxy); + int* pindex = (int*)lua_touserdata(L,3); + if((*pindex) == -1) + *pindex = 0; + SelectOption* opt = nullptr; + while((*pindex) < proxy->owner->GetNumOptions()) + { + opt = proxy->owner->GetOption((*pindex)++); + if(opt != nullptr) + break; + } + //we got to the end without finding an option + if(opt == nullptr) + { + lua_pushnil(L); + lua_pushnil(L); + } + else //we found an option + { + lua_pushinteger(L,(*pindex)-1); //key + lua_newtable(L); //value + //fill the value + LuaType::push(L,opt->GetElement()); + lua_setfield(L,-2,"element"); + lua_pushstring(L,opt->GetValue().c_str()); + lua_setfield(L,-2,"value"); + } + return 2; +} + +RegType SelectOptionsProxyMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg SelectOptionsProxyGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg SelectOptionsProxySetters[] = +{ + { nullptr, nullptr }, +}; + + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,SelectOptionsProxy__index); + lua_setfield(L,metatable_index,"__index"); + lua_pushcfunction(L,SelectOptionsProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + lua_pushcfunction(L,SelectOptionsProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +RMLUI_LUATYPE_DEFINE(SelectOptionsProxy) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Elements/SelectOptionsProxy.h b/thirdparty/RmlUi/Source/Lua/Elements/SelectOptionsProxy.h new file mode 100644 index 000000000..4e7d3731b --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Elements/SelectOptionsProxy.h @@ -0,0 +1,55 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_ELEMENTS_SELECTOPTIONSPROXY_H +#define RMLUI_LUA_ELEMENTS_SELECTOPTIONSPROXY_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +//where owner is the ElementFormControlSelect that we should look up information from +struct SelectOptionsProxy { ElementFormControlSelect* owner; }; + +int SelectOptionsProxy__index(lua_State* L); +int SelectOptionsProxy__pairs(lua_State* L); +int SelectOptionsProxy__ipairs(lua_State* L); + +extern RegType SelectOptionsProxyMethods[]; +extern luaL_Reg SelectOptionsProxyGetters[]; +extern luaL_Reg SelectOptionsProxySetters[]; + + +template<> void ExtraInit(lua_State* L, int metatable_index); +RMLUI_LUATYPE_DECLARE(SelectOptionsProxy) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Event.cpp b/thirdparty/RmlUi/Source/Lua/Event.cpp new file mode 100644 index 000000000..762ea13e1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Event.cpp @@ -0,0 +1,108 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include "EventParametersProxy.h" + + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* /*L*/, int /*metatable_index*/) { return; } + +//method +int EventStopPropagation(lua_State* /*L*/, Event* obj) +{ + obj->StopPropagation(); + return 0; +} + +//getters +int EventGetAttrcurrent_element(lua_State* L) +{ + Event* evt = LuaType::check(L,1); + RMLUI_CHECK_OBJ(evt); + Element* ele = evt->GetCurrentElement(); + LuaType::push(L,ele,false); + return 1; +} + +int EventGetAttrtype(lua_State* L) +{ + Event* evt = LuaType::check(L,1); + RMLUI_CHECK_OBJ(evt); + String type = evt->GetType(); + lua_pushstring(L,type.c_str()); + return 1; +} + +int EventGetAttrtarget_element(lua_State* L) +{ + Event* evt = LuaType::check(L,1); + RMLUI_CHECK_OBJ(evt); + Element* target = evt->GetTargetElement(); + LuaType::push(L,target,false); + return 1; +} + +int EventGetAttrparameters(lua_State* L) +{ + Event* evt = LuaType::check(L,1); + RMLUI_CHECK_OBJ(evt); + EventParametersProxy* proxy = new EventParametersProxy(); + proxy->owner = evt; + LuaType::push(L,proxy,true); + return 1; +} + +RegType EventMethods[] = +{ + RMLUI_LUAMETHOD(Event,StopPropagation) + { nullptr, nullptr }, +}; + +luaL_Reg EventGetters[] = +{ + RMLUI_LUAGETTER(Event,current_element) + RMLUI_LUAGETTER(Event,type) + RMLUI_LUAGETTER(Event,target_element) + RMLUI_LUAGETTER(Event,parameters) + { nullptr, nullptr }, +}; + +luaL_Reg EventSetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Event) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Event.h b/thirdparty/RmlUi/Source/Lua/Event.h new file mode 100644 index 000000000..c61e79023 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Event.h @@ -0,0 +1,54 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_EVENT_H +#define RMLUI_LUA_EVENT_H + +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); +//method +int EventStopPropagation(lua_State* L, Event* obj); + +//getters +int EventGetAttrcurrent_element(lua_State* L); +int EventGetAttrtype(lua_State* L); +int EventGetAttrtarget_element(lua_State* L); +int EventGetAttrparameters(lua_State* L); + +extern RegType EventMethods[]; +extern luaL_Reg EventGetters[]; +extern luaL_Reg EventSetters[]; + +RMLUI_LUATYPE_DECLARE(Event) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/EventParametersProxy.cpp b/thirdparty/RmlUi/Source/Lua/EventParametersProxy.cpp new file mode 100644 index 000000000..1a2ed10e5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/EventParametersProxy.cpp @@ -0,0 +1,117 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "EventParametersProxy.h" +#include +#include +#include + + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,EventParametersProxy__index); + lua_setfield(L,metatable_index,"__index"); + lua_pushcfunction(L,EventParametersProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + lua_pushcfunction(L,EventParametersProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +int EventParametersProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int keytype = lua_type(L,2); + if(keytype == LUA_TSTRING) //only valid key types + { + EventParametersProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + const char* key = lua_tostring(L,2); + auto it = obj->owner->GetParameters().find(key); + const Variant* param = (it == obj->owner->GetParameters().end() ? nullptr : &it->second); + PushVariant(L,param); + return 1; + } + else + return LuaType::index(L); +} + + +//[1] is the object, [2] is the last used key, [3] is the userdata +int EventParametersProxy__pairs(lua_State* L) +{ + EventParametersProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int& pindex = *(int*)lua_touserdata(L,3); + if ((pindex) == -1) + pindex = 0; + const Dictionary& attributes = obj->owner->GetParameters(); + if(pindex >= 0 && pindex < (int)attributes.size()) + { + auto it = attributes.begin(); + for (int i = 0; i < pindex; ++i) + ++it; + const String& key = it->first; + const Variant* value = &it->second; + lua_pushstring(L,key.c_str()); + PushVariant(L,value); + } + else + { + lua_pushnil(L); + lua_pushnil(L); + } + return 2; +} + +//only index by string +int EventParametersProxy__ipairs(lua_State* L) +{ + lua_pushnil(L); + lua_pushnil(L); + return 2; +} + +RegType EventParametersProxyMethods[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg EventParametersProxyGetters[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg EventParametersProxySetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(EventParametersProxy) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/EventParametersProxy.h b/thirdparty/RmlUi/Source/Lua/EventParametersProxy.h new file mode 100644 index 000000000..579b7d4d3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/EventParametersProxy.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_EVENTPARAMETERSPROXY_H +#define RMLUI_LUA_EVENTPARAMETERSPROXY_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +//where owner is the Element that we should look up information from +struct EventParametersProxy { Event* owner; }; + +template<> void ExtraInit(lua_State* L, int metatable_index); +int EventParametersProxy__index(lua_State* L); +int EventParametersProxy__pairs(lua_State* L); +int EventParametersProxy__ipairs(lua_State* L); + +extern RegType EventParametersProxyMethods[]; +extern luaL_Reg EventParametersProxyGetters[]; +extern luaL_Reg EventParametersProxySetters[]; + +RMLUI_LUATYPE_DECLARE(EventParametersProxy) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/GlobalLuaFunctions.cpp b/thirdparty/RmlUi/Source/Lua/GlobalLuaFunctions.cpp new file mode 100644 index 000000000..4a7240116 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/GlobalLuaFunctions.cpp @@ -0,0 +1,167 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + + +#include "GlobalLuaFunctions.h" +#include +#include +#include +#include +#include + +namespace Rml { +namespace Lua { +/* +Below here are global functions and their helper functions that help overwrite the Lua global functions +*/ + +//__pairs should return two values. +//upvalue 1 is the __pairs function, upvalue 2 is the userdata created in rmlui_pairs +//[1] is the object implementing __pairs +//[2] is the key that was just read +int rmlui_pairsaux(lua_State* L) +{ + lua_pushvalue(L,lua_upvalueindex(1)); //push __pairs to top + lua_insert(L,1); //move __pairs to the bottom + lua_pushvalue(L,lua_upvalueindex(2)); //push userdata + //stack looks like [1] = __pairs, [2] = object, [3] = latest key, [4] = userdata + if(lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0) != 0) + Report(L,"__pairs"); + return lua_gettop(L); +} + +//A version of paris that respects a __pairs metamethod. +//"next" function is upvalue 1 +int rmlui_pairs(lua_State* L) +{ + luaL_checkany(L,1); //[1] is the object given to us by pairs(object) + if(luaL_getmetafield(L,1,"__pairs")) + { + void* ud = lua_newuserdata(L,sizeof(void*)); //create a new block of memory to be used as upvalue 1 + (*(int*)(ud)) = -1; + lua_pushcclosure(L,rmlui_pairsaux,2); //uv 1 is __pairs, uv 2 is ud + } + else + lua_pushvalue(L,lua_upvalueindex(1)); //generator + lua_pushvalue(L,1); //state + lua_pushnil(L); //initial value + return 3; +} + +//copy + pasted from Lua's lbaselib.c +int ipairsaux (lua_State *L) { + lua_Integer i = luaL_checkinteger(L, 2); + luaL_checktype(L, 1, LUA_TTABLE); + i++; /* next value */ + lua_pushinteger(L, i); + lua_rawgeti(L, 1, i); + return (lua_isnil(L, -1)) ? 0 : 2; +} + +//__ipairs should return two values +//upvalue 1 is the __ipairs function, upvalue 2 is the userdata created in rmlui_ipairs +//[1] is the object implementing __ipairs, [2] is the key last used +int rmlui_ipairsaux(lua_State* L) +{ + lua_pushvalue(L,lua_upvalueindex(1)); //push __ipairs + lua_insert(L,1); //move __ipairs to the bottom + lua_pushvalue(L,lua_upvalueindex(2)); //push userdata + //stack looks like [1] = __ipairs, [2] = object, [3] = latest key, [4] = userdata + if(lua_pcall(L,lua_gettop(L)-1,LUA_MULTRET,0) != 0) + Report(L,"__ipairs"); + return lua_gettop(L); +} + + +//A version of paris that respects a __pairs metamethod. +//ipairsaux function is upvalue 1 +int rmlui_ipairs(lua_State* L) +{ + luaL_checkany(L,1); //[1] is the object given to us by ipairs(object) + if(luaL_getmetafield(L,1,"__ipairs")) + { + void* ud = lua_newuserdata(L,sizeof(void*)); //create a new block of memory to be used as upvalue 1 + (*(int*)(ud)) = -1; + lua_pushcclosure(L,rmlui_pairsaux,2); //uv 1 is __ipairs, uv 2 is ud + } + else + lua_pushvalue(L,lua_upvalueindex(1)); //generator + lua_pushvalue(L,1); //state + lua_pushnil(L); //initial value + return 3; +} + + +//Based off of the luaB_print function from Lua's lbaselib.c +int LuaPrint(lua_State* L) +{ + int n = lua_gettop(L); /* number of arguments */ + int i; + lua_getglobal(L, "tostring"); + StringList string_list = StringList(); + String output = ""; + for (i=1; i<=n; i++) + { + const char *s; + lua_pushvalue(L, -1); /* function to be called */ + lua_pushvalue(L, i); /* value to print */ + lua_call(L, 1, 1); + s = lua_tostring(L, -1); /* get result */ + if (s == nullptr) + return luaL_error(L, LUA_QL("tostring") " must return a string to " + LUA_QL("print")); + if (i>1) + output += "\t"; + output += String(s); + lua_pop(L, 1); /* pop result */ + } + output += "\n"; + Log::Message(Log::LT_INFO, output.c_str()); + return 0; +} + +void OverrideLuaGlobalFunctions(lua_State* L) +{ + lua_getglobal(L,"_G"); + + lua_getglobal(L,"next"); + lua_pushcclosure(L,rmlui_pairs,1); + lua_setfield(L,-2,"pairs"); + + lua_pushcfunction(L,ipairsaux); + lua_pushcclosure(L,rmlui_ipairs,1); + lua_setfield(L,-2,"ipairs"); + + lua_pushcfunction(L,LuaPrint); + lua_setfield(L,-2,"print"); + + lua_pop(L,1); //pop _G +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/GlobalLuaFunctions.h b/thirdparty/RmlUi/Source/Lua/GlobalLuaFunctions.h new file mode 100644 index 000000000..b35e348b5 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/GlobalLuaFunctions.h @@ -0,0 +1,41 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_GLOBALLUAFUNCTIONS_H +#define RMLUI_LUA_GLOBALLUAFUNCTIONS_H + +typedef struct lua_State lua_State; + +namespace Rml { +namespace Lua { +void OverrideLuaGlobalFunctions(lua_State* L); +//overrides pairs and ipairs to respect __pairs and __ipairs metamethods +//overrdes print to print to the console +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Interpreter.cpp b/thirdparty/RmlUi/Source/Lua/Interpreter.cpp new file mode 100644 index 000000000..b154504c8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Interpreter.cpp @@ -0,0 +1,156 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include "LuaPlugin.h" +#include "LuaDocumentElementInstancer.h" +#include "LuaEventListenerInstancer.h" +#include +#include +#include +#include +#include + +namespace Rml { +namespace Lua { + +lua_State* Interpreter::GetLuaState() +{ + return LuaPlugin::GetLuaState(); +} + +void Interpreter::LoadFile(const String& file) +{ + lua_State* L = GetLuaState(); + + //use the file interface to get the contents of the script + FileInterface* file_interface = GetFileInterface(); + FileHandle handle = file_interface->Open(file); + if (handle == 0) { + lua_pushfstring(L, "LoadFile: Unable to open file: %s", file.c_str()); + Report(L); + return; + } + + size_t size = file_interface->Length(handle); + if (size == 0) { + lua_pushfstring(L, "LoadFile: File is 0 bytes in size: %s", file.c_str()); + Report(L); + return; + } + char* file_contents = new char[size]; + file_interface->Read(file_contents, size, handle); + file_interface->Close(handle); + + if (luaL_loadbuffer(L, file_contents, size, file.c_str()) != 0) + Report(L); + else //if there were no errors loading, then the compiled function is on the top of the stack + { + if (lua_pcall(L, 0, 0, 0) != 0) + Report(L); + } + + delete[] file_contents; +} + + +void Interpreter::DoString(const String& code, const String& name) +{ + lua_State* L = GetLuaState(); + + if (luaL_loadbuffer(L, code.c_str(), code.length(), name.c_str()) != 0) + Report(L); + else + { + if (lua_pcall(L, 0, 0, 0) != 0) + Report(L); + } +} + +void Interpreter::LoadString(const String& code, const String& name) +{ + lua_State* L = GetLuaState(); + + if (luaL_loadbuffer(L, code.c_str(), code.length(), name.c_str()) != 0) + Report(L); +} + + +void Interpreter::BeginCall(int funRef) +{ + lua_State* L = GetLuaState(); + + lua_settop(L, 0); //empty stack + //lua_getref(g_L,funRef); + lua_rawgeti(L, LUA_REGISTRYINDEX, (int)funRef); +} + +bool Interpreter::ExecuteCall(int params, int res) +{ + lua_State* L = GetLuaState(); + + bool ret = true; + int top = lua_gettop(L); + if (lua_type(L, top - params) != LUA_TFUNCTION) + { + ret = false; + //stack cleanup + if (params > 0) + { + for (int i = top; i >= (top - params); i--) + { + if (!lua_isnone(L, i)) + lua_remove(L, i); + } + } + } + else + { + if (lua_pcall(L, params, res, 0) != 0) + { + Report(L); + ret = false; + } + } + return ret; +} + +void Interpreter::EndCall(int res) +{ + lua_State* L = GetLuaState(); + + //stack cleanup + for (int i = res; i > 0; i--) + { + if (!lua_isnone(L, res)) + lua_remove(L, res); + } +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Log.cpp b/thirdparty/RmlUi/Source/Lua/Log.cpp new file mode 100644 index 000000000..0a119f6e0 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Log.cpp @@ -0,0 +1,97 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Log.h" +#include +#include + + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + //due to they way that LuaType::Register is made, we know that the method table is at the index + //directly below the metatable + int method_index = metatable_index - 1; + + lua_pushcfunction(L,LogMessage); + lua_setfield(L,method_index, "Message"); + + //construct the "logtype" table, so that we can use the Log::Type enum like Log.logtype.always in Lua for Log::LT_ALWAYS + lua_newtable(L); + int logtype = lua_gettop(L); + lua_pushvalue(L,-1); //copy of the new table, so that the logtype index will stay valid + lua_setfield(L,method_index,"logtype"); + + lua_pushinteger(L,(int)Log::LT_ALWAYS); + lua_setfield(L,logtype,"always"); + + lua_pushinteger(L,(int)Log::LT_ERROR); + lua_setfield(L,logtype,"error"); + + lua_pushinteger(L,(int)Log::LT_WARNING); + lua_setfield(L,logtype,"warning"); + + lua_pushinteger(L,(int)Log::LT_INFO); + lua_setfield(L,logtype,"info"); + + lua_pushinteger(L,(int)Log::LT_DEBUG); + lua_setfield(L,logtype,"debug"); + + lua_pop(L,1); //pop the logtype table + return; +} + +int LogMessage(lua_State* L) +{ + Log::Type type = Log::Type((int)luaL_checkinteger(L,1)); + const char* str = luaL_checkstring(L,2); + + Log::Message(type, str); + return 0; +} + +RegType LogMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg LogGetters[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg LogSetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Log) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Log.h b/thirdparty/RmlUi/Source/Lua/Log.h new file mode 100644 index 000000000..2bbc78bab --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Log.h @@ -0,0 +1,50 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LOG_H +#define RMLUI_LUA_LOG_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index); +int LogMessage(lua_State* L); + +extern RegType LogMethods[]; +extern luaL_Reg LogGetters[]; +extern luaL_Reg LogSetters[]; + +RMLUI_LUATYPE_DECLARE(Log) +} // namespace Lua +} // namespace Rml + +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Lua.cpp b/thirdparty/RmlUi/Source/Lua/Lua.cpp new file mode 100644 index 000000000..b190aa33e --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Lua.cpp @@ -0,0 +1,47 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include "LuaPlugin.h" + +namespace Rml { +namespace Lua { + +void Initialise() +{ + ::Rml::Lua::Initialise(nullptr); +} + +void Initialise(lua_State* lua_state) +{ + ::Rml::RegisterPlugin(new LuaPlugin(lua_state)); +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaDocument.cpp b/thirdparty/RmlUi/Source/Lua/LuaDocument.cpp new file mode 100644 index 000000000..82a42eee0 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaDocument.cpp @@ -0,0 +1,58 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaDocument.h" +#include +#include +#include + + +namespace Rml { +namespace Lua { + +LuaDocument::LuaDocument(const String& tag) : ElementDocument(tag) +{ +} + +void LuaDocument::LoadScript(Stream* stream, const String& source_name) +{ + //if it is loaded from a file + if(!source_name.empty()) + { + Interpreter::LoadFile(source_name); + } + else + { + String buffer; + stream->Read(buffer,stream->Length()); //just do the whole thing + Interpreter::DoString(buffer, this->GetSourceURL()); + } +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaDocument.h b/thirdparty/RmlUi/Source/Lua/LuaDocument.h new file mode 100644 index 000000000..3497dd771 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaDocument.h @@ -0,0 +1,48 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUADOCUMENT_H +#define RMLUI_LUA_LUADOCUMENT_H +/* + This class is an ElementDocument that overrides the LoadScript function +*/ +#include + +namespace Rml { +namespace Lua { + +class LuaDocument : public ::Rml::ElementDocument +{ +public: + LuaDocument(const String& tag); + void LoadScript(Stream* stream, const String& source_name) override; +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/LuaDocumentElementInstancer.cpp b/thirdparty/RmlUi/Source/Lua/LuaDocumentElementInstancer.cpp new file mode 100644 index 000000000..e8a5441d3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaDocumentElementInstancer.cpp @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaDocumentElementInstancer.h" +#include "LuaDocument.h" + +namespace Rml { +namespace Lua { + +/// Instances an element given the tag name and attributes. +/// @param[in] parent The element the new element is destined to be parented to. +/// @param[in] tag The tag of the element to instance. +/// @param[in] attributes Dictionary of attributes. +ElementPtr LuaDocumentElementInstancer::InstanceElement(Element* /*parent*/, const String& tag, const XMLAttributes& /*attributes*/) +{ + return ElementPtr(new LuaDocument(tag)); +} +/// Releases an element instanced by this instancer. +/// @param[in] element The element to release. +void LuaDocumentElementInstancer::ReleaseElement(Element* element) +{ + delete element; +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaDocumentElementInstancer.h b/thirdparty/RmlUi/Source/Lua/LuaDocumentElementInstancer.h new file mode 100644 index 000000000..586abfc9a --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaDocumentElementInstancer.h @@ -0,0 +1,51 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUADOCUMENTELEMENTINSTANCER_H +#define RMLUI_LUA_LUADOCUMENTELEMENTINSTANCER_H + +#include + +namespace Rml { +namespace Lua { + +class LuaDocumentElementInstancer : public ::Rml::ElementInstancer +{ + /// Instances an element given the tag name and attributes. + /// @param[in] parent The element the new element is destined to be parented to. + /// @param[in] tag The tag of the element to instance. + /// @param[in] attributes Dictionary of attributes. + ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override; + /// Releases an element instanced by this instancer. + /// @param[in] element The element to release. + void ReleaseElement(Element* element) override; +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/LuaElementInstancer.cpp b/thirdparty/RmlUi/Source/Lua/LuaElementInstancer.cpp new file mode 100644 index 000000000..8734447d3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaElementInstancer.cpp @@ -0,0 +1,94 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaElementInstancer.h" +#include +#include +#include +#include + +namespace Rml { +namespace Lua { +//This will be called from ElementInstancernew +LuaElementInstancer::LuaElementInstancer(lua_State* L) : ElementInstancer(), ref_InstanceElement(LUA_NOREF) +{ + if(lua_type(L,1) != LUA_TFUNCTION && !lua_isnoneornil(L,1)) + { + Log::Message(Log::LT_ERROR, "The argument to ElementInstancer.new has to be a function or nil. You passed in a %s.", luaL_typename(L,1)); + return; + } + PushFunctionsTable(L); //top of the table is now ELEMENTINSTANCERFUNCTIONS table + lua_pushvalue(L,1); //copy of the function + ref_InstanceElement = luaL_ref(L,-2); + lua_pop(L,1); //pop the ELEMENTINSTANCERFUNCTIONS table +} + +ElementPtr LuaElementInstancer::InstanceElement(Element* RMLUI_UNUSED_PARAMETER(parent), const String& tag, const XMLAttributes& RMLUI_UNUSED_PARAMETER(attributes)) +{ + RMLUI_UNUSED(parent); + RMLUI_UNUSED(attributes); + + lua_State* L = Interpreter::GetLuaState(); + int top = lua_gettop(L); + ElementPtr ret = nullptr; + if(ref_InstanceElement != LUA_REFNIL && ref_InstanceElement != LUA_NOREF) + { + PushFunctionsTable(L); + lua_rawgeti(L,-1,ref_InstanceElement); //push the function + lua_pushstring(L,tag.c_str()); //push the tag + Interpreter::ExecuteCall(1,1); //we pass in a string, and we want to get an Element back + ret = std::move(*LuaType::check(L,-1)); + } + else + { + Log::Message(Log::LT_WARNING, "Attempt to call the function for ElementInstancer.InstanceElement, the function does not exist."); + } + lua_settop(L,top); + return ret; +} + +void LuaElementInstancer::ReleaseElement(Element* element) +{ + delete element; +} + +void LuaElementInstancer::PushFunctionsTable(lua_State* L) +{ + //make sure there is an area to save the function + lua_getglobal(L,"ELEMENTINSTANCERFUNCTIONS"); + if(lua_isnoneornil(L,-1)) + { + lua_newtable(L); + lua_setglobal(L,"ELEMENTINSTANCERFUNCTIONS"); + lua_pop(L,1); //pop the unsucessful getglobal + lua_getglobal(L,"ELEMENTINSTANCERFUNCTIONS"); + } +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaElementInstancer.h b/thirdparty/RmlUi/Source/Lua/LuaElementInstancer.h new file mode 100644 index 000000000..49185071a --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaElementInstancer.h @@ -0,0 +1,60 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUAELEMENTINSTANCER_H +#define RMLUI_LUA_LUAELEMENTINSTANCER_H + +#include +#include +#include + +namespace Rml { +namespace Lua { + +class LuaElementInstancer : public ::Rml::ElementInstancer +{ +public: + LuaElementInstancer(lua_State* L); + /// Instances an element given the tag name and attributes. + /// @param[in] parent The element the new element is destined to be parented to. + /// @param[in] tag The tag of the element to instance. + /// @param[in] attributes Dictionary of attributes. + ElementPtr InstanceElement(Element* parent, const String& tag, const XMLAttributes& attributes) override; + /// Releases an element instanced by this instancer. + /// @param[in] element The element to release. + void ReleaseElement(Element* element) override; + + int ref_InstanceElement; + + //Pushes on to the top of the stack the table named EVENTINSTNACERFUNCTIONS + void PushFunctionsTable(lua_State* L); +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/LuaEventListener.cpp b/thirdparty/RmlUi/Source/Lua/LuaEventListener.cpp new file mode 100644 index 000000000..e7adbf6f4 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaEventListener.cpp @@ -0,0 +1,149 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaEventListener.h" +#include +#include +#include +#include + +namespace Rml { +namespace Lua { +typedef ElementDocument Document; + +LuaEventListener::LuaEventListener(const String& code, Element* element) : EventListener() +{ + //compose function + String function = "return function (event,element,document) "; + function.append(code); + function.append(" end"); + + //make sure there is an area to save the function + lua_State* L = Interpreter::GetLuaState(); + int top = lua_gettop(L); + lua_getglobal(L,"EVENTLISTENERFUNCTIONS"); + if(lua_isnoneornil(L,-1)) + { + lua_newtable(L); + lua_setglobal(L,"EVENTLISTENERFUNCTIONS"); + lua_pop(L,1); //pop the unsucessful getglobal + lua_getglobal(L,"EVENTLISTENERFUNCTIONS"); + } + int tbl = lua_gettop(L); + + //compile,execute,and save the function + if(luaL_loadstring(L,function.c_str()) != 0) + { + Report(L); + return; + } + else + { + if(lua_pcall(L,0,1,0) != 0) + { + Report(L); + return; + } + } + luaFuncRef = luaL_ref(L,tbl); //creates a reference to the item at the top of the stack in to the table we just created + lua_pop(L,1); //pop the EVENTLISTENERFUNCTIONS table + + attached = element; + if(element) + owner_document = element->GetOwnerDocument(); + else + owner_document = nullptr; + strFunc = function; + lua_settop(L,top); +} + +//if it is passed in a Lua function +LuaEventListener::LuaEventListener(lua_State* L, int narg, Element* element) +{ + int top = lua_gettop(L); + lua_getglobal(L,"EVENTLISTENERFUNCTIONS"); + if(lua_isnoneornil(L,-1)) + { + lua_newtable(L); + lua_setglobal(L,"EVENTLISTENERFUNCTIONS"); + lua_pop(L,1); //pop the unsucessful getglobal + lua_getglobal(L,"EVENTLISTENERFUNCTIONS"); + } + lua_pushvalue(L,narg); + luaFuncRef = luaL_ref(L,-2); //put the funtion as a ref in to that table + lua_pop(L,1); //pop the EVENTLISTENERFUNCTIONS table + + attached = element; + if(element) + owner_document = element->GetOwnerDocument(); + else + owner_document = nullptr; + lua_settop(L,top); +} + +LuaEventListener::~LuaEventListener() +{ + // Remove the Lua function from its table + lua_State* L = Interpreter::GetLuaState(); + lua_getglobal(L, "EVENTLISTENERFUNCTIONS"); + luaL_unref(L, -1, luaFuncRef); + lua_pop(L, 1); // pop table +} + +void LuaEventListener::OnDetach(Element* /*element*/) +{ + // We consider this listener owned by its element, so we must delete ourselves when + // we detach (probably because element was removed). + delete this; +} + +/// Process the incoming Event +void LuaEventListener::ProcessEvent(Event& event) +{ + //not sure if this is the right place to do this, but if the element we are attached to isn't a document, then + //the 'owner_document' variable will be nullptr, because element->ower_document hasn't been set on the construction. We should + //correct that + if(!owner_document && attached) owner_document = attached->GetOwnerDocument(); + lua_State* L = Interpreter::GetLuaState(); + int top = lua_gettop(L); + + //push the arguments + lua_getglobal(L,"EVENTLISTENERFUNCTIONS"); + lua_rawgeti(L,-1,luaFuncRef); + LuaType::push(L,&event,false); + LuaType::push(L,attached,false); + LuaType::push(L,owner_document,false); + + Interpreter::ExecuteCall(3,0); //call the function at the top of the stack with 3 arguments + + lua_settop(L,top); //balanced stack makes Lua happy + +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaEventListener.h b/thirdparty/RmlUi/Source/Lua/LuaEventListener.h new file mode 100644 index 000000000..f75846cf0 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaEventListener.h @@ -0,0 +1,73 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUAEVENTLISTENER_H +#define RMLUI_LUA_LUAEVENTLISTENER_H + +#include +#include + +namespace Rml { +class Element; +class ElementDocument; + +namespace Lua { + +class LuaEventListener : public ::Rml::EventListener +{ +public: + //The plan is to wrap the code in an anonymous function so that we can have named parameters to use, + //rather than putting them in global variables + LuaEventListener(const String& code, Element* element); + + //This is called from a Lua Element if in element:AddEventListener it passes a function in as the 2nd + //parameter rather than a string. We don't wrap the function in an anonymous function, so the user + //should take care to have the proper order. The order is event,element,document. + //narg is the position on the stack + LuaEventListener(lua_State* L, int narg, Element* element); + + virtual ~LuaEventListener(); + + // Deletes itself, which also unreferences the Lua function. + void OnDetach(Element* element) override; + + // Calls the associated Lua function. + void ProcessEvent(Event& event) override; + +private: + //the lua-side function to call when ProcessEvent is called + int luaFuncRef = -1; + + Element* attached = nullptr; + ElementDocument* owner_document = nullptr; + String strFunc; //for debugging purposes +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/LuaEventListenerInstancer.cpp b/thirdparty/RmlUi/Source/Lua/LuaEventListenerInstancer.cpp new file mode 100644 index 000000000..1adb933b8 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaEventListenerInstancer.cpp @@ -0,0 +1,44 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaEventListenerInstancer.h" +#include "LuaEventListener.h" + +namespace Rml { +namespace Lua { + +/// Instance an event listener object. +/// @param value Value of the event. +/// @param element Element that triggers the events. +EventListener* LuaEventListenerInstancer::InstanceEventListener(const String& value, Element* element) +{ + return new LuaEventListener(value,element); +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaEventListenerInstancer.h b/thirdparty/RmlUi/Source/Lua/LuaEventListenerInstancer.h new file mode 100644 index 000000000..0bfd86520 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaEventListenerInstancer.h @@ -0,0 +1,47 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUAEVENTLISTENERINSTANCER_H +#define RMLUI_LUA_LUAEVENTLISTENERINSTANCER_H +#include + +namespace Rml { +namespace Lua { + +class LuaEventListenerInstancer : public ::Rml::EventListenerInstancer +{ +public: + /// Instance an event listener object. + /// @param value Value of the event. + /// @param element Element that triggers the events. + EventListener* InstanceEventListener(const String& value, Element* element) override; +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/LuaPlugin.cpp b/thirdparty/RmlUi/Source/Lua/LuaPlugin.cpp new file mode 100644 index 000000000..d25bbb3d6 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaPlugin.cpp @@ -0,0 +1,186 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "LuaPlugin.h" +#include +#include +#include +#include +#include +#include "LuaDocumentElementInstancer.h" +#include +#include "LuaEventListenerInstancer.h" +#include "RmlUi.h" +//the types I made +#include "ContextDocumentsProxy.h" +#include "EventParametersProxy.h" +#include "ElementAttributesProxy.h" +#include "Log.h" +#include "Element.h" +#include "ElementStyleProxy.h" +#include "Document.h" +#include "Colourb.h" +#include "Colourf.h" +#include "Vector2f.h" +#include "Vector2i.h" +#include "Context.h" +#include "Event.h" +#include "ElementInstancer.h" +#include "ElementChildNodesProxy.h" +#include "ElementText.h" +#include "GlobalLuaFunctions.h" +#include "RmlUiContextsProxy.h" +// Control types +#include "Elements/SelectOptionsProxy.h" +#include "Elements/DataFormatter.h" +#include "Elements/DataSource.h" +#include "Elements/ElementForm.h" +#include "Elements/ElementFormControl.h" +#include "Elements/ElementFormControlSelect.h" +#include "Elements/ElementFormControlDataSelect.h" +#include "Elements/ElementFormControlInput.h" +#include "Elements/ElementFormControlTextArea.h" +#include "Elements/ElementDataGrid.h" +#include "Elements/ElementDataGridRow.h" +#include "Elements/ElementTabSet.h" + +namespace Rml { +namespace Lua { + +static lua_State* g_L = nullptr; + + +/** This will populate the global Lua table with all of the Lua core types by calling LuaType::Register +@remark This is called automatically by LuaPlugin::OnInitialise(). */ +static void RegisterTypes(); + + +LuaPlugin::LuaPlugin(lua_State* lua_state) +{ + RMLUI_ASSERT(g_L == nullptr); + g_L = lua_state; +} + +int LuaPlugin::GetEventClasses() +{ + return EVT_BASIC; +} + +void LuaPlugin::OnInitialise() +{ + if (g_L == nullptr) + { + Log::Message(Log::LT_INFO, "Loading Lua plugin using a new Lua state."); + g_L = luaL_newstate(); + luaL_openlibs(g_L); + owns_lua_state = true; + } + else + { + Log::Message(Log::LT_INFO, "Loading Lua plugin using the provided Lua state."); + owns_lua_state = false; + } + RegisterTypes(); + + lua_document_element_instancer = new LuaDocumentElementInstancer(); + lua_event_listener_instancer = new LuaEventListenerInstancer(); + Factory::RegisterElementInstancer("body", lua_document_element_instancer); + Factory::RegisterEventListenerInstancer(lua_event_listener_instancer); +} + +void LuaPlugin::OnShutdown() +{ + delete lua_document_element_instancer; + delete lua_event_listener_instancer; + lua_document_element_instancer = nullptr; + lua_event_listener_instancer = nullptr; + + if (owns_lua_state) + lua_close(g_L); + + g_L = nullptr; + + delete this; +} + + +static void RegisterTypes() +{ + RMLUI_ASSERT(g_L); + lua_State* L = g_L; + + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + //things that inherit from Element + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + //Proxy tables + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + OverrideLuaGlobalFunctions(L); + //push the global variable "rmlui" to use the "RmlUi" methods + LuaRmlUiPushrmluiGlobal(L); + + // Control types + LuaType::Register(L); + LuaType::Register(L); + //Inherits from ElementFormControl + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + LuaType::Register(L); + //proxy tables + LuaType::Register(L); +} + + +lua_State* LuaPlugin::GetLuaState() +{ + return g_L; +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/LuaPlugin.h b/thirdparty/RmlUi/Source/Lua/LuaPlugin.h new file mode 100644 index 000000000..4b693a605 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaPlugin.h @@ -0,0 +1,70 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_LUAPLUGIN_H +#define RMLUI_LUA_LUAPLUGIN_H + +#include +#include + +typedef struct lua_State lua_State; + +namespace Rml { +namespace Lua { + +class LuaDocumentElementInstancer; +class LuaEventListenerInstancer; + +/** + This initializes the Lua interpreter, and has functions to load the scripts or + call functions that exist in Lua. + + @author Nathan Starkey +*/ +class RMLUILUA_API LuaPlugin : public Plugin +{ +public: + LuaPlugin(lua_State* lua_state); + + static lua_State* GetLuaState(); + +private: + int GetEventClasses() override; + + void OnInitialise() override; + + void OnShutdown() override; + + LuaDocumentElementInstancer* lua_document_element_instancer = nullptr; + LuaEventListenerInstancer* lua_event_listener_instancer = nullptr; + bool owns_lua_state = false; +}; + +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/LuaType.cpp b/thirdparty/RmlUi/Source/Lua/LuaType.cpp new file mode 100644 index 000000000..5fb53f720 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/LuaType.cpp @@ -0,0 +1,123 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include +#include + +namespace Rml { +namespace Lua { + + +int LuaTypeImpl::index(lua_State* L, const char* class_name) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + lua_getglobal(L, class_name); //stack pos [3] (fairly important, just refered to as [3]) + // string form of the key. + const char* key = luaL_checkstring(L, 2); + if (lua_istable(L, -1)) //[-1 = 3] + { + lua_pushvalue(L, 2); //[2] = key, [4] = copy of key + lua_rawget(L, -2); //[-2 = 3] -> pop top and push the return value to top [4] + //If the key were looking for is not in the table, retrieve its' metatables' index value. + if (lua_isnil(L, -1)) //[-1 = 4] is value from rawget above + { + //try __getters + lua_pop(L, 1); //remove top item (nil) from the stack + lua_pushstring(L, "__getters"); + lua_rawget(L, -2); //[-2 = 3], ._getters -> result to [4] + lua_pushvalue(L, 2); //[2 = key] -> copy to [5] + lua_rawget(L, -2); //[-2 = __getters] -> __getters[key], result to [5] + if (lua_type(L, -1) == LUA_TFUNCTION) //[-1 = 5] + { + lua_pushvalue(L, 1); //push the userdata to the stack [6] + if (lua_pcall(L, 1, 1, 0) != 0) //remove one, result is at [6] + Report(L, String(class_name).append(".__index for ").append(lua_tostring(L, 2)).append(": ")); + } + else + { + lua_settop(L, 4); //forget everything we did above + lua_getmetatable(L, -2); //[-2 = 3] -> metatable from to top [5] + if (lua_istable(L, -1)) //[-1 = 5] = the result of the above + { + lua_getfield(L, -1, "__index"); //[-1 = 5] = check the __index metamethod for the metatable-> push result to [6] + if (lua_isfunction(L, -1)) //[-1 = 6] = __index metamethod + { + lua_pushvalue(L, 1); //[1] = object -> [7] = object + lua_pushvalue(L, 2); //[2] = key -> [8] = key + if (lua_pcall(L, 2, 1, 0) != 0) //call function at top of stack (__index) -> pop top 2 as args; [7] = return value + Report(L, String(class_name).append(".__index for ").append(lua_tostring(L, 2)).append(": ")); + } + else if (lua_istable(L, -1)) + lua_getfield(L, -1, key); //shorthand version of above -> [7] = return value + else + lua_pushnil(L); //[7] = nil + } + else + lua_pushnil(L); //[6] = nil + } + } + else if (lua_istable(L, -1))//[-1 = 4] is value from rawget [3] + { + lua_pushvalue(L, 2); //[2] = key, [5] = key + lua_rawget(L, -2); //[-2 = 3] = table of -> pop top and push the return value to top [5] + } + } + else + lua_pushnil(L); //[4] = nil + + lua_insert(L, 1); //top element to position 1 -> [1] = top element as calculated in the earlier rest of the function + lua_settop(L, 1); // -> [1 = -1], removes the other elements + return 1; +} + +int LuaTypeImpl::newindex(lua_State* L, const char* class_name) +{ + //[1] = obj, [2] = key, [3] = value + //look for it in __setters + lua_getglobal(L, class_name); //[4] = this table + lua_pushstring(L, "__setters"); //[5] + lua_rawget(L, -2); //[-2 = 4] -> .__setters to [5] + lua_pushvalue(L, 2); //[2 = key] -> [6] = copy of key + lua_rawget(L, -2); //[-2 = __setters] -> __setters[key] to [6] + if (lua_type(L, -1) == LUA_TFUNCTION) + { + lua_pushvalue(L, 1); //userdata at [7] + lua_pushvalue(L, 3); //[8] = copy of [3] + if (lua_pcall(L, 2, 0, 0) != 0) //call function, pop 2 off push 0 on + Report(L, String(class_name).append(".__newindex for ").append(lua_tostring(L, 2)).append(": ")); + } + else + lua_pop(L, 1); //not a setter function. + lua_pop(L, 2); //pop __setters and the table + return 0; +} + + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/RmlUi.cpp b/thirdparty/RmlUi/Source/Lua/RmlUi.cpp new file mode 100644 index 000000000..13306e446 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/RmlUi.cpp @@ -0,0 +1,329 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "RmlUi.h" +#include +#include +#include +#include "ElementInstancer.h" +#include "LuaElementInstancer.h" +#include "RmlUiContextsProxy.h" + +namespace Rml { +namespace Lua { +#define RMLUILUA_INPUTENUM(keyident,tbl) lua_pushinteger(L,Input::KI_##keyident); lua_setfield(L,(tbl),#keyident); +#define RMLUILUA_INPUTMODIFIERENUM(keymod,tbl) lua_pushinteger(L,Input::KM_##keymod); lua_setfield(L,(tbl),#keymod); + +//c++ representation of the global variable in Lua so that the syntax is consistent +LuaRmlUi lua_global_rmlui; + +void LuaRmlUiPushrmluiGlobal(lua_State* L) +{ + luaL_getmetatable(L,GetTClassName()); + LuaRmlUiEnumkey_identifier(L); + lua_global_rmlui.key_identifier_ref = luaL_ref(L,-2); + LuaRmlUiEnumkey_modifier(L); + lua_global_rmlui.key_modifier_ref = luaL_ref(L,-2); + LuaType::push(L,&lua_global_rmlui,false); + lua_setglobal(L,"rmlui"); +} + +template<> void ExtraInit(lua_State* /*L*/, int /*metatable_index*/) { return; } + +int LuaRmlUiCreateContext(lua_State* L, LuaRmlUi* /*obj*/) +{ + const char* name = luaL_checkstring(L,1); + Vector2i* dimensions = LuaType::check(L,2); + Context* new_context = CreateContext(name, *dimensions); + if(new_context == nullptr || dimensions == nullptr) + { + lua_pushnil(L); + } + else + { + LuaType::push(L, new_context); + } + return 1; +} + +int LuaRmlUiLoadFontFace(lua_State* L, LuaRmlUi* /*obj*/) +{ + const char* file = luaL_checkstring(L,1); + lua_pushboolean(L,LoadFontFace(file)); + return 1; +} + +int LuaRmlUiRegisterTag(lua_State* L, LuaRmlUi* /*obj*/) +{ + const char* tag = luaL_checkstring(L,1); + LuaElementInstancer* lei = (LuaElementInstancer*)LuaType::check(L,2); + RMLUI_CHECK_OBJ(lei); + Factory::RegisterElementInstancer(tag,lei); + return 0; +} + +int LuaRmlUiGetAttrcontexts(lua_State* L) +{ + RmlUiContextsProxy* proxy = new RmlUiContextsProxy(); + LuaType::push(L,proxy,true); + return 1; +} + +int LuaRmlUiGetAttrkey_identifier(lua_State* L) +{ + luaL_getmetatable(L,GetTClassName()); + lua_rawgeti(L,-1,lua_global_rmlui.key_identifier_ref); + return 1; +} + +int LuaRmlUiGetAttrkey_modifier(lua_State* L) +{ + luaL_getmetatable(L,GetTClassName()); + lua_rawgeti(L,-1,lua_global_rmlui.key_modifier_ref); + return 1; +} + +void LuaRmlUiEnumkey_identifier(lua_State* L) +{ + lua_newtable(L); + int tbl = lua_gettop(L); + RMLUILUA_INPUTENUM(UNKNOWN,tbl) + RMLUILUA_INPUTENUM(SPACE,tbl) + RMLUILUA_INPUTENUM(0,tbl) + RMLUILUA_INPUTENUM(1,tbl) + RMLUILUA_INPUTENUM(2,tbl) + RMLUILUA_INPUTENUM(3,tbl) + RMLUILUA_INPUTENUM(4,tbl) + RMLUILUA_INPUTENUM(5,tbl) + RMLUILUA_INPUTENUM(6,tbl) + RMLUILUA_INPUTENUM(7,tbl) + RMLUILUA_INPUTENUM(8,tbl) + RMLUILUA_INPUTENUM(9,tbl) + RMLUILUA_INPUTENUM(A,tbl) + RMLUILUA_INPUTENUM(B,tbl) + RMLUILUA_INPUTENUM(C,tbl) + RMLUILUA_INPUTENUM(D,tbl) + RMLUILUA_INPUTENUM(E,tbl) + RMLUILUA_INPUTENUM(F,tbl) + RMLUILUA_INPUTENUM(G,tbl) + RMLUILUA_INPUTENUM(H,tbl) + RMLUILUA_INPUTENUM(I,tbl) + RMLUILUA_INPUTENUM(J,tbl) + RMLUILUA_INPUTENUM(K,tbl) + RMLUILUA_INPUTENUM(L,tbl) + RMLUILUA_INPUTENUM(M,tbl) + RMLUILUA_INPUTENUM(N,tbl) + RMLUILUA_INPUTENUM(O,tbl) + RMLUILUA_INPUTENUM(P,tbl) + RMLUILUA_INPUTENUM(Q,tbl) + RMLUILUA_INPUTENUM(R,tbl) + RMLUILUA_INPUTENUM(S,tbl) + RMLUILUA_INPUTENUM(T,tbl) + RMLUILUA_INPUTENUM(U,tbl) + RMLUILUA_INPUTENUM(V,tbl) + RMLUILUA_INPUTENUM(W,tbl) + RMLUILUA_INPUTENUM(X,tbl) + RMLUILUA_INPUTENUM(Y,tbl) + RMLUILUA_INPUTENUM(Z,tbl) + RMLUILUA_INPUTENUM(OEM_1,tbl) + RMLUILUA_INPUTENUM(OEM_PLUS,tbl) + RMLUILUA_INPUTENUM(OEM_COMMA,tbl) + RMLUILUA_INPUTENUM(OEM_MINUS,tbl) + RMLUILUA_INPUTENUM(OEM_PERIOD,tbl) + RMLUILUA_INPUTENUM(OEM_2,tbl) + RMLUILUA_INPUTENUM(OEM_3,tbl) + RMLUILUA_INPUTENUM(OEM_4,tbl) + RMLUILUA_INPUTENUM(OEM_5,tbl) + RMLUILUA_INPUTENUM(OEM_6,tbl) + RMLUILUA_INPUTENUM(OEM_7,tbl) + RMLUILUA_INPUTENUM(OEM_8,tbl) + RMLUILUA_INPUTENUM(OEM_102,tbl) + RMLUILUA_INPUTENUM(NUMPAD0,tbl) + RMLUILUA_INPUTENUM(NUMPAD1,tbl) + RMLUILUA_INPUTENUM(NUMPAD2,tbl) + RMLUILUA_INPUTENUM(NUMPAD3,tbl) + RMLUILUA_INPUTENUM(NUMPAD4,tbl) + RMLUILUA_INPUTENUM(NUMPAD5,tbl) + RMLUILUA_INPUTENUM(NUMPAD6,tbl) + RMLUILUA_INPUTENUM(NUMPAD7,tbl) + RMLUILUA_INPUTENUM(NUMPAD8,tbl) + RMLUILUA_INPUTENUM(NUMPAD9,tbl) + RMLUILUA_INPUTENUM(NUMPADENTER,tbl) + RMLUILUA_INPUTENUM(MULTIPLY,tbl) + RMLUILUA_INPUTENUM(ADD,tbl) + RMLUILUA_INPUTENUM(SEPARATOR,tbl) + RMLUILUA_INPUTENUM(SUBTRACT,tbl) + RMLUILUA_INPUTENUM(DECIMAL,tbl) + RMLUILUA_INPUTENUM(DIVIDE,tbl) + RMLUILUA_INPUTENUM(OEM_NEC_EQUAL,tbl) + RMLUILUA_INPUTENUM(BACK,tbl) + RMLUILUA_INPUTENUM(TAB,tbl) + RMLUILUA_INPUTENUM(CLEAR,tbl) + RMLUILUA_INPUTENUM(RETURN,tbl) + RMLUILUA_INPUTENUM(PAUSE,tbl) + RMLUILUA_INPUTENUM(CAPITAL,tbl) + RMLUILUA_INPUTENUM(KANA,tbl) + RMLUILUA_INPUTENUM(HANGUL,tbl) + RMLUILUA_INPUTENUM(JUNJA,tbl) + RMLUILUA_INPUTENUM(FINAL,tbl) + RMLUILUA_INPUTENUM(HANJA,tbl) + RMLUILUA_INPUTENUM(KANJI,tbl) + RMLUILUA_INPUTENUM(ESCAPE,tbl) + RMLUILUA_INPUTENUM(CONVERT,tbl) + RMLUILUA_INPUTENUM(NONCONVERT,tbl) + RMLUILUA_INPUTENUM(ACCEPT,tbl) + RMLUILUA_INPUTENUM(MODECHANGE,tbl) + RMLUILUA_INPUTENUM(PRIOR,tbl) + RMLUILUA_INPUTENUM(NEXT,tbl) + RMLUILUA_INPUTENUM(END,tbl) + RMLUILUA_INPUTENUM(HOME,tbl) + RMLUILUA_INPUTENUM(LEFT,tbl) + RMLUILUA_INPUTENUM(UP,tbl) + RMLUILUA_INPUTENUM(RIGHT,tbl) + RMLUILUA_INPUTENUM(DOWN,tbl) + RMLUILUA_INPUTENUM(SELECT,tbl) + RMLUILUA_INPUTENUM(PRINT,tbl) + RMLUILUA_INPUTENUM(EXECUTE,tbl) + RMLUILUA_INPUTENUM(SNAPSHOT,tbl) + RMLUILUA_INPUTENUM(INSERT,tbl) + RMLUILUA_INPUTENUM(DELETE,tbl) + RMLUILUA_INPUTENUM(HELP,tbl) + RMLUILUA_INPUTENUM(LWIN,tbl) + RMLUILUA_INPUTENUM(RWIN,tbl) + RMLUILUA_INPUTENUM(APPS,tbl) + RMLUILUA_INPUTENUM(POWER,tbl) + RMLUILUA_INPUTENUM(SLEEP,tbl) + RMLUILUA_INPUTENUM(WAKE,tbl) + RMLUILUA_INPUTENUM(F1,tbl) + RMLUILUA_INPUTENUM(F2,tbl) + RMLUILUA_INPUTENUM(F3,tbl) + RMLUILUA_INPUTENUM(F4,tbl) + RMLUILUA_INPUTENUM(F5,tbl) + RMLUILUA_INPUTENUM(F6,tbl) + RMLUILUA_INPUTENUM(F7,tbl) + RMLUILUA_INPUTENUM(F8,tbl) + RMLUILUA_INPUTENUM(F9,tbl) + RMLUILUA_INPUTENUM(F10,tbl) + RMLUILUA_INPUTENUM(F11,tbl) + RMLUILUA_INPUTENUM(F12,tbl) + RMLUILUA_INPUTENUM(F13,tbl) + RMLUILUA_INPUTENUM(F14,tbl) + RMLUILUA_INPUTENUM(F15,tbl) + RMLUILUA_INPUTENUM(F16,tbl) + RMLUILUA_INPUTENUM(F17,tbl) + RMLUILUA_INPUTENUM(F18,tbl) + RMLUILUA_INPUTENUM(F19,tbl) + RMLUILUA_INPUTENUM(F20,tbl) + RMLUILUA_INPUTENUM(F21,tbl) + RMLUILUA_INPUTENUM(F22,tbl) + RMLUILUA_INPUTENUM(F23,tbl) + RMLUILUA_INPUTENUM(F24,tbl) + RMLUILUA_INPUTENUM(NUMLOCK,tbl) + RMLUILUA_INPUTENUM(SCROLL,tbl) + RMLUILUA_INPUTENUM(OEM_FJ_JISHO,tbl) + RMLUILUA_INPUTENUM(OEM_FJ_MASSHOU,tbl) + RMLUILUA_INPUTENUM(OEM_FJ_TOUROKU,tbl) + RMLUILUA_INPUTENUM(OEM_FJ_LOYA,tbl) + RMLUILUA_INPUTENUM(OEM_FJ_ROYA,tbl) + RMLUILUA_INPUTENUM(LSHIFT,tbl) + RMLUILUA_INPUTENUM(RSHIFT,tbl) + RMLUILUA_INPUTENUM(LCONTROL,tbl) + RMLUILUA_INPUTENUM(RCONTROL,tbl) + RMLUILUA_INPUTENUM(LMENU,tbl) + RMLUILUA_INPUTENUM(RMENU,tbl) + RMLUILUA_INPUTENUM(BROWSER_BACK,tbl) + RMLUILUA_INPUTENUM(BROWSER_FORWARD,tbl) + RMLUILUA_INPUTENUM(BROWSER_REFRESH,tbl) + RMLUILUA_INPUTENUM(BROWSER_STOP,tbl) + RMLUILUA_INPUTENUM(BROWSER_SEARCH,tbl) + RMLUILUA_INPUTENUM(BROWSER_FAVORITES,tbl) + RMLUILUA_INPUTENUM(BROWSER_HOME,tbl) + RMLUILUA_INPUTENUM(VOLUME_MUTE,tbl) + RMLUILUA_INPUTENUM(VOLUME_DOWN,tbl) + RMLUILUA_INPUTENUM(VOLUME_UP,tbl) + RMLUILUA_INPUTENUM(MEDIA_NEXT_TRACK,tbl) + RMLUILUA_INPUTENUM(MEDIA_PREV_TRACK,tbl) + RMLUILUA_INPUTENUM(MEDIA_STOP,tbl) + RMLUILUA_INPUTENUM(MEDIA_PLAY_PAUSE,tbl) + RMLUILUA_INPUTENUM(LAUNCH_MAIL,tbl) + RMLUILUA_INPUTENUM(LAUNCH_MEDIA_SELECT,tbl) + RMLUILUA_INPUTENUM(LAUNCH_APP1,tbl) + RMLUILUA_INPUTENUM(LAUNCH_APP2,tbl) + RMLUILUA_INPUTENUM(OEM_AX,tbl) + RMLUILUA_INPUTENUM(ICO_HELP,tbl) + RMLUILUA_INPUTENUM(ICO_00,tbl) + RMLUILUA_INPUTENUM(PROCESSKEY,tbl) + RMLUILUA_INPUTENUM(ICO_CLEAR,tbl) + RMLUILUA_INPUTENUM(ATTN,tbl) + RMLUILUA_INPUTENUM(CRSEL,tbl) + RMLUILUA_INPUTENUM(EXSEL,tbl) + RMLUILUA_INPUTENUM(EREOF,tbl) + RMLUILUA_INPUTENUM(PLAY,tbl) + RMLUILUA_INPUTENUM(ZOOM,tbl) + RMLUILUA_INPUTENUM(PA1,tbl) + RMLUILUA_INPUTENUM(OEM_CLEAR,tbl) +} + +void LuaRmlUiEnumkey_modifier(lua_State* L) +{ + lua_newtable(L); + int tbl = lua_gettop(L); + RMLUILUA_INPUTMODIFIERENUM(CTRL,tbl) + RMLUILUA_INPUTMODIFIERENUM(SHIFT,tbl) + RMLUILUA_INPUTMODIFIERENUM(ALT,tbl) + RMLUILUA_INPUTMODIFIERENUM(META,tbl) + RMLUILUA_INPUTMODIFIERENUM(CAPSLOCK,tbl) + RMLUILUA_INPUTMODIFIERENUM(NUMLOCK,tbl) + RMLUILUA_INPUTMODIFIERENUM(SCROLLLOCK,tbl) +} + + +RegType LuaRmlUiMethods[] = +{ + RMLUI_LUAMETHOD(LuaRmlUi,CreateContext) + RMLUI_LUAMETHOD(LuaRmlUi,LoadFontFace) + RMLUI_LUAMETHOD(LuaRmlUi,RegisterTag) + { nullptr, nullptr }, +}; + +luaL_Reg LuaRmlUiGetters[] = +{ + RMLUI_LUAGETTER(LuaRmlUi,contexts) + RMLUI_LUAGETTER(LuaRmlUi,key_identifier) + RMLUI_LUAGETTER(LuaRmlUi,key_modifier) + { nullptr, nullptr }, +}; + +luaL_Reg LuaRmlUiSetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(LuaRmlUi) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/RmlUi.h b/thirdparty/RmlUi/Source/Lua/RmlUi.h new file mode 100644 index 000000000..04fef5fcb --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/RmlUi.h @@ -0,0 +1,69 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_RMLUI_H +#define RMLUI_LUA_RMLUI_H + +#include +#include + +namespace Rml { +namespace Lua { + + +class LuaRmlUi +{ +public: + //reference to the table defined in LuaRmlUiEnumkey_identifier + int key_identifier_ref; + //reference to the table defined in LuaRmlUiEnumkey_modifier + int key_modifier_ref; +}; + +void LuaRmlUiPushrmluiGlobal(lua_State* L); + +template<> void ExtraInit(lua_State* L, int metatable_index); +int LuaRmlUiCreateContext(lua_State* L, LuaRmlUi* obj); +int LuaRmlUiLoadFontFace(lua_State* L, LuaRmlUi* obj); +int LuaRmlUiRegisterTag(lua_State* L, LuaRmlUi* obj); + +int LuaRmlUiGetAttrcontexts(lua_State* L); +int LuaRmlUiGetAttrkey_identifier(lua_State* L); +int LuaRmlUiGetAttrkey_modifier(lua_State* L); + +void LuaRmlUiEnumkey_identifier(lua_State* L); +void LuaRmlUiEnumkey_modifier(lua_State* L); + +extern RegType LuaRmlUiMethods[]; +extern luaL_Reg LuaRmlUiGetters[]; +extern luaL_Reg LuaRmlUiSetters[]; + +RMLUI_LUATYPE_DECLARE(LuaRmlUi) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/RmlUiContextsProxy.cpp b/thirdparty/RmlUi/Source/Lua/RmlUiContextsProxy.cpp new file mode 100644 index 000000000..673199d58 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/RmlUiContextsProxy.cpp @@ -0,0 +1,139 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "RmlUiContextsProxy.h" +#include +#include + + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,RmlUiContextsProxy__index); + lua_setfield(L,metatable_index,"__index"); + lua_pushcfunction(L,RmlUiContextsProxy__pairs); + lua_setfield(L,metatable_index,"__pairs"); + lua_pushcfunction(L,RmlUiContextsProxy__ipairs); + lua_setfield(L,metatable_index,"__ipairs"); +} + +int RmlUiContextsProxy__index(lua_State* L) +{ + /*the table obj and the missing key are currently on the stack(index 1 & 2) as defined by the Lua language*/ + int keytype = lua_type(L,2); + if(keytype == LUA_TSTRING || keytype == LUA_TNUMBER) //only valid key types + { + RmlUiContextsProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + if(keytype == LUA_TSTRING) + { + const char* key = lua_tostring(L,2); + LuaType::push(L,GetContext(key)); + } + else + { + int key = (int)luaL_checkinteger(L,2); + LuaType::push(L,GetContext(key)); + } + return 1; + } + else + return LuaType::index(L); +} + + +//[1] is the object, [2] is the last used key, [3] is the userdata +int RmlUiContextsProxy__pairs(lua_State* L) +{ + RmlUiContextsProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int* pindex = (int*)lua_touserdata(L,3); + if((*pindex) == -1) + *pindex = 0; + Context* value = nullptr; + if((*pindex)++ < GetNumContexts()) + { + value = GetContext(*pindex); + } + if(value == nullptr) + { + lua_pushnil(L); + lua_pushnil(L); + } + else + { + lua_pushstring(L,value->GetName().c_str()); + LuaType::push(L,value); + } + return 2; +} + +//[1] is the object, [2] is the last used key, [3] is the userdata +int RmlUiContextsProxy__ipairs(lua_State* L) +{ + RmlUiContextsProxy* obj = LuaType::check(L,1); + RMLUI_CHECK_OBJ(obj); + int* pindex = (int*)lua_touserdata(L,3); + if((*pindex) == -1) + *pindex = 0; + Context* value = nullptr; + if((*pindex)++ < GetNumContexts()) + { + value = GetContext(*pindex); + } + if(value == nullptr) + { + lua_pushnil(L); + lua_pushnil(L); + } + else + { + lua_pushinteger(L,(*pindex)-1); + LuaType::push(L,value); + } + return 2; +} + +RegType RmlUiContextsProxyMethods[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg RmlUiContextsProxyGetters[] = +{ + { nullptr, nullptr }, +}; +luaL_Reg RmlUiContextsProxySetters[] = +{ + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(RmlUiContextsProxy) +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/RmlUiContextsProxy.h b/thirdparty/RmlUi/Source/Lua/RmlUiContextsProxy.h new file mode 100644 index 000000000..51f933a0f --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/RmlUiContextsProxy.h @@ -0,0 +1,53 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_RMLUICONTEXTSPROXY_H +#define RMLUI_LUA_RMLUICONTEXTSPROXY_H + +#include +#include + + +namespace Rml { +namespace Lua { +//where owner is the Element that we should look up information from +struct RmlUiContextsProxy { void* nothing; }; + +template<> void ExtraInit(lua_State* L, int metatable_index); +int RmlUiContextsProxy__index(lua_State* L); +int RmlUiContextsProxy__pairs(lua_State* L); +int RmlUiContextsProxy__ipairs(lua_State* L); + +extern RegType RmlUiContextsProxyMethods[]; +extern luaL_Reg RmlUiContextsProxyGetters[]; +extern luaL_Reg RmlUiContextsProxySetters[]; + +RMLUI_LUATYPE_DECLARE(RmlUiContextsProxy) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Utilities.cpp b/thirdparty/RmlUi/Source/Lua/Utilities.cpp new file mode 100644 index 000000000..c3e2722f3 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Utilities.cpp @@ -0,0 +1,93 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +namespace Rml { +namespace Lua { + +void PushVariant(lua_State* L, const Variant* var) +{ + if(var == nullptr) + { + lua_pushnil(L); + return; + } + Variant::Type vartype = var->GetType(); + switch(vartype) + { + case Variant::BYTE: + case Variant::CHAR: + case Variant::INT: + lua_pushinteger(L,var->Get()); + break; + case Variant::FLOAT: + lua_pushnumber(L,var->Get()); + break; + case Variant::COLOURB: + LuaType::push(L,new Colourb(var->Get()),true); + break; + case Variant::COLOURF: + LuaType::push(L,new Colourf(var->Get()),true); + break; + case Variant::STRING: + lua_pushstring(L,var->Get().c_str()); + break; + case Variant::VECTOR2: + //according to Variant.inl, it is going to be a Vector2f + LuaType::push(L,new Vector2f(var->Get()),true); + break; + case Variant::VOIDPTR: + lua_pushlightuserdata(L,var->Get()); + break; + default: + lua_pushnil(L); + break; + } +} + + +void Report(lua_State* L, const String& place) +{ + const char * msg= lua_tostring(L,-1); + String strmsg; + while(msg) + { + lua_pop(L,1); + if(place == "") + strmsg = msg; + else + strmsg = String(place).append(" ").append(msg); + Log::Message(Log::LT_WARNING, strmsg.c_str()); + msg=lua_tostring(L,-1); + } +} + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Vector2f.cpp b/thirdparty/RmlUi/Source/Lua/Vector2f.cpp new file mode 100644 index 000000000..1cba7a4ec --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Vector2f.cpp @@ -0,0 +1,241 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Vector2f.h" +#include + +namespace Rml { +namespace Lua { + +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,Vector2fnew); + lua_setfield(L,metatable_index-1,"new"); + + lua_pushcfunction(L,Vector2f__mul); + lua_setfield(L,metatable_index,"__mul"); + + lua_pushcfunction(L,Vector2f__div); + lua_setfield(L,metatable_index,"__div"); + + lua_pushcfunction(L,Vector2f__add); + lua_setfield(L,metatable_index,"__add"); + + lua_pushcfunction(L,Vector2f__sub); + lua_setfield(L,metatable_index,"__sub"); + + lua_pushcfunction(L,Vector2f__eq); + lua_setfield(L,metatable_index,"__eq"); + + //stack is in the same state as it was before it entered this function + return; +} + +int Vector2fnew(lua_State* L) +{ + float x = (float)luaL_checknumber(L,1); + float y = (float)luaL_checknumber(L,2); + + Vector2f* vect = new Vector2f(x,y); + + LuaType::push(L,vect,true); //true means it will be deleted when it is garbage collected + return 1; +} + +int Vector2f__mul(lua_State* L) +{ + Vector2f* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + float rhs = (float)luaL_checknumber(L,2); + + Vector2f* res = new Vector2f(0.f,0.f); + (*res) = (*lhs) * rhs; + + LuaType::push(L,res,true); + return 1; +} + +int Vector2f__div(lua_State* L) +{ + Vector2f* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + float rhs = (float)luaL_checknumber(L,2); + + Vector2f* res = new Vector2f(0.f,0.f); + (*res) = (*lhs) / rhs; + + LuaType::push(L,res,true); + return 1; +} + +int Vector2f__add(lua_State* L) +{ + Vector2f* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Vector2f* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + Vector2f* res = new Vector2f(0.f,0.f); + (*res) = (*lhs) + (*rhs); + + LuaType::push(L,res,true); + return 1; +} + +int Vector2f__sub(lua_State* L) +{ + Vector2f* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Vector2f* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + Vector2f* res = new Vector2f(0.f,0.f); + (*res) = (*lhs) - (*rhs); + + LuaType::push(L,res,true); + return 1; +} + +int Vector2f__eq(lua_State* L) +{ + Vector2f* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Vector2f* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + lua_pushboolean(L, (*lhs) == (*rhs) ? 1 : 0); + return 1; +} + + +int Vector2fDotProduct(lua_State* L, Vector2f* obj) +{ + Vector2f* rhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(rhs); + + float res = obj->DotProduct(*rhs); + + lua_pushnumber(L,res); + return 1; +} + +int Vector2fNormalise(lua_State* L, Vector2f* obj) +{ + Vector2f* res = new Vector2f(); + (*res) = obj->Normalise(); + + LuaType::push(L,res,true); + return 1; +} + +int Vector2fRotate(lua_State* L, Vector2f* obj) +{ + float num = (float)luaL_checknumber(L,1); + + Vector2f* res = new Vector2f(); + (*res) = obj->Rotate(num); + + LuaType::push(L,res,true); + return 1; +} + +int Vector2fGetAttrx(lua_State*L) +{ + Vector2f* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + + lua_pushnumber(L,self->x); + return 1; +} + +int Vector2fGetAttry(lua_State*L) +{ + Vector2f* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + + lua_pushnumber(L,self->y); + return 1; +} + +int Vector2fGetAttrmagnitude(lua_State*L) +{ + Vector2f* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + + lua_pushnumber(L,self->Magnitude()); + return 1; +} + +int Vector2fSetAttrx(lua_State*L) +{ + Vector2f* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + float value = (float)luaL_checknumber(L,2); + + self->x = value; + return 0; +} + +int Vector2fSetAttry(lua_State*L) +{ + Vector2f* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + float value = (float)luaL_checknumber(L,2); + + self->y = value; + return 0; +} + + +RegType Vector2fMethods[] = +{ + RMLUI_LUAMETHOD(Vector2f,DotProduct) + RMLUI_LUAMETHOD(Vector2f,Normalise) + RMLUI_LUAMETHOD(Vector2f,Rotate) + { nullptr, nullptr }, +}; + +luaL_Reg Vector2fGetters[]= +{ + RMLUI_LUAGETTER(Vector2f,x) + RMLUI_LUAGETTER(Vector2f,y) + RMLUI_LUAGETTER(Vector2f,magnitude) + { nullptr, nullptr }, +}; + +luaL_Reg Vector2fSetters[]= +{ + RMLUI_LUASETTER(Vector2f,x) + RMLUI_LUASETTER(Vector2f,y) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Vector2f) + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Vector2f.h b/thirdparty/RmlUi/Source/Lua/Vector2f.h new file mode 100644 index 000000000..bc6ca8a61 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Vector2f.h @@ -0,0 +1,66 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_VECTOR2F_H +#define RMLUI_LUA_VECTOR2F_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); + +int Vector2fnew(lua_State* L); +int Vector2f__mul(lua_State* L); +int Vector2f__div(lua_State* L); +int Vector2f__add(lua_State* L); +int Vector2f__sub(lua_State* L); +int Vector2f__eq(lua_State* L); + +int Vector2fDotProduct(lua_State* L, Vector2f* obj); +int Vector2fNormalise(lua_State* L, Vector2f* obj); +int Vector2fRotate(lua_State* L, Vector2f* obj); + +int Vector2fGetAttrx(lua_State*L); +int Vector2fGetAttry(lua_State*L); +int Vector2fGetAttrmagnitude(lua_State*L); + +int Vector2fSetAttrx(lua_State*L); +int Vector2fSetAttry(lua_State*L); + + +extern RegType Vector2fMethods[]; +extern luaL_Reg Vector2fGetters[]; +extern luaL_Reg Vector2fSetters[]; + +RMLUI_LUATYPE_DECLARE(Vector2f) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/Source/Lua/Vector2i.cpp b/thirdparty/RmlUi/Source/Lua/Vector2i.cpp new file mode 100644 index 000000000..ec96548f1 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Vector2i.cpp @@ -0,0 +1,205 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Vector2i.h" + + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index) +{ + lua_pushcfunction(L,Vector2inew); + lua_setfield(L,metatable_index-1,"new"); + + lua_pushcfunction(L,Vector2i__mul); + lua_setfield(L,metatable_index,"__mul"); + + lua_pushcfunction(L,Vector2i__div); + lua_setfield(L,metatable_index,"__div"); + + lua_pushcfunction(L,Vector2i__add); + lua_setfield(L,metatable_index,"__add"); + + lua_pushcfunction(L,Vector2i__sub); + lua_setfield(L,metatable_index,"__sub"); + + lua_pushcfunction(L,Vector2i__eq); + lua_setfield(L,metatable_index,"__eq"); + + //stack is in the same state as it was before it entered this function + return; +} + +int Vector2inew(lua_State* L) +{ + int x = (int)luaL_checkinteger(L,1); + int y = (int)luaL_checkinteger(L,2); + + Vector2i* vect = new Vector2i(x,y); + + LuaType::push(L,vect,true); //true means it will be deleted when it is garbage collected + return 1; +} + +int Vector2i__mul(lua_State* L) +{ + Vector2i* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + int rhs = (int)luaL_checkinteger(L,2); + + Vector2i* res = new Vector2i(0,0); + (*res) = (*lhs) * rhs; + + LuaType::push(L,res,true); + return 1; +} + +int Vector2i__div(lua_State* L) +{ + Vector2i* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + int rhs = (int)luaL_checkinteger(L,2); + + Vector2i* res = new Vector2i(0,0); + (*res) = (*lhs) / rhs; + + LuaType::push(L,res,true); + return 1; +} + +int Vector2i__add(lua_State* L) +{ + Vector2i* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Vector2i* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + Vector2i* res = new Vector2i(0,0); + (*res) = (*lhs) + (*rhs); + + LuaType::push(L,res,true); + return 1; +} + +int Vector2i__sub(lua_State* L) +{ + Vector2i* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Vector2i* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + Vector2i* res = new Vector2i(0,0); + (*res) = (*lhs) - (*rhs); + + LuaType::push(L,res,true); + return 1; +} + +int Vector2i__eq(lua_State* L) +{ + Vector2i* lhs = LuaType::check(L,1); + RMLUI_CHECK_OBJ(lhs); + Vector2i* rhs = LuaType::check(L,2); + RMLUI_CHECK_OBJ(rhs); + + lua_pushboolean(L, (*lhs) == (*rhs) ? 1 : 0); + return 1; +} + +int Vector2iGetAttrx(lua_State*L) +{ + Vector2i* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + + lua_pushinteger(L,self->x); + return 1; +} + +int Vector2iGetAttry(lua_State*L) +{ + Vector2i* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + + lua_pushinteger(L,self->y); + return 1; +} + +int Vector2iGetAttrmagnitude(lua_State*L) +{ + Vector2i* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + + lua_pushnumber(L,self->Magnitude()); + return 1; +} + +int Vector2iSetAttrx(lua_State*L) +{ + Vector2i* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + int value = (int)luaL_checkinteger(L,2); + + self->x = value; + return 0; +} + +int Vector2iSetAttry(lua_State*L) +{ + Vector2i* self = LuaType::check(L,1); + RMLUI_CHECK_OBJ(self); + int value = (int)luaL_checkinteger(L,2); + + self->y = value; + return 0; +} + + +RegType Vector2iMethods[] = +{ + { nullptr, nullptr }, +}; + +luaL_Reg Vector2iGetters[]= +{ + RMLUI_LUAGETTER(Vector2i,x) + RMLUI_LUAGETTER(Vector2i,y) + RMLUI_LUAGETTER(Vector2i,magnitude) + { nullptr, nullptr }, +}; + +luaL_Reg Vector2iSetters[]= +{ + RMLUI_LUASETTER(Vector2i,x) + RMLUI_LUASETTER(Vector2i,y) + { nullptr, nullptr }, +}; + +RMLUI_LUATYPE_DEFINE(Vector2i) + +} // namespace Lua +} // namespace Rml diff --git a/thirdparty/RmlUi/Source/Lua/Vector2i.h b/thirdparty/RmlUi/Source/Lua/Vector2i.h new file mode 100644 index 000000000..acfdc65b7 --- /dev/null +++ b/thirdparty/RmlUi/Source/Lua/Vector2i.h @@ -0,0 +1,63 @@ +/* + * This source file is part of RmlUi, the HTML/CSS Interface Middleware + * + * For the latest information, see http://github.com/mikke89/RmlUi + * + * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd + * Copyright (c) 2019 The RmlUi Team, and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef RMLUI_LUA_VECTOR2I_H +#define RMLUI_LUA_VECTOR2I_H + +#include +#include +#include + +namespace Rml { +namespace Lua { +template<> void ExtraInit(lua_State* L, int metatable_index); +int Vector2inew(lua_State* L); +int Vector2i__mul(lua_State* L); +int Vector2i__div(lua_State* L); +int Vector2i__add(lua_State* L); +int Vector2i__sub(lua_State* L); +int Vector2i__eq(lua_State* L); + +//getters +int Vector2iGetAttrx(lua_State*L); +int Vector2iGetAttry(lua_State*L); +int Vector2iGetAttrmagnitude(lua_State*L); + +//setters +int Vector2iSetAttrx(lua_State*L); +int Vector2iSetAttry(lua_State*L); + + +extern RegType Vector2iMethods[]; +extern luaL_Reg Vector2iGetters[]; +extern luaL_Reg Vector2iSetters[]; + +RMLUI_LUATYPE_DECLARE(Vector2i) +} // namespace Lua +} // namespace Rml +#endif diff --git a/thirdparty/RmlUi/changelog.md b/thirdparty/RmlUi/changelog.md new file mode 100644 index 000000000..3d2e15b8d --- /dev/null +++ b/thirdparty/RmlUi/changelog.md @@ -0,0 +1,934 @@ +* [RmlUi 3.3](#rmlui-33) +* [RmlUi 3.2](#rmlui-32) +* [RmlUi 3.1](#rmlui-31) +* [RmlUi 3.0](#rmlui-30) +* [RmlUi 2.0](#rmlui-20) + + +## RmlUi 4.0 (WIP) + +### Restructuring RmlUi + +RmlUi has been restructured to simplify its usage. This involves breaking changes but should benefit everyone using the library in the future. See discussion in [#58](https://github.com/mikke89/RmlUi/issues/58). + +- The old `Controls` plugin is now gone. But fear not! It has been merged into the `Core` project. +- The old `Rml::Core` and `Rml::Controls` namespaces have been removed, their contents are now located directly in the `Rml` namespace. +- The old `Controls` public header files have been moved to ``. +- The old `Controls` source files and private header files have been moved to `Source/Core/Elements/...`. +- The `Debugger` plugin remains as before at the same location and same namespace `Rml::Debugger`. + +The Lua plugins have been changed to reflect the above changes. + +- The old Lua plugins `RmlCoreLua` and `RmlControlsLua` have been merged into a single library `RmlLua`. +- The public header files are now located at ``. +- The Lua plugin is now initialized by calling `Rml::Lua::Initialise()` located in ``. +- Separated the Lua interpreter functions from initialization and the Lua plugin. +- Renamed macros in the Lua plugin, they now start with `RMLUI_`. + +#### Upgrade guide + +- Remove the call to `Rml::Controls::Initialise()`, this is no longer needed. +- Replace all inclusions of `` with `` unless it is already included, or include individual header files. +- Rename all inclusions of `` to ``. +- Replace all occurrences of `Rml::Core` with `Rml`. +- Replace all occurrences of `Rml::Controls` with `Rml`. +- Look for forward declarations in `namespace Rml { namespace Core { ... } }` and `namespace Rml { namespace Controls { ... } }`. Replace with `namespace Rml { ... }`. +- Remove the linkage to the `RmlControls` library. +- For users of the Lua plugin: + - Replace RmlUi's Lua header files with `` or individual header files in ``. + - Replace the old initialization calls with `Rml::Lua::Initialise()`. Previously this was `Rml::Core::Lua::Interpreter::Initialise()` and `Rml::Controls::Lua::RegisterTypes(...)`. + - Link with the library `RmlLua`, remove `RmlCoreLua` and `RmlControlsLua`. +- Welcome to RmlUi 4.0 :) + +#### Related internal changes. + +- Refactored the two `WidgetSlider` classes to avoid duplicate names in Core and Controls. +- Refactored `TransformPrimitive.h` by moving utility functions that should only be used internally to an internal header file. +- Renamed header guard macros. + + +### Model-view-controller (MVC) implementation + +RmlUi now supports a model-view-controller (MVC) approach through data bindings. This is a powerful approach for making documents respond to data changes, or in reverse, updating data based on user actions. + +For now, this is considered an experimental feature. + +- See the work-in-progress [documentation for this feature](https://mikke89.github.io/RmlUiDoc/pages/data_bindings.html). +- Have a look at the 'databinding' sample for usage examples. +- See discussion in [#83](https://github.com/mikke89/RmlUi/pull/83) and [#25](https://github.com/mikke89/RmlUi/issues/25). + +### Other features and improvements + +- Implemented `Element::QuerySelector` and `Element::QuerySelectorAll`. +- Improved the SFML2 sample [#106](https://github.com/mikke89/RmlUi/pull/106) and [#103](https://github.com/mikke89/RmlUi/issues/103) (thanks @hachmeister). + + +### Breaking changes + +- Namespaces and plugin names changed! See the restructuring changes above. +- It is no longer possible to use `{{` and `}}` inside RML documents outside the context of data bindings. +- Attributes starting with `data-` are now reserved for RmlUi. +- The `BaseXMLParser` class has some minor interface changes. + + + +## RmlUi 3.3 + +### Rml `select` element improvements + +- Prevent scrolling in the parent window when scrolling inside the selection box. +- Close the selection box when scrolling in the parent document. +- The selection box will now limit its height to the available space within the context's window dimensions, and position itself either below or above the `select` element as appropriate. [#91](https://github.com/mikke89/RmlUi/issues/91) + +### Cleaning up header files + +An effort has been made for header files to include what they use, and nothing else. This effort has measurably improved compile times, especially when not using precompiled headers. + +This change also makes it easier to include only parts of the library headers in the user application for improved compile times. That is, instead of including the whole core library using `#include `, one can specify which ones are needed such as `#include `. + +### CMake precompiled header support + +The library now makes use of CMake's precompiled header support (requires CMake 3.16 or higher), which can optionally be disabled. In Visual Studio, compilation times are improved by almost 50% when enabled. + +### Changes + +- The `style` attribute no longer requires a semi-colon `;` after the final property. +- The sample projects now universally use the `F8` key to toggle the RmlUi debugger on all platforms. +- Add an upper limit to the number of possible custom properties and events. This change will reduce the number of dynamic allocations in some cases. +- Build improvements and several warnings fixed. Compiles cleanly with `-Wall -Wextra` and on MSVC with `/W4`. +- The sample projects now find their assets when building and running the sample with Visual Studio's native CMake support and default settings. This also applies when targeting Windows Subsystem for Linux (WSL). +- The mouse cursor API is now implemented on the X11 shell. +- RmlUi is now C++20 compatible (C++14 is still the minimum requirement). + +### Bug fixes + +- Fix font textures not released when calling Core::ReleaseTextures [#84](https://github.com/mikke89/RmlUi/issues/84). +- Re-implement `Rml::Core::ReleaseCompiledGeometries()` [#84](https://github.com/mikke89/RmlUi/issues/84). +- Property `white-space: nowrap` no longer disables horizontal scrollbars on overflow [#94](https://github.com/mikke89/RmlUi/issues/94). +- Changes to font effects are now properly applied whenever the `font-effect` property is changed [#98](https://github.com/mikke89/RmlUi/issues/98). +- Fix structural pseudo-selectors only being applied if written with parenthesis [#30](https://github.com/mikke89/RmlUi/issues/30#issuecomment-597648310). + + +## RmlUi 3.2 + +### Animating keyword properties + +Keyword properties can now be animated. Keywords are always interpolated in discrete steps, and normally applied half-way to the next keyframe. The single exception to this rule is for the `visibility` property. As in the CSS specifications, this property always applies the `visible` keyword during transition when present either in the previous or next keyframe. + +Thus, the following can produce a fade-out animation, removing visibility of the element at animation end (thanks to @uniquejack for the example). +```css +@keyframes fadeout { + from { + opacity: 1; + } + to { + opacity: 0; + visibility: hidden; + } +} +.fadeout { + animation: 1.2s cubic-in fadeout; +} +``` + +### Changes + +- Animated properties are now removed when an animation completes. +- Update robin_hood unordered_map to 3.5.0 (thanks @jhasse). [#75](https://github.com/mikke89/RmlUi/issues/75) + +### Bug fixes + +- Range input element: Change event reports the correct value instead of normalized (thanks @andreasschultes). [#72](https://github.com/mikke89/RmlUi/issues/72) [#73](https://github.com/mikke89/RmlUi/issues/73). +- Fix wrong cast in elapsed time in SDL2 sample. [#71](https://github.com/mikke89/RmlUi/issues/71). +- Avoid infinite recursion on Variant construction/assignment with unsupported types. [#70](https://github.com/mikke89/RmlUi/issues/70). +- Fix warnings issued by the MinGW compiler (thanks @jhasse). + + +## RmlUi 3.1 + +### Progress bar + +A new `progressbar` element is introduced for visually displaying progress or relative values. The element can take the following attributes. + +- `value`. Number `[0, 1]`. The fraction of the progress bar that is filled where 1 means completely filled. +- `direction`. Determines the direction in which the filled part expands. One of: + - `top | right (default) | bottom | left | clockwise | counter-clockwise` +- `start-edge`. Only applies to 'clockwise' or 'counter-clockwise' directions. Defines which edge the +circle should start expanding from. Possible values: + - `top (default) | right | bottom | left` + +The element is only available with the `RmlControls` library. + +**Styling** + +The progressbar generates a non-dom `fill` element beneath it which can be used to style the filled part of the bar. The `fill` element can use normal properties such as `background-color`, `border`, and `decorator` to style it, or use the new `fill-image`-property to set an image which will be clipped according to the progress bar's `value`. + +The `fill-image` property is the only way to style circular progress bars (`clockwise` and `counter-clockwise` directions). The `fill` element is still available but it will always be fixed in size independent of the `value` attribute. + +**New RCSS property** + +- `fill-image`. String, non-inherited. Must be the name of a sprite or the path to an image. + +**Examples** + +The following RCSS styles three different progress bars. +```css +@spritesheet progress_bars +{ + src: my_progress_bars.tga; + progress: 103px 267px 80px 34px; + progress-fill-l: 110px 302px 6px 34px; + progress-fill-c: 140px 302px 6px 34px; + progress-fill-r: 170px 302px 6px 34px; + gauge: 0px 271px 100px 86px; + gauge-fill: 0px 356px 100px 86px; +} +.progress_horizontal { + decorator: image( progress ); + width: 80px; + height: 34px; +} +.progress_horizontal fill { + decorator: tiled-horizontal( progress-fill-l, progress-fill-c, progress-fill-r ); + margin: 0 7px; + /* padding ensures that the decorator has a minimum width when the value is zero */ + padding-left: 14px; +} +.progress_vertical { + width: 30px; + height: 80px; + background-color: #E3E4E1; + border: 4px #A90909; +} +.progress_vertical fill { + border: 3px #4D9137; + background-color: #7AE857; +} +.gauge { + decorator: image( gauge ); + width: 100px; + height: 86px; +} +.gauge fill { + fill-image: gauge-fill; +} +``` +Now, they can be used in RML as follows. +```html + + + +``` + + +### New font effects + +Two new font effects have been added. + +**Glow effect** + +Renders a blurred outline around the text. + +The `glow` effect is declared as: +```css +font-effect: glow( ); +``` +Both the outline pass and the subsequent blur pass can be controlled independently. Additionally, an offset can be applied which makes the effect suitable for generating drop shadows as well. + +**Blur effect** + +Renders a Gaussian blurred copy of the text. + +The `blur` effect is declared as: +```css +font-effect: blur( ); +``` +Note that, the blur effect will not replace the original text. To only show the blurred version of the text, set the `color` property of the original text to `transparent`. + +**Example usage** + +```css +/* Declares a glow effect. */ +h1 +{ + font-effect: glow( 3px #ee9 ); +} + +/* The glow effect can also create nice looking shadows. */ +p.glow_shadow +{ + color: #ed5; + font-effect: glow(2px 4px 2px 3px #644); +} + +/* Renders a blurred version of the text, hides the original text. */ +h1 +{ + color: transparent; + font-effect: blur(3px #ed5); +} +``` + +See the `demo` sample for additional usage examples and results. + + + +### CMake options + +New CMake option added. + +- `DISABLE_RTTI_AND_EXCEPTIONS` will try to configure the compiler to disable RTTI language support and exceptions. All internal use of RTTI (eg. dynamic_cast) will then be replaced by a custom solution. If set, users of the library should then `#define RMLUI_USE_CUSTOM_RTTI` before including the library. + + + +### Breaking changes + +- For users that implement custom font effects, there are some minor changes to the font effect interface and the convolution filter. + + + +## RmlUi 3.0 + + +RmlUi 3.0 is the biggest change yet, featuring a substantial amount of new features and bug fixes. One of the main efforts in RmlUi 3.0 has been on improving the performance of the library. Users should see a noticable performance increase when upgrading. + + +### Performance + +One of the main efforts in RmlUi 3.0 has been on improving the performance of the library. Some noteable changes include: + +- The update loop has been reworked to avoid doing unnecessary, repeated calculations whenever the document or style is changed. Instead of immediately updating properties on any affected elements, most of this work is done during the Context::Update call in a more carefully chosen order. Note that for this reason, when querying the Rocket API for properties such as size or position, this information may not be up-to-date with changes since the last Context::Update, such as newly added elements or classes. If this information is needed immediately, a call to ElementDocument::UpdateDocument can be made before such queries at a performance penalty. +- Several containers have been replaced, such as std::map to [robin_hood::unordered_flat_map](https://github.com/martinus/robin-hood-hashing). +- Reduced number of allocations and unnecessary recursive calls. +- Internally, the concept of computed values has been introduced. Computed values take the properties of an element and computes them as far as possible without introducing the layouting. + +All of these changes, in addition to many smaller optimizations, results in a more than **25x** measured performance increase for creation and destruction of a large number of elements. A benchmark is included with the samples. + + +### Sprite sheets + +The RCSS at-rule `@spritesheet` can be used to declare a sprite sheet. A sprite sheet consists of a single image and multiple sprites each specifying a region of the image. Sprites can in turn be used in decorators. + +A sprite sheet can be declared in RCSS as in the following example. +```css +@spritesheet theme +{ + src: invader.tga; + + title-bar-l: 147px 0px 82px 85px; + title-bar-c: 229px 0px 1px 85px; + title-bar-r: 231px 0px 15px 85px; + + icon-invader: 179px 152px 51px 39px; + icon-game: 230px 152px 51px 39px; + icon-score: 434px 152px 51px 39px; + icon-help: 128px 152px 51px 39px; +} +``` +The first property `src` provides the filename of the image for the sprite sheet. Every other property specifies a sprite as `: `. A sprite's name applies globally to all included style sheets in a given document, and must be unique. A rectangle is declared as `x y width height`, each of which must be in `px` units. Here, `x` and `y` refers to the position in the image with the origin placed at the top-left corner, and `width` and `height` extends the rectangle right and down. + +The sprite name can be used in decorators, such as: +```css +decorator: tiled-horizontal( title-bar-l, title-bar-c, title-bar-r ); +``` +This creates a tiled decorator where the `title-bar-l` and `title-bar-r` sprites occupies the left and right parts of the element at their native size, while `title-bar-c` occupies the center and is stretched horizontally as the element is stretched. + + +### Decorators + +The new RCSS `decorator` property replaces the old decorator declarations in libRocket. A decorator is declared by the name of the decorator type and its properties in parenthesis. Some examples follow. + +```css +/* declares an image decorater by a sprite name */ +decorator: image( icon-invader ); + +/* declares a tiled-box decorater by several sprites */ +decorator: tiled-box( + window-tl, window-t, window-tr, + window-l, window-c, window-r, + window-bl, window-b, window-br +); + + /* declares an image decorator by the url of an image */ +decorator: image( invader.tga ); +``` + +The `decorator` property follows the normal cascading rules, is non-inherited, and has the default value `none` which specifies no decorator on the element. The decorator looks for a sprite with the same name first. If none exists, then it treats it as a file name for an image. Decorators can now be set on the element's style, although we recommend declaring them in style sheets for performance reasons. + +Furthermore, multiple decorators can be specified on any element by a comma-separated list of decorators. +```css +/* declares two decorators on the same element, the first will be rendered on top of the latter */ +decorator: image( icon-invader ), tiled-horizontal( title-bar-l, title-bar-c, title-bar-r ); +``` + +When creating a custom decorator, you can provide a shorthand property named `decorator` which will be used to parse the text inside the parenthesis of the property declaration. This allows specifying the decorator with inline properties as in the above examples. + + +### Decorator at-rule + +Note: This part is experimental. If it turns out there are very few use-cases for this feature, it may be removed in the future. Feedback is welcome. + +The `@decorator` at-rule in RCSS can be used to declare a decorator when the shorthand syntax given above is not sufficient. It is best served with an example, we use the custom `starfield` decorator type from the invaders sample. In the style sheet, we can populate it with properties as follows. + +```css +@decorator stars : starfield { + num-layers: 5; + top-colour: #fffc; + bottom-colour: #fff3; + top-speed: 80.0; + bottom-speed: 20.0; + top-density: 8; + bottom-density: 20; +} +``` +And then use it in a decorator. +```css +decorator: stars; +``` +Note the lack of parenthesis which means it is a decorator name and not a type with shorthand properties declared. + + +### Ninepatch decorator + +The new `ninepatch` decorator splits a sprite into a 3x3 grid of patches. The corners of the ninepatch are rendered at their native size, while the inner patches are stretched so that the whole element is filled. In a sense, it can be considered a simplified and more performant version of the `tiled-box` decorator. + +The decorator is specified by two sprites, defining an outer and inner rectangle: +```css +@spritesheet my-button { + src: button.png; + button-outer: 247px 0px 159px 45px; + button-inner: 259px 19px 135px 1px; +} +``` +The inner rectangle defines the parts of the sprite that will be stretched when the element is resized. + +The `ninepatch` decorator is applied as follows: +```css +decorator: ninepatch( button-outer, button-inner ); +``` +The two sprites must be located in the same sprite sheet. Only sprites are supported by the ninepatch decorator, image urls cannot be used. + +Furthermore, the ninepatch decorator can have the rendered size of its edges specified manually. +```css +decorator: ninepatch( button-outer, button-inner, 19px 12px 25px 12px ); +``` +The edge sizes are specified in the common `top-right-bottom-left` box order. The box shorthands are also available, e.g. a single value will be replicated to all. Percent and numbers can also be used, they will scale relative to the native size of the given edge multiplied by the current dp ratio. Thus, setting +```css +decorator: ninepatch( button-outer, button-inner, 1.0 ); +``` +is a simple approach to scale the decorators with higher dp ratios. For crisper graphics, increase the sprite sheet's pixel size at the edges and lower the rendered edge size number correspondingly. + + +### Gradient decorator + +A `gradient` decorator has been implemented with support for horizontal and vertical color gradients (thanks to @viciious). Example usage: + +```css +decorator: gradient( direction start-color stop-color ); + +direction: horizontal|vertical; +start-color: #ff00ff; +stop-color: #00ff00; +``` + + +### Tiled decorators orientation + +The orientation of each tile in the tiled decorators, `image`, `tiled-horizontal`, `tiled-vertical`, and `tiled-box`, can be rotated and flipped (thanks to @viciious). The new keywords are: +``` +none, flip-horizontal, flip-vertical, rotate-180 +``` + +Example usage: + +```css +decorator: tiled-horizontal( header-l, header-c, header-l flip-horizontal ); +``` + + +### Image decorator fit modes and alignment + +The image decorator now supports fit modes and alignment for scaling and positioning the image within its current element. + +The full RCSS specification for the `image` decorator is now +```css +decorator: image( ); +``` +where + +- ``: image source url or sprite name +- ``: none (default) \| flip-horizontal \| flip-vertical \| rotate-180 +- ``: fill (default) \| contain \| cover \| scale-none \| scale-down +- ``: left \| center (default) \| right \| \ +- ``: top \| center (default) \| bottom \| \ + +Values must be specified in the given order, any unspecified properties will be left at their default values. See the 'demo' sample for usage examples. + + +### Font-effects + +The new RCSS `font-effect` property replaces the old font-effect declarations in libRocket. A font-effect is declared similar to a decorator, by the name of the font-effect type and its properties in parenthesis. Some examples follow. + +```css +/* declares an outline font-effect with width 5px and color #f66 */ +font-effect: outline( 5px #f66 ); + +/* declares a shadow font-effect with 2px offset in both x- and y-direction, and the given color */ +font-effect: shadow( 2px 2px #333 ); +``` + +The `font-effect` property follows the normal cascading rules, is inherited, and has the default value `none` which specifies no font-effect on the element. Unlike in libRocket, font-effects can now be set on the element's style, although we recommend declaring them in style sheets for performance reasons. + +Furthermore, multiple font-effects can be specified on any element by a comma-separated list of font-effects. +```css +/* declares two font-effects on the same element */ +font-effect: shadow(3px 3px green), outline(2px black); +``` + +When creating a custom font-effect, you can provide a shorthand property named `font-effect` which will be used to parse the text inside the parenthesis of the property declaration. This allows specifying the font-effect with inline properties as in the above examples. + +There is currently no equivalent of the `@decorator` at-rule for font-effects. If there is a desire for such a feature, please provide some feedback. + +### RCSS Selectors + +The child combinator `>` is now introduced in RCSS, which can be used as in CSS to select a child of another element. +```css +p.green_theme > button { image-color: #0f0; } +``` +Here, any `button` elements which have a parent `p.green_theme` will have their image color set to green. + +Furthermore, the universal selector `*` can now be used in RCSS. This selector matches any element. +```css +div.red_theme > * > p { color: #f00; } +``` +Here, `p` grandchildren of `div.red_theme` will have their color set to red. The universal selector can also be used in combination with other selectors, such as `*.great#content:hover`. + +### Debugger improvements + +The debugger has been improved in several aspects: + +- Live updating of values. Can now see the effect of animations and other property changes. +- Can now toggle drawing of element dimension box, and live update of values. +- Can toggle whether elements are selected in user context. +- Can toggle pseudo classes on the selected element. +- Added the ability to clear the log. +- Support for transforms. The element's dimension box is drawn with the transform applied. + +### Removal of manual reference counting + +All manual reference counting has been removed in favor of smart pointers. There is no longer a need to manually decrement the reference count, such as `element->RemoveReference()` as before. This change also establishes a clear ownership of objects. For the user-facing API, this means raw pointers are non-owning, while unique and shared pointers declare ownership. Internally, there may still be uniquely owning raw pointers, as this is a work-in-progress. + +#### Core API + +The Core API takes raw pointers as before such as for its interfaces. With the new semantics, this means the library retains a non-owning reference. Thus, all construction and destruction of such objects is the responsibility of the user. Typically, the objects must stay alive until after `Core::Shutdown` is called. Each relevant function is commented with its lifetime requirements. + +As an example, the system interface can be constructed into a unique pointer. +```cpp +auto system_interface = std::make_unique(); +Rml::Core::SetSystemInterface(system_interface.get()); +Rml::Core::Initialise(); +... +Rml::Core::Shutdown(); +system_interface.reset(); +``` +Or simply from a stack object. +```cpp +MySystemInterface system_interface; +Rml::Core::SetSystemInterface(&system_interface); +Rml::Core::Initialise(); +... +Rml::Core::Shutdown(); +``` + +#### Element API + +When constructing new elements, there is again no longer a need to decrement the reference count as before. Instead, the element is returned with a unique ownership +```cpp +ElementPtr ElementDocument::CreateElement(const String& name); +``` +where `ElementPtr` is a unique pointer and an alias as follows. +```cpp +using ElementPtr = std::unique_ptr>; +``` +Note that, the custom deleter `Releaser` is there to ensure the element is released from the `ElementInstancer` in which it was created. + +After having called `ElementDocument::CreateElement`, the element can be moved into the list of children of another element. +```cpp +ElementPtr new_child = document->CreateElement("div"); +element->AppendChild( std::move(new_child) ); +``` +Since we moved `new_child`, we cannot use the pointer anymore. Instead, `Element::AppendChild` returns a non-owning raw pointer to the appended child which can be used. Furthermore, the new element can be constructed in-place, e.g. +```cpp +Element* new_child = element->AppendChild( document->CreateElement("div") ); +``` +and now `new_child` can safely be used until the element is destroyed. + +There are aliases to the smart pointers which are used internally for consistency with the library's naming scheme. +```cpp +template using UniquePtr = std::unique_ptr; +template using SharedPtr = std::shared_ptr; +``` + +### Improved transforms + +The inner workings of transforms have been completely revised, resulting in increased performance, simplified API, closer compliance to the CSS specs, and reduced complexity of the relevant parts of the library. + +Some relevant changes for users: +- Removed the need for users to set the view and projection matrices they use outside the library. +- Replaced the `PushTransform()` and `PopTransform()` render interface functions with `SetTransform()`, which is only called when the transform matrix needs to change and never called if there are no `transform` properties present. +- The `perspective` property now applies to the element's children, as in CSS. +- The transform function `perspective()` behaves like in CSS. It applies a perspective projection to the current element. +- Chaining transforms and perspectives now provides more expected results. However, as opposed to CSS we don't flatten transforms. +- Transform rotations can now be interpolated without decomposing when their rotation axes align. When the axes do not align, interpolation will be performed via decomposition (quaternion interpolation) as before. With this addition, transform interpolation should be fully compatible with the CSS specifications. +- Have a look at the updated transforms sample for some fun with 3d boxes. + + +### Focus flags, autofocus + +It is now possible to autofocus on elements when showing a document. By default, the first element with the property `tab-index: auto;` as well as the attribute `autofocus` set, will receive focus. + +The focus behavior as well as the modal state can be controlled with two new separate flags. +```cpp +ElementDocument::Show(ModalFlag modal_flag = ModalFlag::None, FocusFlag focus_flag = FocusFlag::Auto); +``` + +The flags are specified as follows: +```cpp +/** + ModalFlag used for controlling the modal state of the document. + None: Remove modal state. + Modal: Set modal state, other documents cannot receive focus. + Keep: Modal state unchanged. + + FocusFlag used for displaying the document. + None: No focus. + Document: Focus the document. + Keep: Focus the element in the document which last had focus. + Auto: Focus the first tab element with the 'autofocus' attribute or else the document. +*/ +enum class ModalFlag { None, Modal, Keep }; +enum class FocusFlag { None, Document, Keep, Auto }; +``` + + +### Font engine and interface + +The RmlUi font engine has seen a major overhaul. + +- The default font engine has been abstracted away, thereby allowing users to implement their own font engine (thanks to @viciious). See `FontEngineInterface.h` and the CMake flag `NO_FONT_INTERFACE_DEFAULT` for details. +- `font-charset` RCSS property is gone: The font interface now loads new characters as needed. Fallback fonts can be set so that unknown characters are loaded from them. +- The API and internals are now using UTF-8 strings directly, the old UCS-2 strings are ditched completely. All `String`s in RmlUi should be considered as encoded in UTF-8. +- Text string are no longer limited to 16 bit code points, thus grayscale emojis are supported, have a look at the `demo` sample for some examples. +- The internals of the default font engine has had a major overhaul, simplifying a lot of code, and removing the BitmapFont provider. +- Instead, a custom font engine interface has been implemented for bitmap fonts in the `bitmapfont` sample, serving as a quick example of how to create your own font interface. The sample should work even without the FreeType dependency. + + +### CMake options + +Three new CMake options added. + +- `NO_FONT_INTERFACE_DEFAULT` removes the default font engine, thereby allowing users to completely remove the FreeType dependency. If set, a custom font engine must be created and set through `Rml::Core::SetFontEngineInterface` before initialization. See the `bitmapfont` sample for an example implementation of a custom font engine. +- `NO_THIRDPARTY_CONTAINERS`: RmlUi now comes bundled with some third-party container libraries for improved performance. For users that would rather use the `std` counter-parts, this option is available. The option replaces the containers via a preprocessor definition. If the library is compiled with this option, then users of the library *must* specify `#define RMLUI_NO_THIRDPARTY_CONTAINERS` before including the library. +- `ENABLE_TRACY_PROFILING`: RmlUi has parts of the library tagged with markers for profiling with [Tracy Profiler](https://bitbucket.org/wolfpld/tracy/src/master/). This enables a visual inspection of bottlenecks and slowdowns on individual frames. To compile the library with profiling support, add the Tracy Profiler library to `/Dependencies/tracy/`, enable this option, and compile. Follow the Tracy Profiler instructions to build and connect the separate viewer. As users may want to only use profiling for specific compilation targets, then instead one can `#define RMLUI_ENABLE_PROFILING` for the given target. + + +### Events + +There are some changes to events in RmlUi, however, for most users, existing code should still work as before. + +There is now a distinction between actions executed in event listeners, and default actions for events: + +- Event listeners are attached to an element as before. Events follow the normal phases: capture (root -> target), target, and bubble (target -> root). Each event listener is always attached to the target phase, and is additionally attached to either the bubble phase (default) or capture phase. Listeners are executed in the order they are added to the element. Each event type specifies whether it executes the bubble phase or not, see below for details. +- Default actions are primarily for actions performed internally in the library. They are executed in the function `virtual void Element::ProcessDefaultAction(Event& event)`. However, any object that derives from `Element` can override the default behavior and add new behavior. The default actions are always executed after all event listeners, and only propagated according to the phases set in their `default_action_phase` value which is defined for each event type. If an event is interrupted with `Event::StopPropagation()`, then the default actions are not performed. + + +Each event type now has an associated EventId as well as a specification defined as follows: + +- `interruptible`: Whether the event can be cancelled by calling `Event::StopPropagation()`. +- `bubbles`: Whether the event executes the bubble phase. If true, all three phases: capture, target, and bubble, are executed. If false, only capture and target phases are executed. +- `default_action_phase`: One of: None, Target, TargetAndBubble. Specifies during which phases the default action is executed, if any. That is, the phase for which `Element::ProcessDefaultAction()` is called. See above for details. + +See `EventSpecification.cpp` for details of each event type. For example, the event type `click` has the following specification: +``` +id: EventId::Click +type: "click" +interruptible: true +bubbles: true +default_action_phase: TargetAndBubble +``` + +Whenever an event listener is added or event is dispatched, and the provided event type does not already have a specification, the default specification +`interruptible: true, bubbles: true, default_action_phase: None` is added for that event type. To provide a custom specification for a new event, first call the method: +``` +EventId Rml::Core::RegisterEventType(const String& type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase) +``` +After this call, any usage of this type will use the provided specification by default. The returned EventId can be used to dispatch events instead of the type string. + +Various changes: +- All event listeners on the current element will always be called after calling `StopPropagation()`. When propagating to the next element, the event is stopped. This behavior is consistent with the standard DOM events model. The event can be stopped immediately with `StopImmediatePropagation()`. +- `Element::DispatchEvent` can now optionally take an `EventId` instead of a `String`. +- The `resize` event now only applies to the document size, not individual elements. +- The `scrollchange` event has been replaced by a function call. To capture scroll changes, instead use the `scroll` event. +- The `textinput` event now sends a `String` in UTF-8 instead of a UCS-2 character, possibly with multiple characters. The parameter key name is changed from "data" to "text". + + +### Other features + +- `Context::ProcessMouseWheel` now takes a float value for the `wheel_delta` property, thereby enabling continuous/smooth scrolling for input devices with such support. The default scroll length for unity value of `wheel_delta` is now three times the default line-height multiplied by the current dp-ratio. +- The system interface now has two new functions for setting and getting text to and from the clipboard: `virtual void SystemInterface::SetClipboardText(const Core::String& text)` and `virtual void SystemInterface::GetClipboardText(Core::String& text)`. +- The `text-decoration` property can now also be used with `overline` and `line-through`. +- The text input and text area elements can be navigated and edited word for word by holding the Ctrl key. Can now also navigate by using Ctrl+Home/End and Page up/down. Furthermore, select all by Ctrl+A and select word by double click. +- Double clicks are now submitted only when they're inside a small radius of the first click. +- The `` element can now take sprite names in the `sprite` attribute. For images the `src` attribute can be used as before. +- The `sliderbar` on the `range` input element can now use margins to offset it from the track. + + +### Breaking changes + +Breaking changes since RmlUi 2.0. + +- RmlUi now requires a C++14-compatible compiler (previously C++11). +- Rml::Core::String has been replaced by std::string, thus, interfacing with the library now requires you to change your string types. This change was motivated by a small performance gain, additionally, it should make it easier to interface with the library especially for users already using std::string in their codebase. Furthermore, strings should be considered as encoded in UTF-8. +- To load fonts, use `Rml::Core::LoadFontFace` instead of `Rml::Core::FontDatabase::LoadFontFace`. +- Querying the property of an element for size, position and similar may not work as expected right after changes to the document or style. This change is made for performance reasons, see the description under *performance* for reasoning and a workaround. +- The Controls::DataGrid "min-rows" property has been removed. +- Removed RenderInterface::GetPixelsPerInch, instead the pixels per inch value has been fixed to 96 PPI, as per CSS specs. To achieve a scalable user interface, instead use the 'dp' unit. +- The `` element's `coords` attribute is now replaced by a `rect` attribute specified like for sprites. +- Removed 'top' and 'bottom' from z-index property. +- Angles need to be declared in either 'deg' or 'rad'. Unit-less numbers do not work. +- See changes to the declaration of decorators and font-effects above. +- See changes to the render interface regarding transforms above. +- See changes to the event system above. +- The focus flag in `ElementDocument::Show` has been changed, with a new enum name and new options, see above. +- The tiled decorators (`image`, `tiled-horizontal`, `tiled-vertical`, and `tiled-box`) no longer support the old repeat modes. +- Also, see removal of manual reference counting above. + + + + +## RmlUi 2.0 + +RmlUi 2.0 is the first release after the [original libRocket branch](https://github.com/libRocket/libRocket). + +### Transform property + +Based on the work of @shoemark, with additional fixes. + +Use `perspective`, `perspective-origin`, `transform` and `transform-origin` in RCSS, roughly equivalent to their respective CSS properties. + +```css +perspective: 1000px; +perspective-origin: 20px 50%; +transform: rotateX(10deg) skew(-10deg, 15deg) translateZ(100px); +transform-origin: left top 0; +``` + +All transform properties and their argument types are as follows: +``` +perspective, length1 +matrix, abs_numbers6 +matrix3d, abs_numbers16 +translateX, length1 +translateY, length1 +translateZ, length1 +translate, length2 +translate3d, length3 +scaleX, number1 +scaleY, number1 +scaleZ, number1 +scale, number2 +scale, number1 +scale3d, number3 +rotateX, angle1 +rotateY, angle1 +rotateZ, angle1 +rotate, angle1 +rotate3d, number3angle1 +skewX, angle1 +skewY, angle1 +skew, angle2 +``` + +Angles take units of 'deg' or 'rad'. + + + + + +### Animations + + +Most RCSS properties can be animated, this includes properties representing lengths, colors, or transforms. From C++, an animation can be started on an Element by calling + +```cpp +bool Element::Animate(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{}, int num_iterations = 1, bool alternate_direction = true, float delay = 0.0f, const Property* start_value = nullptr); +``` + +Additional animation keys can be added, extending the duration of the animation, by calling + +```cpp +bool Element::AddAnimationKey(const String& property_name, const Property& target_value, float duration, Tween tween = Tween{}); +``` + +C++ example usage: + +```cpp +auto p1 = Transform::MakeProperty({ Transforms::Rotate2D{10.f}, Transforms::TranslateX{100.f} }); +auto p2 = Transform::MakeProperty({ Transforms::Scale2D{3.f} }); +el->Animate("transform", p1, 1.8f, Tween{ Tween::Elastic, Tween::InOut }, -1, true); +el->AddAnimationKey("transform", p2, 1.3f, Tween{ Tween::Elastic, Tween::InOut }); +``` + + +Animations can also be specified entirely in RCSS, with keyframes. +```css +animation: ; +``` +All values, except `` and ``, are optional. Delay must be specified after duration, otherwise values can be given in any order. Keyframes are specified as in CSS, see example below. Multiple animations can be specified on the same element by using a comma-separated list. + +Tweening functions (or in CSS lingo, `animation-timing-function`s) specify how the animated value progresses during the animation cycle. A tweening function in RCSS is specified as `-in`, `-out`, or `-in-out`, with one of the following names, +``` +back +bounce +circular +cubic +elastic +exponential +linear +quadratic +quartic +quintic +sine +``` + +RCSS example usage: + +```css +@keyframes my-progress-bar +{ + 0%, 30% { + background-color: #d99; + } + 50% { + background-color: #9d9; + } + to { + background-color: #f9f; + width: 100%; + } +} +#my_element +{ + width: 25px; + animation: 2s cubic-in-out infinite alternate my-progress-bar; +} +``` + +Internally, animations apply their properties on the local style of the element. Thus, mixing RML style attributes and animations should be avoided on the same element. + +Animations currently support full interpolation of transforms, largely following the CSS specifications. Additionally, interpolation is supported for colors, numbers, lengths, and percentages. + +Animations are very powerful coupled with transforms. See the animation sample project for more examples and details. There are also some [video demonstrations](https://mikke89.github.io/RmlUiDoc/pages/rcss/animations_transitions_transforms.html) of these features in the documentation. + + +### Transitions + +Transitions apply an animation between two property values on an element when its property changes. Transitions are implemented in RCSS similar to how they operate in CSS. However, in RCSS, they only apply when a class or pseudo-class is added to or removed from an element. + +```css +transition: ; +``` +The property list specifies the properties to be animated. Delay and tweening-function are optional. Delay must be specified after duration, otherwise values can be given in any order. Multiple transitions can be specified on the same element by using a comma-separated list. The tweening function is specified as in the `animation` RCSS property. + + +Example usage: + +```css +#transition_test { + transition: padding-left background-color transform 1.6s elastic-out; + transform: scale(1.0); + background-color: #c66; +} +#transition_test:hover { + padding-left: 60px; + transform: scale(1.5); + background-color: #ddb700; +} +``` + +See the animation sample project for more examples and details. + + +### Density-independent pixel (dp) + +The `dp` unit behaves like `px` except that its size can be set globally to scale relative to pixels. This makes it easy to achieve a scalable user interface. Set the ratio globally on the context by calling: + +```cpp +float dp_ratio = 1.5f; +context->SetDensityIndependentPixelRatio(dp_ratio); +``` + +Usage example in RCSS: +```css +div#header +{ + width: 800dp; + height: 50dp; + font-size: 20dp; +} +``` + + +### Pointer events + +Set the element property to disregard mouse input events on this and descending elements. +```css +pointer-events: none; +``` +Default is `auto`. + + +### Image-color property + +Non-standard RCSS property which multiplies a color with images in `` tags and image decorators. Useful for `:hover`-events and for applying transparency. +```css +image-color: rgba(255, 160, 160, 200); +icon-decorator: image; +icon-image: background.png 34px 0px 66px 28px; +``` + + +### Inline-block + +Unlike the original branch, elements with +```css +display: inline-block; +``` +will shrink to the width of their content, like in CSS. + + + +### Border shorthand + +Enables the `border` property shorthand. +```css +border: 4px #e99; +``` + + +### Various features + +- The slider on the `input.range` element can be dragged from anywhere in the element. +- The `:checked` pseudo class can be used to style the selected item in drop-down lists. + + +### Breaking changes + +- The namespace has changed from `Rocket` to `Rml`, include path from `` to ``, and macro prefix from `ROCKET_` to `RMLUI_`. +- `Rml::Core::SystemInterface::GetElapsedTime()` now returns `double` instead of `float`. +```cpp +virtual double GetElapsedTime(); +``` +- The `font-size` property no longer accepts a unit-less ``, instead add the `px` unit for equivalent behavior. The new behavior is consistent with CSS. +- The old functionality for setting and drawing mouse cursors has been replaced by a new function call to the system interface, thereby allowing the user to set the system cursor. +- Python support has been removed. diff --git a/thirdparty/RmlUi/readme.md b/thirdparty/RmlUi/readme.md new file mode 100644 index 000000000..cae49ec05 --- /dev/null +++ b/thirdparty/RmlUi/readme.md @@ -0,0 +1,190 @@ +# RmlUi - The HTML/CSS User Interface Library Evolved + +![RmlUi](https://github.com/mikke89/RmlUiDoc/raw/cc01edd834b003df6c649967bfd552bb0acc3d1e/assets/rmlui.png) + +RmlUi - now with added boosters taking control of the rocket, targeting *your* games and applications. + +--- + +[![Chat on Gitter](https://badges.gitter.im/RmlUi/community.svg)](https://gitter.im/RmlUi/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build Status](https://travis-ci.com/mikke89/RmlUi.svg?branch=master)](https://travis-ci.com/mikke89/RmlUi) [![Build status](https://ci.appveyor.com/api/projects/status/x95oi8mrb001pqhh/branch/master?svg=true)](https://ci.appveyor.com/project/mikke89/rmlui/branch/master) + +RmlUi is the C++ user interface package based on the HTML and CSS standards, designed as a complete solution for any project's interface needs. It is a fork of the [libRocket](https://github.com/libRocket/libRocket) project, introducing new features, bug fixes, and performance improvements. + +RmlUi uses the time-tested open standards XHTML1.0 and CSS2.0 while borrowing features from HTML5 and CSS3, and extends them with features suited towards real-time applications. Because of this, you don't have to learn a whole new proprietary technology like other libraries in this space. Please have a look at the supported [RCSS properties](https://mikke89.github.io/RmlUiDoc/pages/rcss/property_index.html) and [RML elements](https://mikke89.github.io/RmlUiDoc/pages/rml/element_index.html). + +Documentation is located at https://mikke89.github.io/RmlUiDoc/ + +***Note:*** RmlUi 4.0 currently in development is a restructuring of RmlUi 3.x. This includes changes to the namespaces, plugins, and include headers. Take a look at the [changelog](changelog.md#restructuring-rmlui) for a summary of changes and an upgrade guide. + +## Features + +- Cross platform architecture: Windows, macOS, Linux, iOS, etc. +- Dynamic layout system. +- Full animation and transform support. +- Efficient application-wide styling, with a custom-built templating engine. +- Fully featured control set: buttons, sliders, drop-downs, etc. +- Runtime visual debugging suite. + +## Extensible + +- Abstracted interfaces for plugging in to any game engine. +- Decorator engine allowing custom application-specific effects that can be applied to any element. +- Generic event system that binds seamlessly into existing projects. +- Easily integrated and extensible with Lua scripting. + +## Controllable + +- The user controls their own update loop, calling into RmlUi as desired. +- The library strictly runs as a result of calls to its API, never in the background. +- Input handling and rendering is performed by the user. +- The library generates vertices, indices, and textures for the user to render how they like. +- File handling and the font engine can optionally be fully replaced by the user. + + +## Integrating RmlUi + +Here are the general steps to integrate the library into a C++ application, have a look at the [documentation](https://mikke89.github.io/RmlUiDoc/) for details. + +1. Build RmlUi using CMake and your favorite compiler, or fetch the Windows library binaries. +2. Link it up to your application. +3. Implement the abstract [system interface](Include/RmlUi/Core/SystemInterface.h) and [render interface](Include/RmlUi/Core/RenderInterface.h). +4. Initialize RmlUi with the interfaces, create a context, provide font files, and load a document. +5. Call into the context's update and render methods in a loop, and submit input events. +6. Compile and run! + +Several [samples](Samples/) demonstrate everything from basic integration to more complex use of the library, feel free to have a look for inspiration. + +## Dependencies + +- [FreeType](https://www.freetype.org/). However, it can be fully replaced by a custom [font engine](Include/RmlUi/Core/FontEngineInterface.h). +- The standard library. + +In addition, a C++14 compatible compiler is required. + + +## Example: Basic document + +In this example a document is created using a templated window. The template is optional but can aid in achieving a consistent look by sharing it between multiple documents. + +#### Document + +`hello_world.rml` + +```html + + + Hello world + + + + + Hello world! + + +``` + +#### Window template + +`window.rml` + +```html + +``` +No styles are defined internally, thus `rml.rcss` can be included for [styling the standard elements](Samples/assets/rml.rcss). + +#### Style sheet + +`window.rcss` + +```css +body +{ + font-family: Delicious; + font-weight: normal; + font-style: normal; + font-size: 15px; + color: #6f42c1; + background: #f6f8fa; + text-align: center; + padding: 2em 3em; + border: 2px #ccc; +} + +#title_header +{ + color: #9a42c5; + font-size: 1.5em; + font-weight: bold; + padding-bottom: 1em; +} +``` + +#### Rendered output + +![Hello world document](Samples/assets/hello_world.png) + + + +## Gallery + + +![Game interface](https://github.com/mikke89/RmlUiDoc/blob/3f319d8464e73b821179ff8d20537013af5b9810/assets/gallery/invader.png) +**Game interface from the 'invader' sample** + +![Game menu](https://github.com/mikke89/RmlUiDoc/blob/3f319d8464e73b821179ff8d20537013af5b9810/assets/gallery/menu_screen.png) +**Game menu** + +![Form controls](https://github.com/mikke89/RmlUiDoc/blob/3f319d8464e73b821179ff8d20537013af5b9810/assets/gallery/forms.png) +**Form controls from the 'demo' sample** + +![Sandbox](https://github.com/mikke89/RmlUiDoc/blob/3f319d8464e73b821179ff8d20537013af5b9810/assets/gallery/sandbox.png) +**Sandbox from the 'demo' sample, try it yourself!** + +![Transition](https://github.com/mikke89/RmlUiDoc/blob/3f319d8464e73b821179ff8d20537013af5b9810/assets/gallery/transition.gif) +**Transitions on mouse hover (entirely in RCSS)** + +![Transform](https://github.com/mikke89/RmlUiDoc/blob/3f319d8464e73b821179ff8d20537013af5b9810/assets/gallery/transform.gif) +**Animated transforms (entirely in RCSS)** + +To see more examples of animations and transitions in action, have a look at the videos in the [animations documentation](https://mikke89.github.io/RmlUiDoc/pages/rcss/animations_transitions_transforms.html). + + + +## License (MIT) + +Copyright (c) 2008-2014 CodePoint Ltd, Shift Technology Ltd, and contributors\ +Copyright (c) 2019 The RmlUi Team, and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.