label{font-size:20dp;letter-spacing:2.8dp;line-height:20dp;font-style:normal;font-weight:700;text-transform:uppercase}.config-option__details{font-size:18dp;letter-spacing:2.52dp;line-height:18dp;font-style:normal;font-weight:400}body,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.config__wrapper p{font-size:20dp;letter-spacing:0dp;line-height:20dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.prompt-font-sm,.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.nav-vert,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto}.nav-horiz,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-right:auto;nav-left:auto}.nav-foc,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}h1{font-size:68dp;letter-spacing:4.76dp;line-height:68dp;font-style:normal;font-weight:700}h2{font-size:52dp;letter-spacing:3.64dp;line-height:52dp;font-style:normal;font-weight:700}h3,.tab{font-size:36dp;letter-spacing:2.52dp;line-height:36dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:36dp;letter-spacing:3.96dp;line-height:36dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:28dp;letter-spacing:3.08dp;line-height:28dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label,.centered-page__controls>label{font-size:20dp;letter-spacing:2.8dp;line-height:20dp;font-style:normal;font-weight:700;text-transform:uppercase}.config-option__details{font-size:18dp;letter-spacing:2.52dp;line-height:18dp;font-style:normal;font-weight:400}body,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.config__wrapper p{font-size:20dp;letter-spacing:0dp;line-height:20dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.prompt-font-sm,.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.nav-vert,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto}.nav-horiz,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-right:auto;nav-left:auto}.nav-foc,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}*{box-sizing:border-box}hr{display:block;background:#000;padding:1.5dp}body{font-family:chiaro;font-weight:normal;font-style:normal;font-size:20dp;color:#fff}div#window{position:relative;width:100%;height:100%;box-sizing:border-box;background-color:#121018;border-color:rgba(255,255,255,.2)}div#content{z-index:2;width:auto;height:100%;overflow:hidden auto;text-align:center}p{text-align:left}input.submit{margin-left:0}input.text,input.password{box-sizing:border-box;height:31dp;padding:11dp 10dp 0;cursor:text;text-align:left}textarea{padding:14dp 12dp 10dp;cursor:text;text-align:left}input.text,input.password,select,textarea{height:auto}table input.text{box-sizing:border-box;width:100%;margin:0;line-height:1;border-width:1.1dp;border-color:#000;background-color:#fff;font-size:15dp;decorator:none;height:auto}input.radio,input.checkbox{flex:0;tab-index:auto;focus:auto;nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto;width:0dp}scrollbarvertical,scrollbarhorizontal{margin:0;border:0}scrollbarvertical slidertrack,scrollbarhorizontal slidertrack{background:#dabaf7;opacity:.05}scrollbarvertical sliderbar,scrollbarhorizontal sliderbar{border-radius:5dp;background:#dabaf7;opacity:.1}scrollbarvertical sliderbar:hover:not(:active),scrollbarhorizontal sliderbar:hover:not(:active){opacity:.2}scrollbarvertical sliderbar:active,scrollbarhorizontal sliderbar:active{opacity:.3}scrollbarvertical sliderarrowdec,scrollbarvertical sliderarrowinc,scrollbarhorizontal sliderarrowdec,scrollbarhorizontal sliderarrowinc{width:0;height:0}scrollbarvertical{width:12dp}scrollbarvertical slidertrack{width:12dp}scrollbarvertical sliderbar{width:12dp}scrollbarhorizontal{height:12dp}scrollbarhorizontal slidertrack{height:12dp}scrollbarhorizontal sliderbar{height:12dp}.centered-page{display:flex;position:absolute;top:0;right:0;bottom:0;left:0;padding:64dp;background-color:rgba(255,255,255,.1)}.centered-page__modal{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%;background:rgba(8,7,13,.9);border-radius:16dp;border-color:rgba(255,255,255,.2);border-width:1.1dp}.centered-page__modal>.tabs{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%}.centered-page__modal panels{flex:1 1 100%}.centered-page__controls{display:flex;flex-direction:row;position:absolute;align-items:center;justify-content:center;height:auto;bottom:24dp;margin:0 auto;width:100%;max-width:1692.4444444444dp}.centered-page__controls>label{display:inline-block;align-items:center;justify-content:space-between;width:auto;height:24dp}.centered-page__controls>label:not(:last-child){margin-right:40dp}.centered-page__controls>label>span:first-child{margin-right:4dp}.control-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;width:100%;height:auto;padding:4dp 16dp 4dp 20dp;border-radius:8dp;background-color:rgba(0,0,0,0)}.control-option svg{image-color:#ccc}.control-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option:focus-visible:not(:disabled,[disabled]),.control-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.control-option:focus-visible:not(:disabled,[disabled]) svg,.control-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.control-option:disabled,.control-option[disabled]{opacity:.5}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"]{border-color:#f86039}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-icon{opacity:0}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-recording{opacity:1}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"]{border-color:#f86039}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-icon{opacity:0}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-recording{opacity:1}.control-option .icon-button{flex:1 1 auto}.control-option__label{flex:2 1 300dp;height:auto;white-space:nowrap}.control-option__bindings{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;flex:2 1 400dp;width:100%;height:56dp;padding:0 12dp 0 4dp}.control-option__binding{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;position:relative;align-items:center;justify-content:center;margin:0 4dp;flex:1 1 100%;width:100%;height:56dp;padding:8dp;background-color:rgba(190,184,219,.1);border-color:rgba(190,184,219,.1);border-width:1.1dp;border-radius:8dp}.control-option__binding svg{image-color:#ccc}.control-option__binding svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option__binding:focus,.control-option__binding:hover{color:#f2f2f2;background-color:rgba(255,255,255,.1);border-color:#f2f2f2}.control-option__binding:focus svg,.control-option__binding:hover svg{image-color:#f2f2f2}.control-option__binding:active{color:#f5f5f5}.control-option__binding:active svg{image-color:#f5f5f5}.control-option__binding:disabled,.control-option__binding[disabled]{color:#ccc;opacity:.5}.control-option__binding:disabled svg,.control-option__binding[disabled] svg{image-color:#ccc}.control-option__binding:not([disabled]){cursor:pointer}.control-option__binding-icon{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;opacity:1}@keyframes control-option__binding-recording-scale{0%{transform:scale(1)}50%{transform:scale(0.85)}to{transform:scale(1)}}.control-option__binding-recording{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:absolute;display:flex;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0;opacity:0}.control-option__binding-recording .control-option__binding-circle{width:24dp;height:24dp;background-color:#f86039;border-radius:24dp;animation:1.5s sine-in-out infinite control-option__binding-recording-scale}.control-option__binding-recording .control-option__binding-edge{position:absolute;transform:translate(-50%, -50%);top:50%;left:50%;width:36dp;height:36dp}.control-option__binding-recording .control-option__binding-edge>svg.control-option__binding-edge-svg{width:36dp;height:36dp;image-color:#f86039}.tabs tabs{display:flex;flex-direction:row;align-items:center;justify-content:flex-start}.tab{display:block;position:relative;padding:20dp 24dp;background-color:rgba(0,0,0,0);margin:0;color:rgba(255,255,255,.6);transition:color .05s linear-in-out;opacity:.9}.tab:selected{color:#f2f2f2}.tab:selected .tab__indicator{background-color:rgba(255,255,255,.6)}.tab:selected:hover{cursor:default}.rmlui-window:not([mouse-active]) .tab:focus{animation:blue-pulse .75s infinite}.rmlui-window:not([mouse-active]) .tab:focus:selected .tab__indicator{animation:blue-pulse-background .75s infinite}.tab:focus,.tab:hover{cursor:pointer;color:#f2f2f2;opacity:1}.tab__indicator{position:absolute;background-color:rgba(0,0,0,0);right:0;bottom:2dp;left:0;height:2dp}.config__exit-button{position:absolute;top:8dp;right:8dp}.config__form{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;display:flex;flex-direction:column;justify-content:space-between;flex:1 1 100%;width:100%;height:100%;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__wrapper{border-radius:0dp;flex:1 1 100%;height:100%;padding:16dp;text-align:left;background-color:rgba(0,0,0,.35)}.config__wrapper p{padding:16dp;white-space:pre-line;line-height:28dp}.config__wrapper p b{color:#b97df2}.config__hz-wrapper{display:flex;flex-direction:row;border-radius:0dp;flex:1 1 100%;height:100%;text-align:left}.config__header,.config__footer{display:flex;justify-content:space-between;align-items:center;width:100%;background-color:rgba(0,0,0,.35)}.config__header{border-bottom-color:rgba(255,255,255,.1);border-bottom-width:1.1dp;padding:12dp 20dp}.config__footer{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;padding:20dp 20dp;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__header-left{display:flex;flex-direction:row;flex:1 1 auto}.config__header-left>:not(:first-child){margin-left:8dp}.config__row{display:flex;flex-direction:row}.config-option{display:flex;flex-direction:column;flex:1;align-items:flex-start;justify-content:flex-start;margin:16dp 0dp 24dp}.config-option:last-child{margin-top:16dp}.config-option__title{padding:0 12dp}.config-option__list{display:flex;padding:0;flex-direction:row;width:100%;height:auto;align-items:flex-start;justify-content:flex-start}.config-option__list input:first-of-type{nav-left:none}.config-option__list input:last-of-type{nav-right:none}.config-option__list .config-option__tab-label{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:block;position:relative;padding:8dp 0;height:auto;margin:4dp 12dp 0;color:rgba(255,255,255,.6);tab-index:none}.config-option__list .config-option__tab-label:hover{cursor:pointer;color:#f2f2f2}.config-option__list input.radio{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;visibility:visible;width:0;height:0}.config-option__list input.radio:not(:disabled):checked+.config-option__tab-label{border-bottom:1dp;border-color:#f2f2f2;color:#f2f2f2}.config-option__list input.radio:not(:disabled):checked+.config-option__tab-label:hover{cursor:default}.rmlui-window:not([mouse-active]) .config-option__list input.radio:not(:disabled):focus+.config-option__tab-label{animation:blue-pulse .75s infinite;color:#17d6e8;border-color:#17d6e8}.config-option__list input.radio:not(:disabled):focus+.config-option__tab-label,.config-option__list input.radio:not(:disabled):hover+.config-option__tab-label{color:#f2f2f2}.config-option__list input.radio:disabled+.config-option__tab-label{opacity:.5}.config-option__list input.radio:disabled+.config-option__tab-label:hover{cursor:default}.config-option__list input.range slidertrack{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-top:7dp;height:2dp;background-color:rgba(255,255,255,.2)}.config-option__list input.range sliderbar{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-left:-8dp;margin-right:-6dp;width:16dp;height:16dp;background-color:#ccc;border-radius:8dp;transition:background-color .05s linear-in-out}.rmlui-window:not([mouse-active]) .config-option__list input.range sliderbar:focus{border-color:#33f;border-width:1.1dp;animation:blue-pulse-background .75s infinite}.config-option__list input.range sliderbar:hover{cursor:pointer;background-color:#f2f2f2}.config-option__list input.range sliderbar:active,.config-option__list input.range slidertrack:active+sliderbar{background-color:#17d6e8}.config-option__list input.range sliderarrowdec,.config-option__list input.range sliderarrowinc{display:none}.config-option__details{color:#b97df2;margin:14dp 12dp 0;height:18dp}.config-option__range-wrapper{margin-top:4dp;max-width:360dp}.config-option__range-label{flex:0 0 16dp;display:block;padding:0;margin:0 12dp;margin-right:16dp;color:#f2f2f2;tab-index:none}.input-config{padding:0}.input-config__horizontal-split{display:flex;position:relative;flex-direction:row;height:100%}.input-config__mappings{display:block;flex:1 1 auto;height:100%;min-width:640dp}.input-config__mappings-scroll{display:block;width:100%;max-height:100%;overflow-y:auto}.input-config__mappings-wrapper{padding:8dp}.input-config__visual-wrapper{display:block;width:auto;height:auto;max-width:1040.4444444444dp;max-height:780.3333333333dp;margin:auto 0;flex:1 1 100%}.input-config__visual-aspect{position:relative;width:100%;padding-bottom:75%;background-color:rgba(0,0,0,.35);margin:auto 0}.input-config__visual{display:flex;flex-direction:column;position:absolute;top:16dp;right:16dp;bottom:16dp;left:16dp;border-radius:108dp;background-color:rgba(255,255,255,.05)}.input-config__visual-half{display:flex;position:relative;flex-direction:row;flex:1 1 100%;padding:6%}.input-config__visual-half--bottom{align-items:flex-end;justify-content:space-between}.input-config__visual-quarter-left{display:flex;flex:1 1 50%;width:auto;align-items:flex-start;justify-content:flex-start}.input-config__visual-quarter-right{display:flex;flex:1 1 100%;align-items:flex-start;justify-content:flex-end}.input-config__visual-stick-wrapper{display:flex;position:absolute;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0}.input-viz{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:relative;display:flex;align-items:center;justify-content:center}.input-viz>svg:not(.input-viz__dpad-arrow){position:absolute;top:0;right:0;left:0;bottom:0}[cur-input=NONE] .input-viz[visual-input]{opacity:1}.input-viz[visual-input~=A]{opacity:.25}[cur-input=A] .input-viz[visual-input~=A]{opacity:1}.input-viz[visual-input~=B]{opacity:.25}[cur-input=B] .input-viz[visual-input~=B]{opacity:1}.input-viz[visual-input~=Z]{opacity:.25}[cur-input=Z] .input-viz[visual-input~=Z]{opacity:1}.input-viz[visual-input~=START]{opacity:.25}[cur-input=START] .input-viz[visual-input~=START]{opacity:1}.input-viz[visual-input~=DPAD_UP]{opacity:.25}[cur-input=DPAD_UP] .input-viz[visual-input~=DPAD_UP]{opacity:1}.input-viz[visual-input~=DPAD_DOWN]{opacity:.25}[cur-input=DPAD_DOWN] .input-viz[visual-input~=DPAD_DOWN]{opacity:1}.input-viz[visual-input~=DPAD_LEFT]{opacity:.25}[cur-input=DPAD_LEFT] .input-viz[visual-input~=DPAD_LEFT]{opacity:1}.input-viz[visual-input~=DPAD_RIGHT]{opacity:.25}[cur-input=DPAD_RIGHT] .input-viz[visual-input~=DPAD_RIGHT]{opacity:1}.input-viz[visual-input~=L]{opacity:.25}[cur-input=L] .input-viz[visual-input~=L]{opacity:1}.input-viz[visual-input~=R]{opacity:.25}[cur-input=R] .input-viz[visual-input~=R]{opacity:1}.input-viz[visual-input~=C_UP]{opacity:.25}[cur-input=C_UP] .input-viz[visual-input~=C_UP]{opacity:1}.input-viz[visual-input~=C_DOWN]{opacity:.25}[cur-input=C_DOWN] .input-viz[visual-input~=C_DOWN]{opacity:1}.input-viz[visual-input~=C_LEFT]{opacity:.25}[cur-input=C_LEFT] .input-viz[visual-input~=C_LEFT]{opacity:1}.input-viz[visual-input~=C_RIGHT]{opacity:.25}[cur-input=C_RIGHT] .input-viz[visual-input~=C_RIGHT]{opacity:1}.input-viz[visual-input~=X_AXIS_NEG]{opacity:.25}[cur-input=X_AXIS_NEG] .input-viz[visual-input~=X_AXIS_NEG]{opacity:1}.input-viz[visual-input~=X_AXIS_POS]{opacity:.25}[cur-input=X_AXIS_POS] .input-viz[visual-input~=X_AXIS_POS]{opacity:1}.input-viz[visual-input~=Y_AXIS_NEG]{opacity:.25}[cur-input=Y_AXIS_NEG] .input-viz[visual-input~=Y_AXIS_NEG]{opacity:1}.input-viz[visual-input~=Y_AXIS_POS]{opacity:.25}[cur-input=Y_AXIS_POS] .input-viz[visual-input~=Y_AXIS_POS]{opacity:1}.input-viz__button{color:#f2f2f2}.input-viz__button svg{image-color:#f2f2f2}.input-viz__button--sm{width:64dp;height:64dp}.input-viz__button--sm>svg{width:64dp;height:64dp}.input-viz__button--md{width:76dp;height:76dp}.input-viz__button--md>svg{width:76dp;height:76dp}.input-viz__button--lg{width:84dp;height:84dp}.input-viz__button--lg>svg{width:84dp;height:84dp}.input-viz__button--C svg{image-color:#e9cd35}.input-viz__button--A{margin-top:auto}.input-viz__button--A svg{image-color:#33f}.input-viz__button--B svg{image-color:#45d043}.input-viz__button--Start svg{image-color:#f86039}.input-viz__Z{width:136dp;height:136dp}.input-viz__Z svg{image-color:#e9cd35}.input-viz__Z>svg{width:136dp;height:136dp}.input-viz.input-viz__dpad{width:192dp;height:192dp;position:relative}.input-viz.input-viz__dpad svg{image-color:#f2f2f2}.input-viz.input-viz__dpad>svg{width:192dp;height:192dp}.input-config__visual-stick{display:flex;position:relative;align-items:center;justify-content:center;width:200dp;height:200dp;border-radius:100dp;background-color:rgba(255,255,255,.05)}.input-viz__dpad-split,.input-viz__stick-split{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;width:100%;height:100%}.input-viz__dpad-split--vertical,.input-viz__stick-split--vertical{flex-direction:column;align-items:center;justify-content:space-between}.input-viz__dpad-split--horizontal,.input-viz__stick-split--horizontal{flex-direction:row;align-items:center;justify-content:space-between}.input-viz__dpad-split>div,.input-viz__stick-split>div{display:flex;flex:1 1 100%;align-items:center;justify-content:center;flex-direction:row}.input-viz__dpad-split>div{width:64dp;height:64dp}.input-viz__stick-split>div{width:66.6666666667dp;height:66.6666666667dp}.input-viz__dpad-arrow{position:absolute;width:60dp;height:60dp}.input-viz__dpad-arrow--up{top:4dp;margin:0 auto}.input-viz__dpad-arrow--down{bottom:4dp;margin:0 auto;transform:rotate(180deg)}.input-viz__dpad-arrow--left{left:4dp;margin:auto 0;transform:rotate(-90deg)}.input-viz__dpad-arrow--right{right:4dp;margin:auto 0;transform:rotate(90deg)}.input-viz__R{width:96dp;height:96dp}.input-viz__R svg{image-color:#fff}.input-viz__R>svg{width:96dp;height:96dp}.input-viz__L{width:136dp;height:136dp}.input-viz__L svg{image-color:#17d6e8}.input-viz__L>svg{width:136dp;height:136dp}.input-config__c-buttons{position:relative;width:208dp;height:132dp}.input-config__c-buttons-lr,.input-config__c-buttons-du{display:flex;position:absolute;top:0;right:0;left:0;bottom:0}.input-config__c-buttons-lr{flex-direction:row;align-items:flex-start;justify-content:space-between}.input-config__c-buttons-du{flex-direction:column-reverse;align-items:center;justify-content:space-between}.input-config__c-buttons .input-viz[visual-input=C_UP]{margin-top:-32dp}.input-config__main-buttons{display:flex;flex-direction:row;justify-content:space-between;width:268dp;height:128dp;position:relative;margin-right:10dp}.button{background-color:rgba(185,125,242,.05);color:#ccc;border-color:rgba(185,125,242,.8);transition:color .05s linear-in-out,background-color .05s linear-in-out;display:block;padding:23dp;border-radius:12dp;border-width:1.1dp;width:auto;height:auto}.button:focus,.button:hover{color:#f2f2f2;border-color:#b97df2;background-color:rgba(185,125,242,.3)}.button:disabled,.button[disabled]{color:rgba(255,255,255,.6)}.button:active{background-color:rgba(185,125,242,.2);color:#f5f5f5}.button--secondary{background-color:rgba(23,214,232,.05);color:#ccc;border-color:rgba(23,214,232,.8)}.button--secondary:focus,.button--secondary:hover{color:#f2f2f2;border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.button--secondary:disabled,.button--secondary[disabled]{color:rgba(255,255,255,.6)}.button--secondary:active{background-color:rgba(23,214,232,.2);color:#f5f5f5}.button--tertiary{background-color:rgba(242,242,242,.05);color:#ccc;border-color:rgba(242,242,242,.8)}.button--tertiary:focus,.button--tertiary:hover{color:#f2f2f2;border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.button--tertiary:disabled,.button--tertiary[disabled]{color:rgba(255,255,255,.6)}.button--tertiary:active{background-color:rgba(242,242,242,.2);color:#f5f5f5}.button--success{background-color:rgba(69,208,67,.05);color:#ccc;border-color:rgba(69,208,67,.8)}.button--success:focus,.button--success:hover{color:#f2f2f2;border-color:#45d043;background-color:rgba(69,208,67,.3)}.button--success:disabled,.button--success[disabled]{color:rgba(255,255,255,.6)}.button--success:active{background-color:rgba(69,208,67,.2);color:#f5f5f5}.button--error{background-color:rgba(248,96,57,.05);color:#ccc;border-color:rgba(248,96,57,.8)}.button--error:focus,.button--error:hover{color:#f2f2f2;border-color:#f86039;background-color:rgba(248,96,57,.3)}.button--error:disabled,.button--error[disabled]{color:rgba(255,255,255,.6)}.button--error:active{background-color:rgba(248,96,57,.2);color:#f5f5f5}.button--warning{background-color:rgba(233,205,53,.05);color:#ccc;border-color:rgba(233,205,53,.8)}.button--warning:focus,.button--warning:hover{color:#f2f2f2;border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.button--warning:disabled,.button--warning[disabled]{color:rgba(255,255,255,.6)}.button--warning:active{background-color:rgba(233,205,53,.2);color:#f5f5f5}.button:not([disabled]){cursor:pointer}.button:disabled,.button[disabled]{opacity:.5}.button__label{width:auto;height:auto}.icon-button{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;overflow:hidden;border-radius:26.9dp;border-width:1.1dp;border-color:rgba(0,0,0,0);background-color:rgba(0,0,0,0);width:53.8dp;height:53.8dp;min-width:53.8dp;min-height:53.8dp;max-width:53.8dp;max-height:53.8dp}.icon-button svg{image-color:#ccc}.icon-button svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.icon-button:focus,.icon-button:hover{color:#f2f2f2;background-color:rgba(255,255,255,.2)}.icon-button:focus svg,.icon-button:hover svg{image-color:#f2f2f2}.icon-button:active{color:#f5f5f5;background-color:rgba(255,255,255,.1)}.icon-button:active svg{image-color:#f5f5f5}.icon-button:disabled,.icon-button[disabled]{color:#ccc;opacity:.5}.icon-button:disabled svg,.icon-button[disabled] svg{image-color:#ccc}.icon-button:not([disabled]){cursor:pointer}.icon-button svg{width:32dp;height:32dp}.icon-button--primary{background-color:rgba(185,125,242,.05);border-color:rgba(185,125,242,.8)}.icon-button--primary:focus,.icon-button--primary:hover{border-color:#b97df2;background-color:rgba(185,125,242,.3)}.icon-button--primary:active{background-color:rgba(185,125,242,.2)}.icon-button--secondary{background-color:rgba(23,214,232,.05);border-color:rgba(23,214,232,.8)}.icon-button--secondary:focus,.icon-button--secondary:hover{border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.icon-button--secondary:active{background-color:rgba(23,214,232,.2)}.icon-button--tertiary{background-color:rgba(242,242,242,.05);border-color:rgba(242,242,242,.8)}.icon-button--tertiary:focus,.icon-button--tertiary:hover{border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.icon-button--tertiary:active{background-color:rgba(242,242,242,.2)}.icon-button--success{background-color:rgba(69,208,67,.05);border-color:rgba(69,208,67,.8)}.icon-button--success:focus,.icon-button--success:hover{border-color:#45d043;background-color:rgba(69,208,67,.3)}.icon-button--success:active{background-color:rgba(69,208,67,.2)}.icon-button--danger{background-color:rgba(248,96,57,.05);border-color:rgba(248,96,57,.8)}.icon-button--danger:focus,.icon-button--danger:hover{border-color:#f86039;background-color:rgba(248,96,57,.3)}.icon-button--danger:active{background-color:rgba(248,96,57,.2)}.icon-button--warning{background-color:rgba(233,205,53,.05);border-color:rgba(233,205,53,.8)}.icon-button--warning:focus,.icon-button--warning:hover{border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.icon-button--warning:active{background-color:rgba(233,205,53,.2)}.launcher{display:block;flex-direction:row;justify-content:space-between;position:relative;width:100%;height:100%;background-color:#08070d}.launcher__vertical-split{display:flex;position:absolute;flex-direction:column;align-items:flex-start;justify-content:space-between;top:0;right:50%;bottom:0;left:0}.launcher__vertical-split--right{align-items:flex-end;right:0;left:50%}@keyframes slide-mm-bg-over{0%{transform:translateX(100dp)}to{transform:translateX(0dp)}}.launcher__background-wrapper{display:flex;align-items:center;justify-content:flex-start;position:absolute;left:-70vw;right:-100%;top:-55vw;bottom:-50vw;transform:translateX(0dp);animation:25s cubic-out 1 slide-mm-bg-over}@keyframes fade-mm-in{0%{opacity:0}to{opacity:.1}}.launcher__background-mm{position:absolute;left:0;top:0;bottom:0;height:100%;width:auto;opacity:.1;animation:2.5s cubic-in-out 1 fade-mm-in}.launcher__title-quadrant{flex:1 1 auto;padding-top:96dp;padding-left:96dp;width:auto;height:auto}.launcher__title-quadrant--right{padding-right:96dp;padding-left:0}.launcher__content-quadrant{display:flex;position:relative;flex-direction:column;align-items:flex-start;justify-content:flex-end;padding:32dp;width:100%;height:auto;flex:1 1 100%}.menu-list-item{color:#ccc;display:flex;flex-direction:row;align-items:center;width:100%;height:auto;padding:16dp;border-radius:8dp;background-color:rgba(0,0,0,0);cursor:pointer}.menu-list-item svg{image-color:#ccc}.menu-list-item--right{align-content:flex-end;flex-direction:row-reverse}.menu-list-item--right .menu-list-item__bullet{opacity:1;margin-left:12dp}.menu-list-item--right.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item--right.menu-list-item:hover:not(:disabled,[disabled]){decorator:gradient(horizontal #7A2AC600 #DABAF714)}.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item:hover:not(:disabled,[disabled]){color:#b97df2;decorator:gradient(horizontal #7A2AC614 #DABAF700)}.menu-list-item:focus:not(:disabled,[disabled]) svg,.menu-list-item:hover:not(:disabled,[disabled]) svg{image-color:#b97df2}.menu-list-item:focus:not(:disabled,[disabled]) .menu-list-item__bullet,.menu-list-item:hover:not(:disabled,[disabled]) .menu-list-item__bullet{opacity:1}.menu-list-item:disabled,.menu-list-item[disabled]{opacity:.5;tab-index:none;cursor:default}.menu-list-item__bullet{opacity:0;margin-right:12dp}.subtitle-title{display:block;position:relative;width:auto;height:auto;flex-direction:column;align-items:flex-start;align-content:flex-start;background-color:rgba(0,0,0,0);color:#ccc;cursor:pointer;text-align:left;padding:0}.subtitle-title--right{align-content:flex-end}.subtitle-title--right,.subtitle-title--right>*{text-align:right}.subtitle-title[selected]{color:#f2f2f2;cursor:default}.subtitle-title:focus:not(:disabled,[disabled]),.subtitle-title:hover:not(:disabled,[disabled],[selected]){color:#b97df2}.subtitle-title:disabled,.subtitle-title[disabled]{opacity:.5;cursor:default;tab-index:none}.subtitle-title h3{margin-bottom:6dp}.subtitle-title h1{margin-top:6dp}.subtitle-title__disclaimer{margin-top:16dp}.toggle{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;flex-direction:row;align-items:center;justify-content:space-between;position:relative;width:162dp;height:72dp;background:rgba(0,0,0,0);border-radius:36dp;cursor:pointer;opacity:.9}.toggle:hover,.toggle:focus-visible,.toggle:focus{background-color:rgba(23,214,232,.3);opacity:1}.toggle:active{background-color:rgba(23,214,232,.05);opacity:1}.toggle .toggle__border{position:absolute;top:1.1dp;right:1.1dp;bottom:1.1dp;left:1.1dp;border-color:#a2eff6;border-width:1.1dp;display:block;border-radius:36dp}.toggle .toggle__floater{position:absolute;width:80dp;height:64dp;top:50%;left:4dp;transform:translateY(-50%);border-radius:32dp;background:#25a1ad}.toggle--checked .toggle__floater{left:78dp}.toggle--checked .toggle__icon.toggle__icon--left{color:#a2eff6;opacity:.9}.toggle--checked .toggle__icon.toggle__icon--right{color:#f2f2f2;opacity:1}.toggle__icons{display:flex;position:absolute;height:56dp;top:50%;transform:translateY(-50%);right:16dp;left:16dp;align-items:center;justify-content:space-between}.toggle__icon{transition:color .05s linear-in-out,background-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;width:56dp;height:56dp;color:#f2f2f2}.toggle__icon--right{opacity:1;color:#a2eff6}.bottom-left{display:flex;flex-direction:row;position:absolute;align-items:flex-start;justify-content:flex-start;height:auto;bottom:4dp;margin:0 4dp;width:100%;max-width:1692.4444444444dp}.prompt__overlay{pointer-events:none}.prompt__overlay,.prompt__content-wrapper{position:absolute;top:0;right:0;bottom:0;left:0}.prompt__content-wrapper{position:absolute;display:flex;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0}.prompt__content{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:820dp;width:100%;height:auto;background:rgba(8,7,13,.9);border-radius:16dp;border-color:rgba(255,255,255,.2);border-width:1.1dp}.prompt__content h3,.prompt__content p{margin:16dp}.prompt__controls{display:flex;padding:16dp;border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp}.prompt__controls .button{nav-up:none;nav-down:none}.config-debug{display:block;position:relative;width:100%;max-height:100%;padding:8dp}.config-debug__scroll{display:block;position:relative;width:100%;max-height:100%;overflow-y:auto}.config-debug-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;border-bottom-color:rgba(255,255,255,.1);border-bottom-width:1.1dp;display:block;position:relative;flex-direction:column;width:100%;height:auto;padding:12dp 4dp;background-color:rgba(0,0,0,0)}.config-debug-option svg{image-color:#ccc}.config-debug-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug-option:focus:not(:disabled,[disabled]),.config-debug-option:focus-visible:not(:disabled,[disabled]),.config-debug-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.config-debug-option:focus:not(:disabled,[disabled]) svg,.config-debug-option:focus-visible:not(:disabled,[disabled]) svg,.config-debug-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.config-debug-option:disabled,.config-debug-option[disabled]{opacity:.5}.config-debug-option .icon-button{margin-left:8dp}.config-debug__option-split{display:flex;flex-direction:row;align-items:center;justify-content:space-between}.config-debug-option__label{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;padding:4dp 16dp 12dp;width:auto;height:auto;white-space:nowrap}.config-debug__option-controls{display:block;position:relative;flex:1 1 auto;height:auto;width:auto;max-width:800dp;padding:0 12dp}.config-debug__option-trigger{flex:1 1 auto}.config-debug__select-wrapper{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:flex-start;flex:1 1 100%;width:auto;max-width:800dp;height:auto;padding:4dp}.config-debug__select-wrapper .config-debug__select-label{padding-right:16dp;flex:auto;width:196dp}.config-debug__select-wrapper .config-debug__select-label>div{display:inline;width:auto;height:auto}.config-debug__select-wrapper input{display:block;position:relative;box-sizing:border-box;padding:0;flex:1 1 100%;width:auto;height:20dp;margin:auto 0}.config-debug__select-wrapper select{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;border-color:rgba(255,255,255,.5);border-width:1.1dp;display:block;position:relative;box-sizing:border-box;padding:0;flex:1 1 100%;width:auto;height:48dp;border-radius:12dp;background-color:rgba(255,255,255,.05);cursor:pointer;align-items:center;justify-content:flex-start;padding:14dp}.config-debug__select-wrapper select svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug__select-wrapper select:hover,.config-debug__select-wrapper select:focus{border-color:rgba(255,255,255,.8);border-width:1.1dp;background-color:rgba(255,255,255,.2)}.config-debug__select-wrapper select selectvalue{display:inline;margin:auto 0;height:auto}.config-debug__select-wrapper select selectbox{border-color:rgba(255,255,255,.8);border-width:1.1dp;background-color:#191622;padding:4dp 0;margin-top:2dp;border-radius:12dp}.config-debug__select-wrapper select selectbox option{transition:color .05s linear-in-out,background-color .05s linear-in-out;padding:8dp 12dp;background-color:rgba(0,0,0,0);color:#ccc;font-weight:400}.config-debug__select-wrapper select selectbox option:hover,.config-debug__select-wrapper select selectbox option:focus{background-color:rgba(255,255,255,.2)}.config-debug__select-wrapper select selectbox option:hover:not(:checked){cursor:pointer}.config-debug__select-wrapper select selectbox option:checked{color:#fff;background-color:rgba(255,255,255,.05)}body{box-sizing:border-box;color:#f2f2f2;font-family:chiaro}.rmlui-window{opacity:1}.rmlui-window--hidden{opacity:0}.rmlui-window:not([mouse-active]){pointer-events:none}*,*:before,*:after{box-sizing:border-box}button{background-color:#7a2ac6}@keyframes blue-pulse{0%{color:#17d6e8}50%{color:#a2eff6}to{color:#17d6e8}}@keyframes blue-pulse-with-border{0%{color:#17d6e8;border-color:#17d6e8}50%{color:#a2eff6;border-color:#a2eff6}to{color:#17d6e8;border-color:#17d6e8}}@keyframes blue-pulse-background{0%{background-color:#17d6e8}50%{background-color:#a2eff6}to{background-color:#17d6e8}}
+h1{font-size:68dp;letter-spacing:4.76dp;line-height:68dp;font-style:normal;font-weight:700}h2{font-size:52dp;letter-spacing:3.64dp;line-height:52dp;font-style:normal;font-weight:700}h3,.tab{font-size:36dp;letter-spacing:2.52dp;line-height:36dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:36dp;letter-spacing:3.96dp;line-height:36dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:28dp;letter-spacing:3.08dp;line-height:28dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label,.centered-page__controls>label{font-size:20dp;letter-spacing:2.8dp;line-height:20dp;font-style:normal;font-weight:700;text-transform:uppercase}.config-option__details{font-size:18dp;letter-spacing:2.52dp;line-height:18dp;font-style:normal;font-weight:400}body,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.config__wrapper p{font-size:20dp;letter-spacing:0dp;line-height:20dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.prompt-font-sm,.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.nav-vert,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto}.nav-horiz,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-right:auto;nav-left:auto}.nav-foc,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}h1{font-size:68dp;letter-spacing:4.76dp;line-height:68dp;font-style:normal;font-weight:700}h2{font-size:52dp;letter-spacing:3.64dp;line-height:52dp;font-style:normal;font-weight:700}h3,.tab{font-size:36dp;letter-spacing:2.52dp;line-height:36dp;font-style:normal;font-weight:700}.label-lg,.menu-list-item__label,.button--large{font-size:36dp;letter-spacing:3.96dp;line-height:36dp;font-style:normal;font-weight:700}.label-md,.config-debug-option__label,.button,.config-option__title,.control-option__label{font-size:28dp;letter-spacing:3.08dp;line-height:28dp;font-style:normal;font-weight:700}.label-sm,.subtitle-title__disclaimer,.config-debug__select-wrapper .config-debug__select-label,.config-option__range-label,.config-option__list .config-option__tab-label,.centered-page__controls>label{font-size:20dp;letter-spacing:2.8dp;line-height:20dp;font-style:normal;font-weight:700;text-transform:uppercase}.config-option__details{font-size:18dp;letter-spacing:2.52dp;line-height:18dp;font-style:normal;font-weight:400}body,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.config__wrapper p{font-size:20dp;letter-spacing:0dp;line-height:20dp;font-style:normal;font-weight:400}.toggle__icon{font-family:promptfont;font-style:normal;font-weight:400;font-size:56dp;line-height:56dp}.prompt-font{font-family:promptfont;font-style:normal;font-weight:400;font-size:40dp;line-height:40dp}.prompt-font-sm,.input-viz__mappings div{font-family:promptfont;font-style:normal;font-weight:400;font-size:32dp;line-height:32dp}.nav-vert,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-up:auto;nav-down:auto}.nav-horiz,.nav-dir,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{nav-right:auto;nav-left:auto}.nav-foc,.nav-all,.config-debug__select-wrapper select selectbox option,.config-debug__select-wrapper select,.config-debug__select-wrapper input,.toggle,.subtitle-title:not(:disabled,[disabled]),.menu-list-item:not(:disabled,[disabled]),.icon-button:not([disabled]),.button:not([disabled]),.button,.config-option__list input.radio,.tab,.control-option__binding:not([disabled]),.centered-page__modal{focus:auto;tab-index:auto}*{box-sizing:border-box}hr{display:block;background:#000;padding:1.5dp}body{font-family:chiaro;font-weight:normal;font-style:normal;font-size:20dp;color:#fff}div#window{position:relative;width:100%;height:100%;box-sizing:border-box;background-color:#121018;border-color:rgba(255,255,255,.2)}div#content{z-index:2;width:auto;height:100%;overflow:hidden auto;text-align:center}p{text-align:left}input.submit{margin-left:0}input.text,input.password{box-sizing:border-box;height:31dp;padding:11dp 10dp 0;cursor:text;text-align:left}textarea{padding:14dp 12dp 10dp;cursor:text;text-align:left}input.text,input.password,select,textarea{height:auto}table input.text{box-sizing:border-box;width:100%;margin:0;line-height:1;border-width:1.1dp;border-color:#000;background-color:#fff;font-size:15dp;decorator:none;height:auto}input.radio,input.checkbox{flex:0;tab-index:auto;focus:auto;nav-up:auto;nav-down:auto;nav-right:auto;nav-left:auto;width:0dp}scrollbarvertical,scrollbarhorizontal{margin:0;border:0}scrollbarvertical slidertrack,scrollbarhorizontal slidertrack{background:#dabaf7;opacity:.05}scrollbarvertical sliderbar,scrollbarhorizontal sliderbar{border-radius:5dp;background:#dabaf7;opacity:.1}scrollbarvertical sliderbar:hover:not(:active),scrollbarhorizontal sliderbar:hover:not(:active){opacity:.2}scrollbarvertical sliderbar:active,scrollbarhorizontal sliderbar:active{opacity:.3}scrollbarvertical sliderarrowdec,scrollbarvertical sliderarrowinc,scrollbarhorizontal sliderarrowdec,scrollbarhorizontal sliderarrowinc{width:0;height:0}scrollbarvertical{width:12dp}scrollbarvertical slidertrack{width:12dp}scrollbarvertical sliderbar{width:12dp}scrollbarhorizontal{height:12dp}scrollbarhorizontal slidertrack{height:12dp}scrollbarhorizontal sliderbar{height:12dp}.centered-page{display:flex;position:absolute;top:0;right:0;bottom:0;left:0;padding:64dp;background-color:rgba(255,255,255,.1)}.centered-page__modal{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%;background:rgba(8,7,13,.9);border-radius:16dp;border-color:rgba(255,255,255,.2);border-width:1.1dp}.centered-page__modal>.tabs{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:1692.4444444444dp;width:100%;height:100%}.centered-page__modal panels{flex:1 1 100%}.centered-page__controls{display:flex;flex-direction:row;position:absolute;align-items:center;justify-content:center;height:auto;bottom:24dp;margin:0 auto;width:100%;max-width:1692.4444444444dp}.centered-page__controls>label{display:inline-block;align-items:center;justify-content:space-between;width:auto;height:24dp}.centered-page__controls>label:not(:last-child){margin-right:40dp}.centered-page__controls>label>span:first-child{margin-right:4dp}.control-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;width:100%;height:auto;padding:4dp 16dp 4dp 20dp;border-radius:8dp;background-color:rgba(0,0,0,0)}.control-option svg{image-color:#ccc}.control-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option:focus-visible:not(:disabled,[disabled]),.control-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.control-option:focus-visible:not(:disabled,[disabled]) svg,.control-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.control-option:disabled,.control-option[disabled]{opacity:.5}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"]{border-color:#f86039}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-icon{opacity:0}[cur-binding-slot="0"] .control-option--active .control-option__binding[bind-slot="0"] .control-option__binding-recording{opacity:1}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"]{border-color:#f86039}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-icon{opacity:0}[cur-binding-slot="1"] .control-option--active .control-option__binding[bind-slot="1"] .control-option__binding-recording{opacity:1}.control-option .icon-button{flex:1 1 auto}.control-option__label{flex:2 1 300dp;height:auto;white-space:nowrap}.control-option__bindings{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:space-between;flex:2 1 400dp;width:100%;height:56dp;padding:0 12dp 0 4dp}.control-option__binding{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;position:relative;align-items:center;justify-content:center;margin:0 4dp;flex:1 1 100%;width:100%;height:56dp;padding:8dp;background-color:rgba(190,184,219,.1);border-color:rgba(190,184,219,.1);border-width:1.1dp;border-radius:8dp}.control-option__binding svg{image-color:#ccc}.control-option__binding svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.control-option__binding:focus,.control-option__binding:hover{color:#f2f2f2;background-color:rgba(255,255,255,.1);border-color:#f2f2f2}.control-option__binding:focus svg,.control-option__binding:hover svg{image-color:#f2f2f2}.control-option__binding:active{color:#f5f5f5}.control-option__binding:active svg{image-color:#f5f5f5}.control-option__binding:disabled,.control-option__binding[disabled]{color:#ccc;opacity:.5}.control-option__binding:disabled svg,.control-option__binding[disabled] svg{image-color:#ccc}.control-option__binding:not([disabled]){cursor:pointer}.control-option__binding-icon{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;opacity:1}@keyframes control-option__binding-recording-scale{0%{transform:scale(1)}50%{transform:scale(0.85)}to{transform:scale(1)}}.control-option__binding-recording{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:absolute;display:flex;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0;opacity:0}.control-option__binding-recording .control-option__binding-circle{width:24dp;height:24dp;background-color:#f86039;border-radius:24dp;animation:1.5s sine-in-out infinite control-option__binding-recording-scale}.control-option__binding-recording .control-option__binding-edge{position:absolute;transform:translate(-50%, -50%);top:50%;left:50%;width:36dp;height:36dp}.control-option__binding-recording .control-option__binding-edge>svg.control-option__binding-edge-svg{width:36dp;height:36dp;image-color:#f86039}.tabs tabs{display:flex;flex-direction:row;align-items:center;justify-content:flex-start}.tab{display:block;position:relative;padding:20dp 24dp;background-color:rgba(0,0,0,0);margin:0;color:rgba(255,255,255,.6);transition:color .05s linear-in-out;opacity:.9}.tab:selected{color:#f2f2f2}.tab:selected .tab__indicator{background-color:rgba(255,255,255,.6)}.tab:selected:hover{cursor:default}.rmlui-window:not([mouse-active]) .tab:focus{animation:blue-pulse .75s infinite}.rmlui-window:not([mouse-active]) .tab:focus:selected .tab__indicator{animation:blue-pulse-background .75s infinite}.tab:focus,.tab:hover{cursor:pointer;color:#f2f2f2;opacity:1}.tab__indicator{position:absolute;background-color:rgba(0,0,0,0);right:0;bottom:2dp;left:0;height:2dp}.config__exit-button{position:absolute;top:8dp;right:8dp}.config__form{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;display:flex;flex-direction:column;justify-content:space-between;flex:1 1 100%;width:100%;height:100%;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__wrapper{border-radius:0dp;flex:1 1 100%;height:100%;padding:16dp;text-align:left;background-color:rgba(0,0,0,.35);width:auto;height:auto}.config__wrapper p{padding:16dp;white-space:pre-line;line-height:28dp}.config__wrapper p b{color:#b97df2}.config__hz-wrapper{display:flex;flex-direction:row;border-radius:0dp;flex:1 1 100%;width:100%;height:100%;text-align:left}.config__header,.config__footer{display:flex;justify-content:space-between;align-items:center;width:100%;background-color:rgba(0,0,0,.35)}.config__header{border-bottom-color:rgba(255,255,255,.1);border-bottom-width:1.1dp;padding:12dp 20dp}.config__footer{border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp;padding:20dp 20dp;border-bottom-left-radius:16dp;border-bottom-right-radius:16dp}.config__header-left{display:flex;flex-direction:row;flex:1 1 auto}.config__header-left>:not(:first-child){margin-left:8dp}.config__row{display:flex;flex-direction:row}.config-option{display:flex;flex-direction:column;flex:1;align-items:flex-start;justify-content:flex-start;margin:16dp 0dp 24dp}.config-option:last-child{margin-top:16dp}.config-option__title{padding:0 12dp}.config-option__list{display:flex;padding:0;flex-direction:row;width:100%;height:auto;align-items:flex-start;justify-content:flex-start}.config-option__list input:first-of-type{nav-left:none}.config-option__list input:last-of-type{nav-right:none}.config-option__list .config-option__tab-label{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:block;position:relative;padding:8dp 0;height:auto;margin:4dp 12dp 0;color:rgba(255,255,255,.6);tab-index:none}.config-option__list .config-option__tab-label:hover{cursor:pointer;color:#f2f2f2}.config-option__list input.radio{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;visibility:visible;width:0;height:0}.config-option__list input.radio:not(:disabled):checked+.config-option__tab-label{border-bottom:1dp;border-color:#f2f2f2;color:#f2f2f2}.config-option__list input.radio:not(:disabled):checked+.config-option__tab-label:hover{cursor:default}.rmlui-window:not([mouse-active]) .config-option__list input.radio:not(:disabled):focus+.config-option__tab-label{animation:blue-pulse .75s infinite;color:#17d6e8;border-color:#17d6e8}.config-option__list input.radio:not(:disabled):focus+.config-option__tab-label,.config-option__list input.radio:not(:disabled):hover+.config-option__tab-label{color:#f2f2f2}.config-option__list input.radio:disabled+.config-option__tab-label{opacity:.5}.config-option__list input.radio:disabled+.config-option__tab-label:hover{cursor:default}.config-option__list input.range slidertrack{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-top:7dp;height:2dp;background-color:rgba(255,255,255,.2)}.config-option__list input.range sliderbar{transition:color .05s linear-in-out,background-color .05s linear-in-out;margin-left:-8dp;margin-right:-6dp;width:16dp;height:16dp;background-color:#ccc;border-radius:8dp;transition:background-color .05s linear-in-out}.rmlui-window:not([mouse-active]) .config-option__list input.range sliderbar:focus{border-color:#33f;border-width:1.1dp;animation:blue-pulse-background .75s infinite}.config-option__list input.range sliderbar:hover{cursor:pointer;background-color:#f2f2f2}.config-option__list input.range sliderbar:active,.config-option__list input.range slidertrack:active+sliderbar{background-color:#17d6e8}.config-option__list input.range sliderarrowdec,.config-option__list input.range sliderarrowinc{display:none}.config-option__details{color:#b97df2;margin:14dp 12dp 0;height:18dp}.config-option__range-wrapper{margin-top:4dp;max-width:360dp}.config-option__range-label{flex:0 0 16dp;display:block;padding:0;margin:0 12dp;margin-right:16dp;color:#f2f2f2;tab-index:none}.input-config{padding:0}.input-config__horizontal-split{display:flex;position:relative;flex-direction:row;height:100%}.input-config__mappings{display:block;flex:1 1 auto;height:100%;min-width:640dp}.input-config__mappings-scroll{display:block;width:100%;max-height:100%;overflow-y:auto}.input-config__mappings-wrapper{padding:8dp}.input-config__visual-wrapper{display:block;width:auto;height:auto;max-width:1040.4444444444dp;max-height:780.3333333333dp;margin:auto 0;flex:1 1 100%}.input-config__visual-aspect{position:relative;width:100%;padding-bottom:75%;background-color:rgba(0,0,0,.35);margin:auto 0}.input-config__visual{display:flex;flex-direction:column;position:absolute;top:16dp;right:16dp;bottom:16dp;left:16dp;border-radius:108dp;background-color:rgba(255,255,255,.05)}.input-config__visual-half{display:flex;position:relative;flex-direction:row;flex:1 1 100%;padding:6%}.input-config__visual-half--bottom{align-items:flex-end;justify-content:space-between}.input-config__visual-quarter-left{display:flex;flex:1 1 50%;width:auto;align-items:flex-start;justify-content:flex-start}.input-config__visual-quarter-right{display:flex;flex:1 1 100%;align-items:flex-start;justify-content:flex-end}.input-config__visual-stick-wrapper{display:flex;position:absolute;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0}.input-viz{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;position:relative;display:flex;align-items:center;justify-content:center}.input-viz>svg:not(.input-viz__dpad-arrow){position:absolute;top:0;right:0;left:0;bottom:0}[cur-input=NONE] .input-viz[visual-input]{opacity:1}.input-viz[visual-input~=A]{opacity:.25}[cur-input=A] .input-viz[visual-input~=A]{opacity:1}.input-viz[visual-input~=B]{opacity:.25}[cur-input=B] .input-viz[visual-input~=B]{opacity:1}.input-viz[visual-input~=Z]{opacity:.25}[cur-input=Z] .input-viz[visual-input~=Z]{opacity:1}.input-viz[visual-input~=START]{opacity:.25}[cur-input=START] .input-viz[visual-input~=START]{opacity:1}.input-viz[visual-input~=DPAD_UP]{opacity:.25}[cur-input=DPAD_UP] .input-viz[visual-input~=DPAD_UP]{opacity:1}.input-viz[visual-input~=DPAD_DOWN]{opacity:.25}[cur-input=DPAD_DOWN] .input-viz[visual-input~=DPAD_DOWN]{opacity:1}.input-viz[visual-input~=DPAD_LEFT]{opacity:.25}[cur-input=DPAD_LEFT] .input-viz[visual-input~=DPAD_LEFT]{opacity:1}.input-viz[visual-input~=DPAD_RIGHT]{opacity:.25}[cur-input=DPAD_RIGHT] .input-viz[visual-input~=DPAD_RIGHT]{opacity:1}.input-viz[visual-input~=L]{opacity:.25}[cur-input=L] .input-viz[visual-input~=L]{opacity:1}.input-viz[visual-input~=R]{opacity:.25}[cur-input=R] .input-viz[visual-input~=R]{opacity:1}.input-viz[visual-input~=C_UP]{opacity:.25}[cur-input=C_UP] .input-viz[visual-input~=C_UP]{opacity:1}.input-viz[visual-input~=C_DOWN]{opacity:.25}[cur-input=C_DOWN] .input-viz[visual-input~=C_DOWN]{opacity:1}.input-viz[visual-input~=C_LEFT]{opacity:.25}[cur-input=C_LEFT] .input-viz[visual-input~=C_LEFT]{opacity:1}.input-viz[visual-input~=C_RIGHT]{opacity:.25}[cur-input=C_RIGHT] .input-viz[visual-input~=C_RIGHT]{opacity:1}.input-viz[visual-input~=X_AXIS_NEG]{opacity:.25}[cur-input=X_AXIS_NEG] .input-viz[visual-input~=X_AXIS_NEG]{opacity:1}.input-viz[visual-input~=X_AXIS_POS]{opacity:.25}[cur-input=X_AXIS_POS] .input-viz[visual-input~=X_AXIS_POS]{opacity:1}.input-viz[visual-input~=Y_AXIS_NEG]{opacity:.25}[cur-input=Y_AXIS_NEG] .input-viz[visual-input~=Y_AXIS_NEG]{opacity:1}.input-viz[visual-input~=Y_AXIS_POS]{opacity:.25}[cur-input=Y_AXIS_POS] .input-viz[visual-input~=Y_AXIS_POS]{opacity:1}.input-viz__button{color:#f2f2f2}.input-viz__button svg{image-color:#f2f2f2}.input-viz__button--sm{width:64dp;height:64dp}.input-viz__button--sm>svg{width:64dp;height:64dp}.input-viz__button--md{width:76dp;height:76dp}.input-viz__button--md>svg{width:76dp;height:76dp}.input-viz__button--lg{width:84dp;height:84dp}.input-viz__button--lg>svg{width:84dp;height:84dp}.input-viz__button--C svg{image-color:#e9cd35}.input-viz__button--A{margin-top:auto}.input-viz__button--A svg{image-color:#33f}.input-viz__button--B svg{image-color:#45d043}.input-viz__button--Start svg{image-color:#f86039}.input-viz__Z{width:136dp;height:136dp}.input-viz__Z svg{image-color:#e9cd35}.input-viz__Z>svg{width:136dp;height:136dp}.input-viz.input-viz__dpad{width:192dp;height:192dp;position:relative}.input-viz.input-viz__dpad svg{image-color:#f2f2f2}.input-viz.input-viz__dpad>svg{width:192dp;height:192dp}.input-config__visual-stick{display:flex;position:relative;align-items:center;justify-content:center;width:200dp;height:200dp;border-radius:100dp;background-color:rgba(255,255,255,.05)}.input-viz__dpad-split,.input-viz__stick-split{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;width:100%;height:100%}.input-viz__dpad-split--vertical,.input-viz__stick-split--vertical{flex-direction:column;align-items:center;justify-content:space-between}.input-viz__dpad-split--horizontal,.input-viz__stick-split--horizontal{flex-direction:row;align-items:center;justify-content:space-between}.input-viz__dpad-split>div,.input-viz__stick-split>div{display:flex;flex:1 1 100%;align-items:center;justify-content:center;flex-direction:row}.input-viz__dpad-split>div{width:64dp;height:64dp}.input-viz__stick-split>div{width:66.6666666667dp;height:66.6666666667dp}.input-viz__dpad-arrow{position:absolute;width:60dp;height:60dp}.input-viz__dpad-arrow--up{top:4dp;margin:0 auto}.input-viz__dpad-arrow--down{bottom:4dp;margin:0 auto;transform:rotate(180deg)}.input-viz__dpad-arrow--left{left:4dp;margin:auto 0;transform:rotate(-90deg)}.input-viz__dpad-arrow--right{right:4dp;margin:auto 0;transform:rotate(90deg)}.input-viz__R{width:96dp;height:96dp}.input-viz__R svg{image-color:#fff}.input-viz__R>svg{width:96dp;height:96dp}.input-viz__L{width:136dp;height:136dp}.input-viz__L svg{image-color:#17d6e8}.input-viz__L>svg{width:136dp;height:136dp}.input-config__c-buttons{position:relative;width:208dp;height:132dp}.input-config__c-buttons-lr,.input-config__c-buttons-du{display:flex;position:absolute;top:0;right:0;left:0;bottom:0}.input-config__c-buttons-lr{flex-direction:row;align-items:flex-start;justify-content:space-between}.input-config__c-buttons-du{flex-direction:column-reverse;align-items:center;justify-content:space-between}.input-config__c-buttons .input-viz[visual-input=C_UP]{margin-top:-32dp}.input-config__main-buttons{display:flex;flex-direction:row;justify-content:space-between;width:268dp;height:128dp;position:relative;margin-right:10dp}.button{background-color:rgba(185,125,242,.05);color:#ccc;border-color:rgba(185,125,242,.8);transition:color .05s linear-in-out,background-color .05s linear-in-out;display:block;padding:23dp;border-radius:12dp;border-width:1.1dp;width:auto;height:auto}.button:focus,.button:hover{color:#f2f2f2;border-color:#b97df2;background-color:rgba(185,125,242,.3)}.button:disabled,.button[disabled]{color:rgba(255,255,255,.6)}.button:active{background-color:rgba(185,125,242,.2);color:#f5f5f5}.button--secondary{background-color:rgba(23,214,232,.05);color:#ccc;border-color:rgba(23,214,232,.8)}.button--secondary:focus,.button--secondary:hover{color:#f2f2f2;border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.button--secondary:disabled,.button--secondary[disabled]{color:rgba(255,255,255,.6)}.button--secondary:active{background-color:rgba(23,214,232,.2);color:#f5f5f5}.button--tertiary{background-color:rgba(242,242,242,.05);color:#ccc;border-color:rgba(242,242,242,.8)}.button--tertiary:focus,.button--tertiary:hover{color:#f2f2f2;border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.button--tertiary:disabled,.button--tertiary[disabled]{color:rgba(255,255,255,.6)}.button--tertiary:active{background-color:rgba(242,242,242,.2);color:#f5f5f5}.button--success{background-color:rgba(69,208,67,.05);color:#ccc;border-color:rgba(69,208,67,.8)}.button--success:focus,.button--success:hover{color:#f2f2f2;border-color:#45d043;background-color:rgba(69,208,67,.3)}.button--success:disabled,.button--success[disabled]{color:rgba(255,255,255,.6)}.button--success:active{background-color:rgba(69,208,67,.2);color:#f5f5f5}.button--error{background-color:rgba(248,96,57,.05);color:#ccc;border-color:rgba(248,96,57,.8)}.button--error:focus,.button--error:hover{color:#f2f2f2;border-color:#f86039;background-color:rgba(248,96,57,.3)}.button--error:disabled,.button--error[disabled]{color:rgba(255,255,255,.6)}.button--error:active{background-color:rgba(248,96,57,.2);color:#f5f5f5}.button--warning{background-color:rgba(233,205,53,.05);color:#ccc;border-color:rgba(233,205,53,.8)}.button--warning:focus,.button--warning:hover{color:#f2f2f2;border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.button--warning:disabled,.button--warning[disabled]{color:rgba(255,255,255,.6)}.button--warning:active{background-color:rgba(233,205,53,.2);color:#f5f5f5}.button:not([disabled]){cursor:pointer}.button:disabled,.button[disabled]{opacity:.5}.button__label{width:auto;height:auto}.icon-button{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;overflow:hidden;border-radius:26.9dp;border-width:1.1dp;border-color:rgba(0,0,0,0);background-color:rgba(0,0,0,0);width:53.8dp;height:53.8dp;min-width:53.8dp;min-height:53.8dp;max-width:53.8dp;max-height:53.8dp}.icon-button svg{image-color:#ccc}.icon-button svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.icon-button:focus,.icon-button:hover{color:#f2f2f2;background-color:rgba(255,255,255,.2)}.icon-button:focus svg,.icon-button:hover svg{image-color:#f2f2f2}.icon-button:active{color:#f5f5f5;background-color:rgba(255,255,255,.1)}.icon-button:active svg{image-color:#f5f5f5}.icon-button:disabled,.icon-button[disabled]{color:#ccc;opacity:.5}.icon-button:disabled svg,.icon-button[disabled] svg{image-color:#ccc}.icon-button:not([disabled]){cursor:pointer}.icon-button svg{width:32dp;height:32dp}.icon-button--primary{background-color:rgba(185,125,242,.05);border-color:rgba(185,125,242,.8)}.icon-button--primary:focus,.icon-button--primary:hover{border-color:#b97df2;background-color:rgba(185,125,242,.3)}.icon-button--primary:active{background-color:rgba(185,125,242,.2)}.icon-button--secondary{background-color:rgba(23,214,232,.05);border-color:rgba(23,214,232,.8)}.icon-button--secondary:focus,.icon-button--secondary:hover{border-color:#17d6e8;background-color:rgba(23,214,232,.3)}.icon-button--secondary:active{background-color:rgba(23,214,232,.2)}.icon-button--tertiary{background-color:rgba(242,242,242,.05);border-color:rgba(242,242,242,.8)}.icon-button--tertiary:focus,.icon-button--tertiary:hover{border-color:#f2f2f2;background-color:rgba(242,242,242,.3)}.icon-button--tertiary:active{background-color:rgba(242,242,242,.2)}.icon-button--success{background-color:rgba(69,208,67,.05);border-color:rgba(69,208,67,.8)}.icon-button--success:focus,.icon-button--success:hover{border-color:#45d043;background-color:rgba(69,208,67,.3)}.icon-button--success:active{background-color:rgba(69,208,67,.2)}.icon-button--danger{background-color:rgba(248,96,57,.05);border-color:rgba(248,96,57,.8)}.icon-button--danger:focus,.icon-button--danger:hover{border-color:#f86039;background-color:rgba(248,96,57,.3)}.icon-button--danger:active{background-color:rgba(248,96,57,.2)}.icon-button--warning{background-color:rgba(233,205,53,.05);border-color:rgba(233,205,53,.8)}.icon-button--warning:focus,.icon-button--warning:hover{border-color:#e9cd35;background-color:rgba(233,205,53,.3)}.icon-button--warning:active{background-color:rgba(233,205,53,.2)}.launcher{display:block;flex-direction:row;justify-content:space-between;position:relative;width:100%;height:100%;background-color:#08070d}.launcher__vertical-split{display:flex;position:absolute;flex-direction:column;align-items:flex-start;justify-content:space-between;top:0;right:50%;bottom:0;left:0}.launcher__vertical-split--right{align-items:flex-end;right:0;left:50%}@keyframes slide-mm-bg-over{0%{transform:translateX(100dp)}to{transform:translateX(0dp)}}.launcher__background-wrapper{display:flex;align-items:center;justify-content:flex-start;position:absolute;left:-70vw;right:-100%;top:-55vw;bottom:-50vw;transform:translateX(0dp);animation:25s cubic-out 1 slide-mm-bg-over}@keyframes fade-mm-in{0%{opacity:0}to{opacity:.1}}.launcher__background-mm{position:absolute;left:0;top:0;bottom:0;height:100%;width:auto;opacity:.1;animation:2.5s cubic-in-out 1 fade-mm-in}.launcher__title-quadrant{flex:1 1 auto;padding-top:96dp;padding-left:96dp;width:auto;height:auto}.launcher__title-quadrant--right{padding-right:96dp;padding-left:0}.launcher__content-quadrant{display:flex;position:relative;flex-direction:column;align-items:flex-start;justify-content:flex-end;padding:32dp;width:100%;height:auto;flex:1 1 100%}.menu-list-item{color:#ccc;display:flex;flex-direction:row;align-items:center;width:100%;height:auto;padding:16dp;border-radius:8dp;background-color:rgba(0,0,0,0);cursor:pointer}.menu-list-item svg{image-color:#ccc}.menu-list-item--right{align-content:flex-end;flex-direction:row-reverse}.menu-list-item--right .menu-list-item__bullet{opacity:1;margin-left:12dp}.menu-list-item--right.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item--right.menu-list-item:hover:not(:disabled,[disabled]){decorator:gradient(horizontal #7A2AC600 #DABAF714)}.menu-list-item:focus:not(:disabled,[disabled]),.menu-list-item:hover:not(:disabled,[disabled]){color:#b97df2;decorator:gradient(horizontal #7A2AC614 #DABAF700)}.menu-list-item:focus:not(:disabled,[disabled]) svg,.menu-list-item:hover:not(:disabled,[disabled]) svg{image-color:#b97df2}.menu-list-item:focus:not(:disabled,[disabled]) .menu-list-item__bullet,.menu-list-item:hover:not(:disabled,[disabled]) .menu-list-item__bullet{opacity:1}.menu-list-item:disabled,.menu-list-item[disabled]{opacity:.5;tab-index:none;cursor:default}.menu-list-item__bullet{opacity:0;margin-right:12dp}.subtitle-title{display:block;position:relative;width:auto;height:auto;flex-direction:column;align-items:flex-start;align-content:flex-start;background-color:rgba(0,0,0,0);color:#ccc;cursor:pointer;text-align:left;padding:0}.subtitle-title--right{align-content:flex-end}.subtitle-title--right,.subtitle-title--right>*{text-align:right}.subtitle-title[selected]{color:#f2f2f2;cursor:default}.subtitle-title:focus:not(:disabled,[disabled]),.subtitle-title:hover:not(:disabled,[disabled],[selected]){color:#b97df2}.subtitle-title:disabled,.subtitle-title[disabled]{opacity:.5;cursor:default;tab-index:none}.subtitle-title h3{margin-bottom:6dp}.subtitle-title h1{margin-top:6dp}.subtitle-title__disclaimer{margin-top:16dp}.toggle{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;display:flex;flex-direction:row;align-items:center;justify-content:space-between;position:relative;width:162dp;height:72dp;background:rgba(0,0,0,0);border-radius:36dp;cursor:pointer;opacity:.9}.toggle:hover,.toggle:focus-visible,.toggle:focus{background-color:rgba(23,214,232,.3);opacity:1}.toggle:active{background-color:rgba(23,214,232,.05);opacity:1}.toggle .toggle__border{position:absolute;top:1.1dp;right:1.1dp;bottom:1.1dp;left:1.1dp;border-color:#a2eff6;border-width:1.1dp;display:block;border-radius:36dp}.toggle .toggle__floater{position:absolute;width:80dp;height:64dp;top:50%;left:4dp;transform:translateY(-50%);border-radius:32dp;background:#25a1ad}.toggle--checked .toggle__floater{left:78dp}.toggle--checked .toggle__icon.toggle__icon--left{color:#a2eff6;opacity:.9}.toggle--checked .toggle__icon.toggle__icon--right{color:#f2f2f2;opacity:1}.toggle__icons{display:flex;position:absolute;height:56dp;top:50%;transform:translateY(-50%);right:16dp;left:16dp;align-items:center;justify-content:space-between}.toggle__icon{transition:color .05s linear-in-out,background-color .05s linear-in-out;display:flex;align-items:center;justify-content:center;width:56dp;height:56dp;color:#f2f2f2}.toggle__icon--right{opacity:1;color:#a2eff6}.bottom-left{display:flex;flex-direction:row;position:absolute;align-items:flex-start;justify-content:flex-start;height:auto;bottom:4dp;margin:0 4dp;width:100%;max-width:1692.4444444444dp}.prompt__overlay{pointer-events:none}.prompt__overlay,.prompt__content-wrapper{position:absolute;top:0;right:0;bottom:0;left:0}.prompt__content-wrapper{position:absolute;display:flex;align-items:center;justify-content:center;top:0;right:0;bottom:0;left:0}.prompt__content{display:flex;flex-direction:column;position:relative;margin:auto;flex:1 1 100%;max-width:820dp;width:100%;height:auto;background:rgba(8,7,13,.9);border-radius:16dp;border-color:rgba(255,255,255,.2);border-width:1.1dp}.prompt__content h3,.prompt__content p{margin:16dp}.prompt__controls{display:flex;padding:16dp;border-top-color:rgba(255,255,255,.1);border-top-width:1.1dp}.prompt__controls .button{nav-up:none;nav-down:none}.config-debug{display:block;position:relative;width:100%;max-height:100%;padding:8dp}.config-debug__scroll{display:block;position:relative;width:100%;max-height:100%;overflow-y:auto}.config-debug-option{color:#ccc;transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out;border-bottom-color:rgba(255,255,255,.1);border-bottom-width:1.1dp;display:block;position:relative;flex-direction:column;width:100%;height:auto;padding:12dp 4dp;background-color:rgba(0,0,0,0)}.config-debug-option svg{image-color:#ccc}.config-debug-option svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug-option:focus:not(:disabled,[disabled]),.config-debug-option:focus-visible:not(:disabled,[disabled]),.config-debug-option:hover:not(:disabled,[disabled]){color:#f2f2f2;background-color:rgba(190,184,219,.1)}.config-debug-option:focus:not(:disabled,[disabled]) svg,.config-debug-option:focus-visible:not(:disabled,[disabled]) svg,.config-debug-option:hover:not(:disabled,[disabled]) svg{image-color:#f2f2f2}.config-debug-option:disabled,.config-debug-option[disabled]{opacity:.5}.config-debug-option .icon-button{margin-left:8dp}.config-debug__option-split{display:flex;flex-direction:row;align-items:center;justify-content:space-between}.config-debug-option__label{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;padding:4dp 16dp 12dp;width:auto;height:auto;white-space:nowrap}.config-debug__option-controls{display:block;position:relative;flex:1 1 auto;height:auto;width:auto;max-width:800dp;padding:0 12dp}.config-debug__option-trigger{flex:1 1 auto}.config-debug__select-wrapper{display:flex;position:relative;flex-direction:row;align-items:center;justify-content:flex-start;flex:1 1 100%;width:auto;max-width:800dp;height:auto;padding:4dp}.config-debug__select-wrapper .config-debug__select-label{padding-right:16dp;flex:auto;width:196dp}.config-debug__select-wrapper .config-debug__select-label>div{display:inline;width:auto;height:auto}.config-debug__select-wrapper input{display:block;position:relative;box-sizing:border-box;padding:0;flex:1 1 100%;width:auto;height:20dp;margin:auto 0}.config-debug__select-wrapper select{transition:color .05s linear-in-out,background-color .05s linear-in-out,opacity .05s linear-in-out,border-color .05s linear-in-out;border-color:rgba(255,255,255,.5);border-width:1.1dp;display:block;position:relative;box-sizing:border-box;padding:0;flex:1 1 100%;width:auto;height:48dp;border-radius:12dp;background-color:rgba(255,255,255,.05);cursor:pointer;align-items:center;justify-content:flex-start;padding:14dp}.config-debug__select-wrapper select svg{transition:image-color .05s linear-in-out,background-color .05s linear-in-out}.config-debug__select-wrapper select:hover,.config-debug__select-wrapper select:focus{border-color:rgba(255,255,255,.8);border-width:1.1dp;background-color:rgba(255,255,255,.2)}.config-debug__select-wrapper select selectvalue{display:inline;margin:auto 0;height:auto}.config-debug__select-wrapper select selectbox{border-color:rgba(255,255,255,.8);border-width:1.1dp;background-color:#191622;padding:4dp 0;margin-top:2dp;border-radius:12dp}.config-debug__select-wrapper select selectbox option{transition:color .05s linear-in-out,background-color .05s linear-in-out;padding:8dp 12dp;background-color:rgba(0,0,0,0);color:#ccc;font-weight:400}.config-debug__select-wrapper select selectbox option:hover,.config-debug__select-wrapper select selectbox option:focus{background-color:rgba(255,255,255,.2)}.config-debug__select-wrapper select selectbox option:hover:not(:checked){cursor:pointer}.config-debug__select-wrapper select selectbox option:checked{color:#fff;background-color:rgba(255,255,255,.05)}body{box-sizing:border-box;color:#f2f2f2;font-family:chiaro}.rmlui-window{opacity:1}.rmlui-window--hidden{opacity:0}.rmlui-window:not([mouse-active]){pointer-events:none}*,*:before,*:after{box-sizing:border-box}button{background-color:#7a2ac6}@keyframes blue-pulse{0%{color:#17d6e8}50%{color:#a2eff6}to{color:#17d6e8}}@keyframes blue-pulse-with-border{0%{color:#17d6e8;border-color:#17d6e8}50%{color:#a2eff6;border-color:#a2eff6}to{color:#17d6e8;border-color:#17d6e8}}@keyframes blue-pulse-background{0%{background-color:#17d6e8}50%{background-color:#a2eff6}to{background-color:#17d6e8}}
diff --git a/assets/scss/styles/components/Config.scss b/assets/scss/styles/components/Config.scss
index 6350144..b3d1bb7 100644
--- a/assets/scss/styles/components/Config.scss
+++ b/assets/scss/styles/components/Config.scss
@@ -24,6 +24,8 @@
padding: space(16);
text-align: left;
background-color: $color-bg-shadow;
+ width: auto;
+ height: auto;
p {
@extend %body;
@@ -42,6 +44,7 @@
flex-direction: row;
border-radius: 0dp;
flex: 1 1 100%;
+ width: 100%;
height: 100%;
text-align: left;
}
diff --git a/lib/RmlUi b/lib/RmlUi
index bb25b88..a893ea6 160000
--- a/lib/RmlUi
+++ b/lib/RmlUi
@@ -1 +1 @@
-Subproject commit bb25b881791bc77805b30b22fea01ae42b619bd7
+Subproject commit a893ea6386e0c842f90a726a53c9b9e888797519
diff --git a/lib/lunasvg b/lib/lunasvg
index 73cc40b..610b8bf 160000
--- a/lib/lunasvg
+++ b/lib/lunasvg
@@ -1 +1 @@
-Subproject commit 73cc40b482d0adad226ad101bff40d8ffa69ffeb
+Subproject commit 610b8bf5148a27489b4e3344b4f5617b81be38c7
diff --git a/src/ui/FontEngineScaled/FontEngineInterfaceScaled.cpp b/src/ui/FontEngineScaled/FontEngineInterfaceScaled.cpp
deleted file mode 100644
index c42a9b7..0000000
--- a/src/ui/FontEngineScaled/FontEngineInterfaceScaled.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "FontEngineInterfaceScaled.h"
-#include "FontFaceHandleScaled.h"
-#include "FontProvider.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-FontEngineInterfaceScaled::FontEngineInterfaceScaled()
-{
- FontProvider::Initialise();
-}
-
-FontEngineInterfaceScaled::~FontEngineInterfaceScaled()
-{
- FontProvider::Shutdown();
-}
-
-bool FontEngineInterfaceScaled::LoadFontFace(const String& file_name, bool fallback_face, Style::FontWeight weight)
-{
- return FontProvider::LoadFontFace(file_name, fallback_face, weight);
-}
-
-bool FontEngineInterfaceScaled::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 FontEngineInterfaceScaled::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 FontEngineInterfaceScaled::PrepareFontEffects(FontFaceHandle handle, const FontEffectList& font_effects)
-{
- auto handle_scaled = reinterpret_cast(handle);
- return (FontEffectsHandle)handle_scaled->GenerateLayerConfiguration(font_effects);
-}
-
-const FontMetrics& FontEngineInterfaceScaled::GetFontMetrics(FontFaceHandle handle)
-{
- auto handle_scaled = reinterpret_cast(handle);
- return handle_scaled->GetFontMetrics();
-}
-
-int FontEngineInterfaceScaled::GetStringWidth(FontFaceHandle handle, const String& string, float letter_spacing, Character prior_character)
-{
- auto handle_scaled = reinterpret_cast(handle);
- return handle_scaled->GetStringWidth(string, letter_spacing, prior_character);
-}
-
-int FontEngineInterfaceScaled::GenerateString(FontFaceHandle handle, FontEffectsHandle font_effects_handle, const String& string,
- const Vector2f& position, const Colourb& colour, float opacity, float letter_spacing, GeometryList& geometry)
-{
- auto handle_scaled = reinterpret_cast(handle);
- return handle_scaled->GenerateString(geometry, string, position, colour, opacity, letter_spacing, (int)font_effects_handle);
-}
-
-int FontEngineInterfaceScaled::GetVersion(FontFaceHandle handle)
-{
- auto handle_scaled = reinterpret_cast(handle);
- return handle_scaled->GetVersion();
-}
-
-void FontEngineInterfaceScaled::ReleaseFontResources()
-{
- FontProvider::ReleaseFontResources();
-}
-
-} // namespace Rml
diff --git a/src/ui/FontEngineScaled/FontEngineInterfaceScaled.h b/src/ui/FontEngineScaled/FontEngineInterfaceScaled.h
deleted file mode 100644
index 846e0b9..0000000
--- a/src/ui/FontEngineScaled/FontEngineInterfaceScaled.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, 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_FONTENGINESCALED_FONTENGINEINTERFACESCALED_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTENGINEINTERFACESCALED_H
-
-#include "RmlUi/Core/FontEngineInterface.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class RMLUICORE_API FontEngineInterfaceScaled : public FontEngineInterface {
-public:
- FontEngineInterfaceScaled();
- virtual ~FontEngineInterfaceScaled();
-
- /// 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, Style::FontWeight weight) 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 font metrics of the given font face.
- const FontMetrics& GetFontMetrics(FontFaceHandle handle) override;
-
- /// Returns the width a string will take up if rendered with this handle.
- int GetStringWidth(FontFaceHandle, const String& string, float letter_spacing, 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, float opacity,
- float letter_spacing, GeometryList& geometry) override;
-
- /// Returns the current version of the font face.
- int GetVersion(FontFaceHandle handle) override;
-
- /// Releases resources owned by sized font faces, including their textures and rendered glyphs.
- void ReleaseFontResources() override;
-};
-
-} // namespace Rml
-#endif
diff --git a/src/ui/FontEngineScaled/FontFace.cpp b/src/ui/FontEngineScaled/FontFace.cpp
deleted file mode 100644
index 0424888..0000000
--- a/src/ui/FontEngineScaled/FontFace.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "FontFace.h"
-#include "RmlUi/Core/Log.h"
-#include "FontFaceHandleScaled.h"
-#include "FreeTypeInterface.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-FontFace::FontFace(FontFaceHandleFreetype _face, Style::FontStyle _style, Style::FontWeight _weight)
-{
- style = _style;
- weight = _weight;
- face = _face;
-}
-
-FontFace::~FontFace()
-{
- if (face)
- FreeType::ReleaseFace(face);
-}
-
-Style::FontStyle FontFace::GetStyle() const
-{
- return style;
-}
-
-Style::FontWeight FontFace::GetWeight() const
-{
- return weight;
-}
-
-FontFaceHandleScaled* FontFace::GetHandle(int size, bool load_default_glyphs)
-{
- 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, load_default_glyphs))
- {
- handles[size] = nullptr;
- return nullptr;
- }
-
- FontFaceHandleScaled* result = handle.get();
-
- // Save the new handle to the font face
- handles[size] = std::move(handle);
-
- return result;
-}
-
-void FontFace::ReleaseFontResources()
-{
- HandleMap().swap(handles);
-}
-
-} // namespace Rml
diff --git a/src/ui/FontEngineScaled/FontFace.h b/src/ui/FontEngineScaled/FontFace.h
deleted file mode 100644
index e632203..0000000
--- a/src/ui/FontEngineScaled/FontFace.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FONTFACE_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTFACE_H
-
-#include "RmlUi/Core/StyleTypes.h"
-#include "FontTypes.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class FontFaceHandleScaled;
-
-/**
- @author Peter Curry
- */
-
-class FontFace {
-public:
- FontFace(FontFaceHandleFreetype face, Style::FontStyle style, Style::FontWeight weight);
- ~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.
- /// @param[in] load_default_glyphs True to load the default set of glyph (ASCII range).
- /// @return The font handle.
- FontFaceHandleScaled* GetHandle(int size, bool load_default_glyphs);
-
- /// Releases resources owned by sized font faces, including their textures and rendered glyphs.
- void ReleaseFontResources();
-
-private:
- Style::FontStyle style;
- Style::FontWeight weight;
-
- // Key is font size
- using HandleMap = UnorderedMap>;
- HandleMap handles;
-
- FontFaceHandleFreetype face;
-};
-
-} // namespace Rml
-#endif
diff --git a/src/ui/FontEngineScaled/FontFaceHandleScaled.cpp b/src/ui/FontEngineScaled/FontFaceHandleScaled.cpp
deleted file mode 100644
index 42f57c2..0000000
--- a/src/ui/FontEngineScaled/FontFaceHandleScaled.cpp
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "FontFaceHandleScaled.h"
-#include "RmlUi/Core.h"
-#include "FontFaceLayer.h"
-#include "FontProvider.h"
-#include "FreeTypeInterface.h"
-#include
-
-namespace RecompRml {
-
-using namespace Rml;
-
-static constexpr char32_t KerningCache_AsciiSubsetBegin = 32;
-static constexpr char32_t KerningCache_AsciiSubsetLast = 126;
-
-FontFaceHandleScaled::FontFaceHandleScaled()
-{
- base_layer = nullptr;
- metrics = {};
- ft_face = 0;
-}
-
-FontFaceHandleScaled::~FontFaceHandleScaled()
-{
- glyphs.clear();
- layers.clear();
-}
-
-bool FontFaceHandleScaled::Initialize(FontFaceHandleFreetype face, int font_size, bool load_default_glyphs)
-{
- ft_face = face;
-
- RMLUI_ASSERTMSG(layer_configurations.empty(), "Initialize must only be called once.");
-
- if (!FreeType::InitialiseFaceHandle(ft_face, font_size, glyphs, metrics, load_default_glyphs))
- return false;
-
- has_kerning = FreeType::HasKerning(ft_face);
- FillKerningPairCache();
-
- // Generate the default layer and layer configuration.
- base_layer = GetOrCreateLayer(nullptr);
- layer_configurations.push_back(LayerConfiguration{base_layer});
-
- return true;
-}
-
-const FontMetrics& FontFaceHandleScaled::GetFontMetrics() const
-{
- return metrics;
-}
-
-const FontGlyphMap& FontFaceHandleScaled::GetGlyphs() const
-{
- return glyphs;
-}
-
-int FontFaceHandleScaled::GetStringWidth(const String& string, float letter_spacing, Character prior_character)
-{
- RMLUI_ZoneScoped;
-
- 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.
- width += GetKerning(prior_character, character);
-
- // Adjust the cursor for this character's advance.
- width += glyph->advance;
- width += (int)letter_spacing;
-
- prior_character = character;
- }
-
- return Math::Max(width, 0);
-}
-
-int FontFaceHandleScaled::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);
-}
-
-bool FontFaceHandleScaled::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);
-}
-
-int FontFaceHandleScaled::GenerateString(GeometryList& geometry, const String& string, const Vector2f position, const Colourb colour,
- const float opacity, const float letter_spacing, const 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();
- if (opacity < 1.f)
- layer_colour.alpha = byte(opacity * float(layer_colour.alpha));
- }
-
- 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.
- line_width += GetKerning(prior_character, character);
-
- // Use white vertex colors on RGB glyphs.
- const Colourb glyph_color =
- (layer == base_layer && glyph->color_format == ColorFormat::RGBA8 ? Colourb(255, layer_colour.alpha) : layer_colour);
-
- layer->GenerateGeometry(&geometry[geometry_index], character, Vector2f(position.x + line_width, position.y), glyph_color);
-
- line_width += glyph->advance;
- line_width += (int)letter_spacing;
- prior_character = character;
- }
-
- geometry_index += num_textures;
- }
-
- // Cull any excess geometry from a previous generation.
- geometry.resize(geometry_index);
-
- return Math::Max(line_width, 0);
-}
-
-bool FontFaceHandleScaled::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 FontFaceHandleScaled::GetVersion() const
-{
- return version;
-}
-
-bool FontFaceHandleScaled::AppendGlyph(Character character)
-{
- bool result = FreeType::AppendGlyph(ft_face, metrics.size, character, glyphs);
- return result;
-}
-
-void FontFaceHandleScaled::FillKerningPairCache()
-{
- if (!has_kerning)
- return;
-
- for (char32_t i = KerningCache_AsciiSubsetBegin; i <= KerningCache_AsciiSubsetLast; i++)
- {
- for (char32_t j = KerningCache_AsciiSubsetBegin; j <= KerningCache_AsciiSubsetLast; j++)
- {
- const bool first_iteration = (i == KerningCache_AsciiSubsetBegin && j == KerningCache_AsciiSubsetBegin);
-
- // Fetch the kerning from the font face. Submit zero font size on subsequent iterations for performance reasons.
- const int kerning = FreeType::GetKerning(ft_face, first_iteration ? metrics.size : 0, Character(i), Character(j));
- if (kerning != 0)
- {
- kerning_pair_cache.emplace(AsciiPair((i << 8) | j), KerningIntType(kerning));
- }
- }
- }
-}
-
-int FontFaceHandleScaled::GetKerning(Character lhs, Character rhs) const
-{
- static_assert(' ' == 32, "Only ASCII/UTF8 character set supported.");
-
- // Check if we have no kerning, or if we are have a control character.
- if (!has_kerning || char32_t(lhs) < ' ' || char32_t(rhs) < ' ')
- return 0;
-
- // See if the kerning pair has been cached.
- const bool lhs_in_cache = (char32_t(lhs) >= KerningCache_AsciiSubsetBegin && char32_t(lhs) <= KerningCache_AsciiSubsetLast);
- const bool rhs_in_cache = (char32_t(rhs) >= KerningCache_AsciiSubsetBegin && char32_t(rhs) <= KerningCache_AsciiSubsetLast);
-
- if (lhs_in_cache && rhs_in_cache)
- {
- const auto it = kerning_pair_cache.find(AsciiPair((int(lhs) << 8) | int(rhs)));
-
- if (it != kerning_pair_cache.end())
- {
- return it->second;
- }
-
- return 0;
- }
-
- // Fetch it from the font face instead.
- const int result = FreeType::GetKerning(ft_face, metrics.size, lhs, rhs);
- return result;
-}
-
-const FontGlyph* FontFaceHandleScaled::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++)
- {
- FontFaceHandleScaled* 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;
-}
-
-FontFaceLayer* FontFaceHandleScaled::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 FontFaceHandleScaled::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/src/ui/FontEngineScaled/FontFaceHandleScaled.h b/src/ui/FontEngineScaled/FontFaceHandleScaled.h
deleted file mode 100644
index 609349f..0000000
--- a/src/ui/FontEngineScaled/FontFaceHandleScaled.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FONTFACEHANDLE_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTFACEHANDLE_H
-
-#include "RmlUi/Core.h"
-///FontEffect.h"
-// #include "../../../Include/RmlUi/Core/FontGlyph.h"
-// #include "../../../Include/RmlUi/Core/FontMetrics.h"
-// #include "../../../Include/RmlUi/Core/Geometry.h"
-// #include "../../../Include/RmlUi/Core/Texture.h"
-// #include "../../../Include/RmlUi/Core/Traits.h"
-#include "FontTypes.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class FontFaceLayer;
-
-/**
- @author Peter Curry
- */
-
-class FontFaceHandleScaled final : public NonCopyMoveable {
-public:
- FontFaceHandleScaled();
- ~FontFaceHandleScaled();
-
- bool Initialize(FontFaceHandleFreetype face, int font_size, bool load_default_glyphs);
-
- const FontMetrics& GetFontMetrics() const;
-
- 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, float letter_spacing, 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.
- /// @param[in] opacity The opacity of the text, should be applied to font effects.
- /// @param[in] layer_configuration Face configuration index to use for generating string.
- /// @return The width, in pixels, of the string geometry.
- int GenerateString(GeometryList& geometry, const String& string, Vector2f position, Colourb colour, float opacity, float letter_spacing,
- 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);
-
- // Build a kerning cache for common characters.
- void FillKerningPairCache();
-
- // Return the kerning for a character pair.
- 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;
- using FontLayerCache = SmallUnorderedMap;
- using LayerConfiguration = Vector;
- using LayerConfigurationList = Vector;
-
- // 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;
-
- // Pre-cache kerning pairs for some ascii subset of all characters.
- using AsciiPair = uint16_t;
- using KerningIntType = int16_t;
- using KerningPairs = UnorderedMap;
- KerningPairs kerning_pair_cache;
-
- bool has_kerning = false;
- bool is_layers_dirty = false;
- int version = 0;
-
- // 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/src/ui/FontEngineScaled/FontFaceLayer.cpp b/src/ui/FontEngineScaled/FontFaceLayer.cpp
deleted file mode 100644
index 51b4913..0000000
--- a/src/ui/FontEngineScaled/FontFaceLayer.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "RmlUi/Core/Log.h"
-#include "RmlUi/Core/RenderInterface.h"
-#include "FontFaceHandleScaled.h"
-#include
-
-namespace RecompRml {
-
-using namespace Rml;
-
-FontFaceLayer::FontFaceLayer(const SharedPtr& _effect) : colour(255, 255, 255)
-{
- effect = _effect;
- if (effect)
- colour = effect->GetColour();
-}
-
-FontFaceLayer::~FontFaceLayer() {}
-
-bool FontFaceLayer::Generate(const FontFaceHandleScaled* 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 FontHandleScaled. We will
- // probably be regenerated soon, just skip the character for now.
- continue;
- }
-
- TextureBox& box = it->second;
-
- Vector2i glyph_origin = Vector2i(box.origin);
- Vector2i glyph_dimensions = Vector2i(box.dimensions);
-
- if (effect->GetGlyphMetrics(glyph_origin, glyph_dimensions, glyph))
- box.origin = Vector2f(glyph_origin);
- 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;
- }
-
- Vector2i scaled_origin = glyph_origin * global_font_scale;
- Vector2i scaled_dimensions = glyph_dimensions * global_font_scale;
- TextureBox box;
- box.origin = Vector2f(float(scaled_origin.x + glyph.bearing.x), float(scaled_origin.y - glyph.bearing.y));
- box.dimensions = Vector2f(scaled_dimensions);
-
- 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)
- {
- const int texture_id = i;
-
- TextureCallback texture_callback = [handle, effect_ptr, texture_id, handle_version](RenderInterface* render_interface,
- const String& /*name*/, TextureHandle& out_texture_handle, Vector2i& out_dimensions) -> bool {
- UniquePtr data;
- if (!handle->GenerateLayerTexture(data, out_dimensions, effect_ptr, texture_id, handle_version) || !data)
- return false;
- if (!render_interface->GenerateTexture(out_texture_handle, data.get(), out_dimensions))
- return false;
- return true;
- };
-
- Texture texture;
- texture.Set("font-face-layer", texture_callback);
- textures.push_back(texture);
- }
- }
-
- return true;
-}
-
-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;
- const int num_bytes_per_line = glyph.bitmap_dimensions.x * (glyph.color_format == ColorFormat::RGBA8 ? 4 : 1);
-
- for (int j = 0; j < glyph.bitmap_dimensions.y; ++j)
- {
- switch (glyph.color_format)
- {
- case ColorFormat::A8:
- {
- for (int k = 0; k < num_bytes_per_line; ++k)
- destination[k * 4 + 3] = source[k];
- }
- break;
- case ColorFormat::RGBA8:
- {
- memcpy(destination, source, num_bytes_per_line);
- }
- break;
- }
-
- destination += rectangle.GetTextureStride();
- source += num_bytes_per_line;
- }
- }
- }
- else
- {
- effect->GenerateGlyphTexture(rectangle.GetTextureData(), Vector2i(box.dimensions), rectangle.GetTextureStride(), glyph);
- }
- }
-
- return true;
-}
-
-const FontEffect* FontFaceLayer::GetFontEffect() const
-{
- return effect.get();
-}
-
-const Texture* FontFaceLayer::GetTexture(int index)
-{
- RMLUI_ASSERT(index >= 0);
- RMLUI_ASSERT(index < GetNumTextures());
-
- return &(textures[index]);
-}
-
-int FontFaceLayer::GetNumTextures() const
-{
- return (int)textures.size();
-}
-
-Colourb FontFaceLayer::GetColour() const
-{
- return colour;
-}
-
-} // namespace Rml
diff --git a/src/ui/FontEngineScaled/FontFaceLayer.h b/src/ui/FontEngineScaled/FontFaceLayer.h
deleted file mode 100644
index 7c98a5d..0000000
--- a/src/ui/FontEngineScaled/FontFaceLayer.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FONTFACELAYER_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTFACELAYER_H
-
-#include "RmlUi/Core.h"
-#include "RmlUi/Core/FontGlyph.h"
-#include "RmlUi/../../Source/Core/TextureLayout.h"
-
-namespace Rml {
- class FontEffect;
-}
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class FontFaceHandleScaled;
-
-/**
- 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 FontFaceHandleScaled* 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& character_vertices = geometry[box.texture_index].GetVertices();
- Vector& 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.
- 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/src/ui/FontEngineScaled/FontFamily.cpp b/src/ui/FontEngineScaled/FontFamily.cpp
deleted file mode 100644
index 661f6e7..0000000
--- a/src/ui/FontEngineScaled/FontFamily.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "RmlUi/Core/ComputedValues.h"
-#include "RmlUi/Core/Math.h"
-#include "FontFace.h"
-#include
-
-namespace RecompRml {
-
-using namespace Rml;
-
-FontFamily::FontFamily(const String& name) : name(name) {}
-
-FontFamily::~FontFamily()
-{
- // Multiple face entries may share memory within a single font family, although only one of them owns it. Here we make sure that all the face
- // destructors are run before all the memory is released. This way we don't leave any hanging references to invalidated memory.
- for (FontFaceEntry& entry : font_faces)
- entry.face.reset();
-}
-
-FontFaceHandleScaled* FontFamily::GetFaceHandle(Style::FontStyle style, Style::FontWeight weight, int size)
-{
- int best_dist = INT_MAX;
- FontFace* matching_face = nullptr;
- for (size_t i = 0; i < font_faces.size(); i++)
- {
- FontFace* face = font_faces[i].face.get();
-
- if (face->GetStyle() == style)
- {
- const int dist = Math::Absolute((int)face->GetWeight() - (int)weight);
- if (dist == 0)
- {
- // Direct match for weight, break the loop early.
- matching_face = face;
- break;
- }
- else if (dist < best_dist)
- {
- // Best match so far for weight, store the face and dist.
- matching_face = face;
- best_dist = dist;
- }
- }
- }
-
- if (!matching_face)
- return nullptr;
-
- return matching_face->GetHandle(size, true);
-}
-
-FontFace* FontFamily::AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, UniquePtr face_memory)
-{
- auto face = MakeUnique(ft_face, style, weight);
- FontFace* result = face.get();
-
- font_faces.push_back(FontFaceEntry{std::move(face), std::move(face_memory)});
-
- return result;
-}
-
-void FontFamily::ReleaseFontResources()
-{
- for (auto& entry : font_faces)
- entry.face->ReleaseFontResources();
-}
-
-} // namespace Rml
diff --git a/src/ui/FontEngineScaled/FontFamily.h b/src/ui/FontEngineScaled/FontFamily.h
deleted file mode 100644
index 1ce2127..0000000
--- a/src/ui/FontEngineScaled/FontFamily.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FONTFAMILY_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTFAMILY_H
-
-#include "FontTypes.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class FontFace;
-class FontFaceHandleScaled;
-
-/**
- @author Peter Curry
- */
-
-class FontFamily {
-public:
- FontFamily(const String& name);
- ~FontFamily();
-
- /// 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.
- FontFaceHandleScaled* 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] face_memory Optionally pass ownership of the face's memory to the face itself, automatically releasing it on destruction.
- /// @return True if the face was loaded successfully, false otherwise.
- FontFace* AddFace(FontFaceHandleFreetype ft_face, Style::FontStyle style, Style::FontWeight weight, UniquePtr face_memory);
-
- /// Releases resources owned by sized font faces, including their textures and rendered glyphs.
- void ReleaseFontResources();
-
-protected:
- String name;
-
- struct FontFaceEntry {
- UniquePtr face;
- // Only filled if we own the memory used by the face's FreeType handle. May be shared with other faces in this family.
- UniquePtr face_memory;
- };
-
- using FontFaceList = Vector;
- FontFaceList font_faces;
-};
-
-} // namespace Rml
-#endif
diff --git a/src/ui/FontEngineScaled/FontProvider.cpp b/src/ui/FontEngineScaled/FontProvider.cpp
deleted file mode 100644
index e41c842..0000000
--- a/src/ui/FontEngineScaled/FontProvider.cpp
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "RmlUi/Core/Core.h"
-#include "RmlUi/Core/FileInterface.h"
-#include "RmlUi/Core/Log.h"
-#include "RmlUi/Core/Math.h"
-#include "RmlUi/Core/StringUtilities.h"
-#include "RmlUi/../../Source/Core/ComputeProperty.h"
-#include "FontFace.h"
-#include "FontFamily.h"
-#include "FreeTypeInterface.h"
-#include
-
-namespace RecompRml {
-
-using 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;
-}
-
-FontFaceHandleScaled* 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();
-}
-
-FontFaceHandleScaled* 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, false);
-
- return nullptr;
-}
-
-void FontProvider::ReleaseFontResources()
-{
- RMLUI_ASSERT(g_font_provider);
- for (auto& name_family : g_font_provider->font_families)
- name_family.second->ReleaseFontResources();
-}
-
-bool FontProvider::LoadFontFace(const String& file_name, bool fallback_face, Style::FontWeight weight)
-{
- 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);
-
- auto buffer_ptr = UniquePtr(new byte[length]);
- byte* buffer = buffer_ptr.get();
- file_interface->Read(buffer, length, handle);
- file_interface->Close(handle);
-
- bool result = Get().LoadFontFace(buffer, (int)length, fallback_face, std::move(buffer_ptr), file_name, {}, Style::FontStyle::Normal, weight);
-
- 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, nullptr, source, font_family, style, weight);
-
- return result;
-}
-
-bool FontProvider::LoadFontFace(const byte* data, int data_size, bool fallback_face, UniquePtr face_memory, const String& source,
- String font_family, Style::FontStyle style, Style::FontWeight weight)
-{
- using Style::FontWeight;
-
- Vector face_variations;
- if (!FreeType::GetFaceVariations(data, data_size, face_variations))
- {
- Log::Message(Log::LT_ERROR, "Failed to load font face from '%s': Invalid or unsupported font face file format.", source.c_str());
- return false;
- }
-
- Vector load_variations;
- if (face_variations.empty())
- {
- load_variations.push_back(FaceVariation{Style::FontWeight::Auto, 0, 0});
- }
- else
- {
- // Iterate through all the face variations and pick the ones to load. The list is already sorted by (weight, width). When weight is set to
- // 'auto' we load all the weights of the face. However, we only want to load one width for each weight.
- for (auto it = face_variations.begin(); it != face_variations.end();)
- {
- if (weight != FontWeight::Auto && it->weight != weight)
- {
- ++it;
- continue;
- }
-
- // We don't currently have any way for users to select widths, so we search for a regular (medium) value here.
- constexpr int search_width = 100;
- const FontWeight current_weight = it->weight;
-
- int best_width_distance = Math::Absolute((int)it->width - search_width);
- auto it_best_width = it;
-
- // Search forward to find the best 'width' with the same weight.
- for (++it; it != face_variations.end(); ++it)
- {
- if (it->weight != current_weight)
- break;
-
- const int width_distance = Math::Absolute((int)it->width - search_width);
- if (width_distance < best_width_distance)
- {
- best_width_distance = width_distance;
- it_best_width = it;
- }
- }
-
- load_variations.push_back(*it_best_width);
- }
- }
-
- if (load_variations.empty())
- {
- Log::Message(Log::LT_ERROR, "Failed to load font face from '%s': Could not locate face with weight %d.", source.c_str(), (int)weight);
- return false;
- }
-
- for (const FaceVariation& variation : load_variations)
- {
- FontFaceHandleFreetype ft_face = FreeType::LoadFace(data, data_size, source, variation.named_instance_index);
- if (!ft_face)
- return false;
-
- if (font_family.empty())
- FreeType::GetFaceStyle(ft_face, &font_family, &style, nullptr);
- if (weight == FontWeight::Auto)
- FreeType::GetFaceStyle(ft_face, nullptr, nullptr, &weight);
-
- const FontWeight variation_weight = (variation.weight == FontWeight::Auto ? weight : variation.weight);
- const String font_face_description = GetFontFaceDescription(font_family, style, variation_weight);
-
- if (!AddFace(ft_face, font_family, style, variation_weight, fallback_face, std::move(face_memory)))
- {
- Log::Message(Log::LT_ERROR, "Failed to load font face %s from '%s'.", font_face_description.c_str(), source.c_str());
- return false;
- }
-
- Log::Message(Log::LT_INFO, "Loaded font face %s from '%s'.", font_face_description.c_str(), source.c_str());
- }
-
- return true;
-}
-
-bool FontProvider::AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face,
- UniquePtr face_memory)
-{
- if (family.empty() || weight == Style::FontWeight::Auto)
- return false;
-
- 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, std::move(face_memory));
-
- 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/src/ui/FontEngineScaled/FontProvider.h b/src/ui/FontEngineScaled/FontProvider.h
deleted file mode 100644
index ca52dc4..0000000
--- a/src/ui/FontEngineScaled/FontProvider.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FONTPROVIDER_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTPROVIDER_H
-
-#include "RmlUi/Core/StyleTypes.h"
-#include "RmlUi/Core/Types.h"
-#include "FontTypes.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class FontFace;
-class FontFamily;
-class FontFaceHandleScaled;
-
-/**
- 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 FontFaceHandleScaled* 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, Style::FontWeight weight = Style::FontWeight::Auto);
-
- /// 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 FontFaceHandleScaled* GetFallbackFontFace(int index, int font_size);
-
- /// Releases resources owned by sized font faces, including their textures and rendered glyphs.
- static void ReleaseFontResources();
-
-private:
- FontProvider();
- ~FontProvider();
-
- static FontProvider& Get();
-
- bool LoadFontFace(const byte* data, int data_size, bool fallback_face, UniquePtr face_memory, const String& source, String font_family,
- Style::FontStyle style, Style::FontWeight weight);
-
- bool AddFace(FontFaceHandleFreetype face, const String& family, Style::FontStyle style, Style::FontWeight weight, bool fallback_face,
- UniquePtr face_memory);
-
- using FontFaceList = Vector;
- using FontFamilyMap = UnorderedMap>;
-
- FontFamilyMap font_families;
- FontFaceList fallback_font_faces;
-
- static const String debugger_font_family_name;
-};
-
-} // namespace Rml
-#endif
diff --git a/src/ui/FontEngineScaled/FontTypes.h b/src/ui/FontEngineScaled/FontTypes.h
deleted file mode 100644
index 8d49aa8..0000000
--- a/src/ui/FontEngineScaled/FontTypes.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FONTTYPES_H
-#define RMLUI_CORE_FONTENGINESCALED_FONTTYPES_H
-
-#include "RmlUi/Core/FontGlyph.h"
-#include "RmlUi/Core/StyleTypes.h"
-#include "RmlUi/Core/Types.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-constexpr int global_font_scale = 1;
-
-using FontFaceHandleFreetype = uintptr_t;
-
-struct FaceVariation {
- Style::FontWeight weight;
- uint16_t width;
- int named_instance_index;
-};
-
-inline bool operator<(const FaceVariation& a, const FaceVariation& b)
-{
- if (a.weight == b.weight)
- return a.width < b.width;
- return a.weight < b.weight;
-}
-
-} // namespace Rml
-#endif
diff --git a/src/ui/FontEngineScaled/FreeTypeInterface.cpp b/src/ui/FontEngineScaled/FreeTypeInterface.cpp
deleted file mode 100644
index b8cdd7b..0000000
--- a/src/ui/FontEngineScaled/FreeTypeInterface.cpp
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "RmlUi/Core/ComputedValues.h"
-#include "RmlUi/Core/FontMetrics.h"
-#include "RmlUi/Core/Log.h"
-#include
-#include
-#include
-#include
-#include FT_FREETYPE_H
-#include FT_MULTIPLE_MASTERS_H
-#include FT_TRUETYPE_TABLES_H
-
-namespace RecompRml {
-
-using namespace Rml;
-
-static FT_Library ft_library = nullptr;
-
-static bool BuildGlyph(FT_Face ft_face, Character character, FontGlyphMap& glyphs, float bitmap_scaling_factor);
-static void BuildGlyphMap(FT_Face ft_face, int size, FontGlyphMap& glyphs, float bitmap_scaling_factor, bool load_default_glyphs);
-static void GenerateMetrics(FT_Face ft_face, FontMetrics& metrics, float bitmap_scaling_factor);
-static bool SetFontSize(FT_Face ft_face, int font_size, float& out_bitmap_scaling_factor);
-static void BitmapDownscale(byte* bitmap_new, int new_width, int new_height, const byte* bitmap_source, int width, int height, int pitch,
- ColorFormat color_format);
-
-static int ConvertFixed16_16ToInt(int32_t fx)
-{
- return fx / 0x10000;
-}
-
-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;
- }
-}
-
-bool FreeType::GetFaceVariations(const byte* data, int data_length, Vector& out_face_variations)
-{
- RMLUI_ASSERT(ft_library);
-
- FT_Face face = nullptr;
- FT_Error error = FT_New_Memory_Face(ft_library, (const FT_Byte*)data, data_length, 0, &face);
- if (error)
- return false;
-
- FT_MM_Var* var = nullptr;
- error = FT_Get_MM_Var(face, &var);
- if (error)
- return true;
-
- unsigned int axis_index_weight = 0;
- unsigned int axis_index_width = 1;
-
- const unsigned int num_axis = var->num_axis;
- for (unsigned int i = 0; i < num_axis; i++)
- {
- switch (var->axis[i].tag)
- {
- case 0x77676874: // 'wght'
- axis_index_weight = i;
- break;
- case 0x77647468: // 'wdth'
- axis_index_width = i;
- break;
- }
- }
-
- if (num_axis > 0)
- {
- for (unsigned int i = 0; i < var->num_namedstyles; i++)
- {
- uint16_t weight = (axis_index_weight < num_axis ? (uint16_t)ConvertFixed16_16ToInt(var->namedstyle[i].coords[axis_index_weight]) : 0);
- uint16_t width = (axis_index_width < num_axis ? (uint16_t)ConvertFixed16_16ToInt(var->namedstyle[i].coords[axis_index_width]) : 0);
- int named_instance_index = (i + 1);
-
- out_face_variations.push_back(FaceVariation{weight == 0 ? Style::FontWeight::Normal : (Style::FontWeight)weight,
- width == 0 ? (uint16_t)100 : width, named_instance_index});
- }
- }
-
- std::sort(out_face_variations.begin(), out_face_variations.end());
-
-#if FREETYPE_MAJOR >= 2 && FREETYPE_MINOR >= 9
- FT_Done_MM_Var(ft_library, var);
-#endif
-
- FT_Done_Face(face);
-
- return true;
-}
-
-FontFaceHandleFreetype FreeType::LoadFace(const byte* data, int data_length, const String& source, int named_style_index)
-{
- RMLUI_ASSERT(ft_library);
-
- FT_Face face = nullptr;
- FT_Error error = FT_New_Memory_Face(ft_library, (const FT_Byte*)data, data_length, (named_style_index << 16), &face);
- if (error)
- {
- 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)
-{
- FT_Face face = (FT_Face)in_face;
- FT_Error error = FT_Done_Face(face);
-
- 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;
-
- if (font_family)
- *font_family = face->family_name;
- if (style)
- *style = face->style_flags & FT_STYLE_FLAG_ITALIC ? Style::FontStyle::Italic : Style::FontStyle::Normal;
-
- if (weight)
- {
- TT_OS2* font_table = (TT_OS2*)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
- if (font_table && font_table->usWeightClass != 0)
- *weight = (Style::FontWeight)font_table->usWeightClass;
- else
- *weight = (face->style_flags & FT_STYLE_FLAG_BOLD) == FT_STYLE_FLAG_BOLD ? Style::FontWeight::Bold : Style::FontWeight::Normal;
- }
-}
-
-bool FreeType::InitialiseFaceHandle(FontFaceHandleFreetype face, int font_size, FontGlyphMap& glyphs, FontMetrics& metrics, bool load_default_glyphs)
-{
- FT_Face ft_face = (FT_Face)face;
-
- metrics.size = font_size;
-
- float bitmap_scaling_factor = 1.0f;
- if (!SetFontSize(ft_face, font_size, bitmap_scaling_factor))
- return false;
-
- // Construct the initial list of glyphs.
- BuildGlyphMap(ft_face, font_size / 4, glyphs, bitmap_scaling_factor, load_default_glyphs);
-
- // Generate the metrics for the handle.
- GenerateMetrics(ft_face, metrics, bitmap_scaling_factor);
-
- 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.
- float bitmap_scaling_factor = 1.0f;
- if (!SetFontSize(ft_face, font_size, bitmap_scaling_factor))
- return false;
-
- if (!BuildGlyph(ft_face, character, glyphs, bitmap_scaling_factor))
- return false;
-
- return true;
-}
-
-int FreeType::GetKerning(FontFaceHandleFreetype face, int font_size, Character lhs, Character rhs)
-{
- FT_Face ft_face = (FT_Face)face;
-
- RMLUI_ASSERT(FT_HAS_KERNING(ft_face));
-
- // Set face size again in case it was used at another size in another font face handle.
- // Font size value of zero assumes it is already set.
- if (font_size > 0)
- {
- float bitmap_scaling_factor = 1.0f;
- if (!SetFontSize(ft_face, font_size, bitmap_scaling_factor) || bitmap_scaling_factor != 1.0f)
- return 0;
- }
-
- FT_Vector ft_kerning;
-
- FT_Error 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;
-}
-
-bool FreeType::HasKerning(FontFaceHandleFreetype face)
-{
- FT_Face ft_face = (FT_Face)face;
-
- return FT_HAS_KERNING(ft_face);
-}
-
-static void BuildGlyphMap(FT_Face ft_face, int size, FontGlyphMap& glyphs, const float bitmap_scaling_factor, const bool load_default_glyphs)
-{
- if (load_default_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, bitmap_scaling_factor);
- }
-
- // 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, const Character character, FontGlyphMap& glyphs, const float bitmap_scaling_factor)
-{
- FT_UInt index = FT_Get_Char_Index(ft_face, (FT_ULong)character);
- if (index == 0)
- return false;
-
- FT_Error error = FT_Load_Glyph(ft_face, index, FT_LOAD_COLOR);
- if (error != 0)
- {
- Log::Message(Log::LT_WARNING, "Unable to load glyph for character '%u' on the font face '%s %s'; error code: %d.", (unsigned int)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.", (unsigned int)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'.", (unsigned int)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 * global_font_scale) >> 6;
- glyph.dimensions.y = (ft_glyph->metrics.height * global_font_scale) >> 6;
-
- // Set the glyph's bearing.
- glyph.bearing.x = (ft_glyph->metrics.horiBearingX * global_font_scale) >> 6;
- glyph.bearing.y = (ft_glyph->metrics.horiBearingY * global_font_scale) >> 6;
-
- // Set the glyph's advance.
- glyph.advance = (ft_glyph->metrics.horiAdvance * global_font_scale) >> 6;
-
- // Set the glyph's bitmap dimensions.
- glyph.bitmap_dimensions.x = ft_glyph->bitmap.width;
- glyph.bitmap_dimensions.y = ft_glyph->bitmap.rows;
-
- // Determine new metrics if we need to scale the bitmap received from FreeType. Only allow bitmap downscaling.
- const bool scale_bitmap = (bitmap_scaling_factor < 1.f);
- if (scale_bitmap)
- {
- glyph.dimensions = Vector2i(Vector2f(glyph.dimensions) * bitmap_scaling_factor);
- glyph.bearing = Vector2i(Vector2f(glyph.bearing) * bitmap_scaling_factor);
- glyph.advance = int(float(glyph.advance) * bitmap_scaling_factor);
- glyph.bitmap_dimensions = Vector2i(Vector2f(glyph.bitmap_dimensions) * bitmap_scaling_factor);
- }
-
- // 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 if the pixel mode is supported.
- if (ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO && ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY &&
- ft_glyph->bitmap.pixel_mode != FT_PIXEL_MODE_BGRA)
- {
- 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 if (ft_glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO && scale_bitmap)
- {
- Log::Message(Log::LT_WARNING, "Unable to render glyph on the font face '%s %s': bitmap scaling unsupported in mono pixel mode.",
- ft_glyph->face->family_name, ft_glyph->face->style_name);
- }
- else
- {
- const int num_bytes_per_pixel = (ft_glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 1);
- glyph.color_format = (ft_glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? ColorFormat::RGBA8 : ColorFormat::A8);
-
- glyph.bitmap_owned_data.reset(new byte[glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y * num_bytes_per_pixel]);
- glyph.bitmap_data = glyph.bitmap_owned_data.get();
- byte* destination_bitmap = glyph.bitmap_owned_data.get();
- const byte* source_bitmap = ft_glyph->bitmap.buffer;
-
- // Copy the bitmap data into the newly-allocated space on our glyph.
- switch (ft_glyph->bitmap.pixel_mode)
- {
- case FT_PIXEL_MODE_MONO:
- {
- // Unpack 1-bit data into 8-bit.
- 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;
- case FT_PIXEL_MODE_GRAY:
- case FT_PIXEL_MODE_BGRA:
- {
- if (scale_bitmap)
- {
- // Resize the glyph data to the new dimensions.
- BitmapDownscale(destination_bitmap, glyph.bitmap_dimensions.x, glyph.bitmap_dimensions.y, source_bitmap,
- (int)ft_glyph->bitmap.width, (int)ft_glyph->bitmap.rows, ft_glyph->bitmap.pitch, glyph.color_format);
- }
- else
- {
- // Copy the glyph data directly.
- const int num_bytes_per_line = glyph.bitmap_dimensions.x * num_bytes_per_pixel;
- for (int i = 0; i < glyph.bitmap_dimensions.y; ++i)
- {
- memcpy(destination_bitmap, source_bitmap, num_bytes_per_line);
- destination_bitmap += num_bytes_per_line;
- source_bitmap += ft_glyph->bitmap.pitch;
- }
- }
-
- if (glyph.color_format == ColorFormat::RGBA8)
- {
- // Swizzle channels (BGRA -> RGBA) and un-premultiply alpha.
- destination_bitmap = glyph.bitmap_owned_data.get();
-
- for (int k = 0; k < glyph.bitmap_dimensions.x * glyph.bitmap_dimensions.y * num_bytes_per_pixel; k += 4)
- {
- byte b = destination_bitmap[k];
- byte g = destination_bitmap[k + 1];
- byte r = destination_bitmap[k + 2];
- const byte alpha = destination_bitmap[k + 3];
- RMLUI_ASSERTMSG(b <= alpha && g <= alpha && r <= alpha, "Assumption of glyph data being premultiplied is broken.");
-
- if (alpha > 0 && alpha < 255)
- {
- b = byte((b * 255) / alpha);
- g = byte((g * 255) / alpha);
- r = byte((r * 255) / alpha);
- }
-
- destination_bitmap[k] = r;
- destination_bitmap[k + 1] = g;
- destination_bitmap[k + 2] = b;
- destination_bitmap[k + 3] = alpha;
- }
- }
- }
- break;
- }
- }
- }
-
- return true;
-}
-
-static void GenerateMetrics(FT_Face ft_face, FontMetrics& metrics, float bitmap_scaling_factor)
-{
- metrics.ascent = ft_face->size->metrics.ascender * bitmap_scaling_factor * global_font_scale / float(1 << 6);
- metrics.descent = -ft_face->size->metrics.descender * bitmap_scaling_factor * global_font_scale / float(1 << 6);
- metrics.line_spacing = ft_face->size->metrics.height * bitmap_scaling_factor * global_font_scale / float(1 << 6);
-
- metrics.underline_position = FT_MulFix(-ft_face->underline_position, ft_face->size->metrics.y_scale) * bitmap_scaling_factor * global_font_scale / float(1 << 6);
- metrics.underline_thickness = FT_MulFix(ft_face->underline_thickness, ft_face->size->metrics.y_scale) * bitmap_scaling_factor * global_font_scale / float(1 << 6);
- metrics.underline_thickness = Math::Max(metrics.underline_thickness, 1.0f);
-
- // Determine the x-height of this font face.
- FT_UInt index = FT_Get_Char_Index(ft_face, 'x');
- if (index != 0 && FT_Load_Glyph(ft_face, index, 0) == 0)
- metrics.x_height = ft_face->glyph->metrics.height * bitmap_scaling_factor * global_font_scale / float(1 << 6);
- else
- metrics.x_height = 0.5f * metrics.line_spacing;
-}
-
-static bool SetFontSize(FT_Face ft_face, int font_size, float& out_bitmap_scaling_factor)
-{
- RMLUI_ASSERT(out_bitmap_scaling_factor == 1.f);
- font_size /= global_font_scale;
-
- FT_Error error = 0;
-
- // Set the character size on the font face.
- error = FT_Set_Char_Size(ft_face, 0, font_size << 6, 0, 0);
-
- // If setting char size fails, try to select a bitmap strike instead when available.
- if (error != 0 && FT_HAS_FIXED_SIZES(ft_face))
- {
- constexpr int a_big_number = INT_MAX / 2;
- int heuristic_min = INT_MAX;
- int index_min = -1;
-
- // Select the bitmap strike with the smallest size *above* font_size, or else the largest size.
- for (int i = 0; i < ft_face->num_fixed_sizes; i++)
- {
- const int size_diff = ft_face->available_sizes[i].height - font_size;
- const int heuristic = (size_diff < 0 ? a_big_number - size_diff : size_diff);
-
- if (heuristic < heuristic_min)
- {
- index_min = i;
- heuristic_min = heuristic;
- }
- }
-
- if (index_min >= 0)
- {
- out_bitmap_scaling_factor = float(font_size) / ft_face->available_sizes[index_min].height;
-
- // Add some tolerance to the scaling factor to avoid unnecessary scaling. Only allow downscaling.
- constexpr float bitmap_scaling_factor_threshold = 0.95f;
- if (out_bitmap_scaling_factor >= bitmap_scaling_factor_threshold)
- out_bitmap_scaling_factor = 1.f;
-
- error = FT_Select_Size(ft_face, index_min);
- }
- }
-
- 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;
- }
-
- return true;
-}
-
-static void BitmapDownscale(byte* bitmap_new, const int new_width, const int new_height, const byte* bitmap_source, const int width, const int height,
- const int pitch, const ColorFormat color_format)
-{
- // Average filter for downscaling bitmap images, based on https://stackoverflow.com/a/9571580
- constexpr int max_num_channels = 4;
- const int num_channels = (color_format == ColorFormat::RGBA8 ? 4 : 1);
-
- const float xscale = float(new_width) / width;
- const float yscale = float(new_height) / height;
- const float sumscale = xscale * yscale;
-
- float yend = 0.0f;
- for (int f = 0; f < new_height; f++) // y on output
- {
- const float ystart = yend;
- yend = (f + 1) * (1.f / yscale);
- if (yend >= height)
- yend = height - 0.001f;
-
- float xend = 0.0;
- for (int g = 0; g < new_width; g++) // x on output
- {
- float xstart = xend;
- xend = (g + 1) * (1.f / xscale);
- if (xend >= width)
- xend = width - 0.001f;
-
- float sum[max_num_channels] = {};
- for (int y = (int)ystart; y <= (int)yend; ++y)
- {
- float yportion = 1.0f;
- if (y == (int)ystart)
- yportion -= ystart - y;
- if (y == (int)yend)
- yportion -= y + 1 - yend;
-
- for (int x = (int)xstart; x <= (int)xend; ++x)
- {
- float xportion = 1.0f;
- if (x == (int)xstart)
- xportion -= xstart - x;
- if (x == (int)xend)
- xportion -= x + 1 - xend;
-
- for (int i = 0; i < num_channels; i++)
- sum[i] += bitmap_source[y * pitch + x * num_channels + i] * yportion * xportion;
- }
- }
-
- for (int i = 0; i < num_channels; i++)
- bitmap_new[(f * new_width + g) * num_channels + i] = (byte)Math::Min(sum[i] * sumscale, 255.f);
- }
- }
-}
-
-} // namespace Rml
diff --git a/src/ui/FontEngineScaled/FreeTypeInterface.h b/src/ui/FontEngineScaled/FreeTypeInterface.h
deleted file mode 100644
index fa26755..0000000
--- a/src/ui/FontEngineScaled/FreeTypeInterface.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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_FONTENGINESCALED_FREETYPEINTERFACE_H
-#define RMLUI_CORE_FONTENGINESCALED_FREETYPEINTERFACE_H
-
-#include "RmlUi/Core/FontMetrics.h"
-#include "FontTypes.h"
-
-namespace RecompRml {
-
-using namespace Rml;
-
-namespace FreeType {
-
- // Initialize FreeType library.
- bool Initialise();
- // Shutdown FreeType library.
- void Shutdown();
-
- // Returns a sorted list of available font variations for the font face located in memory.
- bool GetFaceVariations(const byte* data, int data_length, Vector& out_face_variations);
-
- // Loads a FreeType face from memory, 'source' is only used for logging.
- FontFaceHandleFreetype LoadFace(const byte* data, int data_length, const String& source, int named_instance_index = 0);
-
- // Releases the FreeType face.
- bool ReleaseFace(FontFaceHandleFreetype face);
-
- // Retrieves the font family, style and weight of the given font face. Use nullptr to ignore a property.
- 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, bool load_default_glyphs);
-
- // 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.
- // 'font_size' value of zero assumes the font size is already set on the face, and skips this step for performance reasons.
- int GetKerning(FontFaceHandleFreetype face, int font_size, Character lhs, Character rhs);
-
- // Returns true if the font face has kerning.
- bool HasKerning(FontFaceHandleFreetype face);
-
-} // namespace FreeType
-} // namespace Rml
-#endif
diff --git a/src/ui/ScaledSVG/ElementScaledSVG.cpp b/src/ui/ScaledSVG/ElementScaledSVG.cpp
deleted file mode 100644
index 0b99ee3..0000000
--- a/src/ui/ScaledSVG/ElementScaledSVG.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION 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 "ElementScaledSVG.h"
-#include "../FontEngineScaled/FontTypes.h"
-#include "RmlUi/Core/ComputedValues.h"
-#include "RmlUi/Core/Core.h"
-#include "RmlUi/Core/ElementDocument.h"
-#include "RmlUi/Core/FileInterface.h"
-#include "RmlUi/Core/GeometryUtilities.h"
-#include "RmlUi/Core/Math.h"
-#include "RmlUi/Core/PropertyIdSet.h"
-#include "RmlUi/Core/RenderInterface.h"
-#include "RmlUi/Core/SystemInterface.h"
-#include
-#include
-#include
-
-namespace RecompRml {
-
-using namespace Rml;
-
-ElementScaledSVG::ElementScaledSVG(const String& tag) : Element(tag) {}
-
-ElementScaledSVG::~ElementScaledSVG() {}
-
-bool ElementScaledSVG::GetIntrinsicDimensions(Vector2f& dimensions, float& ratio)
-{
- if (source_dirty)
- LoadSource();
-
- dimensions = intrinsic_dimensions;
-
- if (HasAttribute("width"))
- {
- dimensions.x = GetAttribute("width", -1);
- }
- if (HasAttribute("height"))
- {
- dimensions.y = GetAttribute("height", -1);
- }
-
- if (dimensions.y > 0)
- ratio = dimensions.x / dimensions.y;
-
- return true;
-}
-
-void ElementScaledSVG::OnRender()
-{
- if (svg_document)
- {
- if (geometry_dirty)
- GenerateGeometry();
-
- UpdateTexture();
- geometry.Render(GetAbsoluteOffset(BoxArea::Content));
- }
-}
-
-void ElementScaledSVG::OnResize()
-{
- geometry_dirty = true;
- texture_dirty = true;
-}
-
-void ElementScaledSVG::OnAttributeChange(const ElementAttributes& changed_attributes)
-{
- Element::OnAttributeChange(changed_attributes);
-
- if (changed_attributes.count("src"))
- {
- source_dirty = true;
- DirtyLayout();
- }
-
- if (changed_attributes.find("width") != changed_attributes.end() || changed_attributes.find("height") != changed_attributes.end())
- {
- DirtyLayout();
- }
-}
-
-void ElementScaledSVG::OnPropertyChange(const PropertyIdSet& changed_properties)
-{
- Element::OnPropertyChange(changed_properties);
-
- if (changed_properties.Contains(PropertyId::ImageColor) || changed_properties.Contains(PropertyId::Opacity))
- {
- geometry_dirty = true;
- }
-}
-
-void ElementScaledSVG::GenerateGeometry()
-{
- geometry.Release(true);
-
- Vector& vertices = geometry.GetVertices();
- Vector& indices = geometry.GetIndices();
-
- vertices.resize(4);
- indices.resize(6);
-
- Vector2f texcoords[2] = {
- {0.0f, 0.0f},
- {1.0f, 1.0f},
- };
-
- const ComputedValues& computed = GetComputedValues();
-
- const float opacity = computed.opacity();
- Colourb quad_colour = computed.image_color();
- quad_colour.alpha = (byte)(opacity * (float)quad_colour.alpha);
-
- const Vector2f render_dimensions_f = GetBox().GetSize(BoxArea::Content).Round();
- render_dimensions.x = int(render_dimensions_f.x) / RecompRml::global_font_scale;
- render_dimensions.y = int(render_dimensions_f.y) / RecompRml::global_font_scale;
-
- GeometryUtilities::GenerateQuad(&vertices[0], &indices[0], Vector2f(0, 0), render_dimensions_f, quad_colour, texcoords[0], texcoords[1]);
-
- geometry_dirty = false;
-}
-
-bool ElementScaledSVG::LoadSource()
-{
- source_dirty = false;
- texture_dirty = true;
- intrinsic_dimensions = Vector2f{};
- geometry.SetTexture(nullptr);
- svg_document.reset();
-
- const String attribute_src = GetAttribute("src", "");
-
- if (attribute_src.empty())
- return false;
-
- String path = attribute_src;
- String directory;
-
- if (ElementDocument* document = GetOwnerDocument())
- {
- const String document_source_url = StringUtilities::Replace(document->GetSourceURL(), '|', ':');
- GetSystemInterface()->JoinPath(path, document_source_url, attribute_src);
- GetSystemInterface()->JoinPath(directory, document_source_url, "");
- }
-
- String svg_data;
-
- if (path.empty() || !GetFileInterface()->LoadFile(path, svg_data))
- {
- Log::Message(Rml::Log::Type::LT_WARNING, "Could not load SVG file %s", path.c_str());
- return false;
- }
-
- // We use a reset-release approach here in case clients use a non-std unique_ptr (lunasvg uses std::unique_ptr)
- svg_document.reset(lunasvg::Document::loadFromData(svg_data).release());
-
- if (!svg_document)
- {
- Log::Message(Rml::Log::Type::LT_WARNING, "Could not load SVG data from file %s", path.c_str());
- return false;
- }
-
- intrinsic_dimensions.x = Math::Max(float(svg_document->width()), 1.0f);
- intrinsic_dimensions.y = Math::Max(float(svg_document->height()), 1.0f);
-
- return true;
-}
-
-void ElementScaledSVG::UpdateTexture()
-{
- if (!svg_document || !texture_dirty)
- return;
-
- // Callback for generating texture.
- auto p_callback = [this](RenderInterface* render_interface, const String& /*name*/, TextureHandle& out_handle, Vector2i& out_dimensions) -> bool {
- RMLUI_ASSERT(svg_document);
- lunasvg::Bitmap bitmap = svg_document->renderToBitmap(render_dimensions.x, render_dimensions.y);
- if (!bitmap.valid() || !bitmap.data())
- return false;
- if (!render_interface->GenerateTexture(out_handle, reinterpret_cast(bitmap.data()), render_dimensions))
- return false;
- out_dimensions = render_dimensions;
- return true;
- };
-
- texture.Set("svg", p_callback);
- geometry.SetTexture(&texture);
- texture_dirty = false;
-}
-
-} // namespace Rml
diff --git a/src/ui/ScaledSVG/ElementScaledSVG.h b/src/ui/ScaledSVG/ElementScaledSVG.h
deleted file mode 100644
index 6c73cac..0000000
--- a/src/ui/ScaledSVG/ElementScaledSVG.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * This source file is modified from a part of RmlUi, the HTML/CSS Interface Middleware
- *
- * For the latest information, see http://github.com/mikke89/RmlUi
- *
- * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
- * Copyright (c) 2019-2023 The RmlUi Team, and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- */
-
-#ifndef RMLUI_SVG_ELEMENT_SCALEDSVG_H
-#define RMLUI_SVG_ELEMENT_SCALEDSVG_H
-
-#include "RmlUi/Core/Element.h"
-#include "RmlUi/Core/Geometry.h"
-#include "RmlUi/Core/Header.h"
-#include "RmlUi/Core/Texture.h"
-
-namespace lunasvg {
-class Document;
-}
-
-namespace RecompRml {
-
-using namespace Rml;
-
-class RMLUICORE_API ElementScaledSVG : public Element {
-public:
- RMLUI_RTTI_DefineWithParent(ElementScaledSVG, Element)
-
- ElementScaledSVG(const String& tag);
- virtual ~ElementScaledSVG();
-
- /// Returns the element's inherent size.
- bool GetIntrinsicDimensions(Vector2f& dimensions, float& ratio) 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 SVG document specified by the 'src' attribute.
- bool LoadSource();
- // Update the texture when necessary.
- void UpdateTexture();
-
- bool source_dirty = false;
- bool geometry_dirty = false;
- bool texture_dirty = false;
-
- // The texture this element is rendering from.
- Texture texture;
-
- // The image's intrinsic dimensions.
- Vector2f intrinsic_dimensions;
- // The element's size for rendering.
- Vector2i render_dimensions;
-
- // The geometry used to render this element.
- Geometry geometry;
-
- UniquePtr svg_document;
-};
-
-} // namespace Rml
-
-#endif
diff --git a/src/ui/ui_color_hack.cpp b/src/ui/ui_color_hack.cpp
index 7f555ff..3bd5e74 100644
--- a/src/ui/ui_color_hack.cpp
+++ b/src/ui/ui_color_hack.cpp
@@ -4,6 +4,8 @@
#include "recomp_ui.h"
#include
+using ColourMap = Rml::UnorderedMap;
+
namespace recomp {
class PropertyParserColorHack : public Rml::PropertyParser {
public:
@@ -11,8 +13,7 @@ namespace recomp {
virtual ~PropertyParserColorHack();
bool ParseValue(Rml::Property& property, const Rml::String& value, const Rml::ParameterMap& /*parameters*/) const override;
private:
- using ColourMap = Rml::UnorderedMap;
- ColourMap html_colours;
+ static ColourMap html_colours;
};
static_assert(sizeof(PropertyParserColorHack) == sizeof(Rml::PropertyParserColour));
PropertyParserColorHack::PropertyParserColorHack() {
@@ -165,4 +166,6 @@ namespace recomp {
// Copy the allocated object into the color parser pointer to overwrite its vtable.
memcpy((void*)Rml::StyleSheetSpecification::GetParser("color"), (void*)new_parser, sizeof(*new_parser));
}
+
+ ColourMap PropertyParserColorHack::html_colours{};
}
diff --git a/src/ui/ui_renderer.cpp b/src/ui/ui_renderer.cpp
index df49321..34a952a 100644
--- a/src/ui/ui_renderer.cpp
+++ b/src/ui/ui_renderer.cpp
@@ -18,6 +18,7 @@
#include "RmlUi/Core.h"
#include "RmlUi/Debugger.h"
+#include "RmlUi/Core/RenderInterfaceCompatibility.h"
#include "RmlUi/../../Source/Core/Elements/ElementLabel.h"
#include "RmlUi_Platform_SDL.h"
@@ -29,10 +30,6 @@
# include "InterfacePS.hlsl.dxil.h"
#endif
-#include "FontEngineScaled/FontEngineInterfaceScaled.h"
-#include "FontEngineScaled/FontTypes.h"
-#include "ScaledSVG/ElementScaledSVG.h"
-
#ifdef _WIN32
# define GET_SHADER_BLOB(name, format) \
((format) == RT64::RenderShaderFormat::SPIRV ? name##BlobSPIRV : \
@@ -98,7 +95,7 @@ T from_bytes_le(const char* input) {
void load_document();
-class RmlRenderInterface_RT64 : public Rml::RenderInterface {
+class RmlRenderInterface_RT64 : public Rml::RenderInterfaceCompatibility {
static constexpr uint32_t per_frame_descriptor_set = 0;
static constexpr uint32_t per_draw_descriptor_set = 1;
@@ -246,7 +243,7 @@ public:
screen_vertex_buffer_size_ = sizeof(Rml::Vertex) * 3;
screen_vertex_buffer_ = render_context->device->createBuffer(RT64::RenderBufferDesc::VertexBuffer(screen_vertex_buffer_size_, RT64::RenderHeapType::UPLOAD));
Rml::Vertex *vertices = (Rml::Vertex *)(screen_vertex_buffer_->map());
- const Rml::Colourb white(255, 255, 255, 255);
+ const Rml::ColourbPremultiplied white(255, 255, 255, 255);
vertices[0] = Rml::Vertex{ Rml::Vector2f(-1.0f, 1.0f), white, Rml::Vector2f(0.0f, 0.0f) };
vertices[1] = Rml::Vertex{ Rml::Vector2f(-1.0f, -3.0f), white, Rml::Vector2f(0.0f, 2.0f) };
vertices[2] = Rml::Vertex{ Rml::Vector2f(3.0f, 1.0f), white, Rml::Vector2f(2.0f, 0.0f) };
@@ -384,10 +381,10 @@ public:
list_->setViewports(RT64::RenderViewport{ 0, 0, float(window_width_), float(window_height_) });
if (scissor_enabled_) {
list_->setScissors(RT64::RenderRect{
- scissor_x_ / RecompRml::global_font_scale,
- scissor_y_ / RecompRml::global_font_scale,
- (scissor_width_ + scissor_x_) / RecompRml::global_font_scale,
- (scissor_height_ + scissor_y_) / RecompRml::global_font_scale });
+ scissor_x_,
+ scissor_y_,
+ (scissor_width_ + scissor_x_),
+ (scissor_height_ + scissor_y_) });
}
else {
list_->setScissors(RT64::RenderRect{ 0, 0, window_width_, window_height_ });
@@ -610,7 +607,7 @@ public:
window_width_ = image_width;
window_height_ = image_height;
- projection_mtx_ = Rml::Matrix4f::ProjectOrtho(0.0f, float(image_width * RecompRml::global_font_scale), float(image_height * RecompRml::global_font_scale), 0.0f, -10000, 10000);
+ projection_mtx_ = Rml::Matrix4f::ProjectOrtho(0.0f, float(image_width), float(image_height), 0.0f, -10000, 10000);
recalculate_mvp();
// The following code assumes command lists aren't double buffered.
@@ -781,8 +778,6 @@ struct UIContext {
int last_active_mouse_position[2] = {0, 0};
std::unique_ptr system_interface;
std::unique_ptr render_interface;
- std::unique_ptr font_interface;
- std::unique_ptr svg_instancer;
Rml::Context* context;
recomp::UiEventListenerInstancer event_listener_instancer;
@@ -1019,17 +1014,10 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
ui_context->rml.make_event_listeners();
Rml::SetSystemInterface(ui_context->rml.system_interface.get());
- Rml::SetRenderInterface(ui_context->rml.render_interface.get());
+ Rml::SetRenderInterface(ui_context->rml.render_interface.get()->GetAdaptedInterface());
Rml::Factory::RegisterEventListenerInstancer(&ui_context->rml.event_listener_instancer);
-
- ui_context->rml.font_interface = std::make_unique();
- Rml::SetFontEngineInterface(ui_context->rml.font_interface.get());
Rml::Initialise();
-
- ui_context->rml.svg_instancer = std::make_unique>();
-
- Rml::Factory::RegisterElementInstancer("svg", ui_context->rml.svg_instancer.get());
// Apply the hack to replace RmlUi's default color parser with one that conforms to HTML5 alpha parsing for SASS compatibility
recomp::apply_color_hack();
@@ -1037,7 +1025,7 @@ void init_hook(RT64::RenderInterface* interface, RT64::RenderDevice* device) {
int width, height;
SDL_GetWindowSizeInPixels(window, &width, &height);
- ui_context->rml.context = Rml::CreateContext("main", Rml::Vector2i(width * RecompRml::global_font_scale, height * RecompRml::global_font_scale));
+ ui_context->rml.context = Rml::CreateContext("main", Rml::Vector2i(width, height));
ui_context->rml.make_bindings();
Rml::Debugger::Initialise(ui_context->rml.context);
@@ -1164,31 +1152,6 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
while (recomp::try_deque_event(cur_event)) {
bool menu_is_open = cur_menu != recomp::Menu::None;
- // Scale coordinates for mouse and window events based on the UI scale
- switch (cur_event.type) {
- case SDL_EventType::SDL_MOUSEMOTION:
- cur_event.motion.x *= RecompRml::global_font_scale;
- cur_event.motion.y *= RecompRml::global_font_scale;
- cur_event.motion.xrel *= RecompRml::global_font_scale;
- cur_event.motion.yrel *= RecompRml::global_font_scale;
- break;
- case SDL_EventType::SDL_MOUSEBUTTONDOWN:
- case SDL_EventType::SDL_MOUSEBUTTONUP:
- cur_event.button.x *= RecompRml::global_font_scale;
- cur_event.button.y *= RecompRml::global_font_scale;
- break;
- case SDL_EventType::SDL_MOUSEWHEEL:
- cur_event.wheel.x *= RecompRml::global_font_scale;
- cur_event.wheel.y *= RecompRml::global_font_scale;
- break;
- case SDL_EventType::SDL_WINDOWEVENT:
- if (cur_event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
- cur_event.window.data1 *= RecompRml::global_font_scale;
- cur_event.window.data2 *= RecompRml::global_font_scale;
- }
- break;
- }
-
if (!recomp::all_input_disabled()) {
// Implement some additional behavior for specific events on top of what RmlUi normally does with them.
switch (cur_event.type) {
@@ -1298,7 +1261,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
int height = swap_chain_framebuffer->getHeight();
// Scale the UI based on the window size with 1080 vertical resolution as the reference point.
- ui_context->rml.context->SetDensityIndependentPixelRatio((height * RecompRml::global_font_scale) / 1080.0f);
+ ui_context->rml.context->SetDensityIndependentPixelRatio((height) / 1080.0f);
ui_context->rml.render_interface->start(command_list, width, height);
@@ -1306,7 +1269,7 @@ void draw_hook(RT64::RenderCommandList* command_list, RT64::RenderFramebuffer* s
static int prev_height = 0;
if (prev_width != width || prev_height != height) {
- ui_context->rml.context->SetDimensions({ (int)(width * RecompRml::global_font_scale), (int)(height * RecompRml::global_font_scale) });
+ ui_context->rml.context->SetDimensions({ width, height });
}
prev_width = width;
prev_height = height;
@@ -1339,7 +1302,6 @@ void recomp::set_config_submenu(recomp::ConfigSubmenu submenu) {
void recomp::destroy_ui() {
std::lock_guard lock {ui_context_mutex};
Rml::Debugger::Shutdown();
- ui_context->rml.font_interface.reset();
Rml::Shutdown();
ui_context->rml.unload();
ui_context.reset();