Merge branch 'DRTVWR-489-emoji' of https://github.com/secondlife/viewer
# Conflicts: # autobuild.xml # indra/llrender/llfontfreetype.cpp # indra/llrender/llfontregistry.cpp # indra/llui/lltextbase.cpp # indra/llui/lltextbase.h # indra/llui/lltexteditor.cpp # indra/newview/llviewermenu.cpp # indra/newview/llworldmapview.cpp # indra/newview/skins/default/xui/en/widgets/chat_editor.xmlmaster
commit
9e3079f859
|
|
@ -47,6 +47,7 @@ indra/newview/dbghelp.dll
|
|||
indra/newview/filters.xml
|
||||
indra/newview/fmod.dll
|
||||
indra/newview/fmod.log
|
||||
indra/newview/fonts
|
||||
indra/newview/mozilla-theme
|
||||
indra/newview/mozilla-universal-darwin.tgz
|
||||
indra/newview/pilot.txt
|
||||
|
|
|
|||
228
autobuild.xml
228
autobuild.xml
|
|
@ -606,9 +606,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>fedc8d63856f534b6098102e059dc548</string>
|
||||
<string>cae490999f05151e3a048b00d64237bb</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87776/805857/boost-1.72-darwin64-563847.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109513/952781/boost-1.72-darwin64-577704.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -630,9 +630,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6cc9fb4ca21365c4470a3e516544ba71</string>
|
||||
<string>aa0f955996442b8d7097447de1f5a9fe</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87784/805850/boost-1.72-windows-563847.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109516/952793/boost-1.72-windows-577704.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -642,9 +642,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>0c526efc3f8825cd25cdf635e238fab3</string>
|
||||
<string>d3738a7ea84e2569017ae0237526da36</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87783/805851/boost-1.72-windows64-563847.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109515/952797/boost-1.72-windows64-577704.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
|
|
@ -724,9 +724,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>f283a064c30695bd7bf071f1bd481f32</string>
|
||||
<string>b923ca041271446592b3b10e678b93b6</string>
|
||||
<key>url</key>
|
||||
<string>https://3p.firestormviewer.org/colladadom-2.3.222232011-darwin64-222232011.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109517/952832/colladadom-2.3.577706-darwin64-577706.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -748,9 +748,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>1c094d709a35b252bba7b6ef1871085c</string>
|
||||
<string>26f3e24adbd0bbb6ed002f5eb61c64ab</string>
|
||||
<key>url</key>
|
||||
<string>https://3p.firestormviewer.org/colladadom-2.3.222231850-windows-222231850.tar.bz2</string>
|
||||
<string>https://3p.firestormviewer.org/colladadom-2.3.230231147-windows-230231147.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -760,16 +760,16 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>a7596da3696fc423ec1bc7d6764c01ab</string>
|
||||
<string>231a7ce499126806e051490d81591fec</string>
|
||||
<key>url</key>
|
||||
<string>https://3p.firestormviewer.org/colladadom-2.3.222231903-windows64-222231903.tar.bz2</string>
|
||||
<string>https://3p.firestormviewer.org/colladadom-2.3.230231451-windows64-230231451.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>2.3.569219</string>
|
||||
<string>2.3.577706</string>
|
||||
</map>
|
||||
<key>cubemaptoequirectangular</key>
|
||||
<map>
|
||||
|
|
@ -1188,9 +1188,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>8865739d8e530199dacb3c3042c1bc01</string>
|
||||
<string>4390c5182b5d6c397ef0396828093600</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87777/805782/freetype-2.4.4.563848-darwin64-563848.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/106585/931193/freetype-2.12.1.576132-darwin64-576132.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -1212,9 +1212,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>90d94d031bc27bcefe3473432d6fa213</string>
|
||||
<string>6ad01c23db703cd6ad2a491aae937379</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/freetype-2.3.9.220141015-windows-220141015.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/106586/931203/freetype-2.12.1.576132-windows-576132.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -1224,16 +1224,16 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c5d76132e28039d1785a1719594b8418</string>
|
||||
<string>db5f433b65a268a1ea601d7e29766cb1</string>
|
||||
<key>url</key>
|
||||
<string>http://3p.firestormviewer.org/freetype-2.3.9.220141018-windows64-220141018.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/106587/931202/freetype-2.12.1.576132-windows64-576132.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>2.4.4.563848</string>
|
||||
<string>2.12.1.576132</string>
|
||||
</map>
|
||||
<key>glext</key>
|
||||
<map>
|
||||
|
|
@ -1374,9 +1374,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7d267050970ec6e28749178597bc8af0</string>
|
||||
<string>47303c9bb9a06c6f488f9d7b2b2282c4</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87793/805930/googlemock-1.7.0.563853-windows-563853.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109524/952870/googlemock-1.7.0.577708-windows-577708.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -1386,16 +1386,16 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>27638c692f0ec6121e54bf75f2d45e49</string>
|
||||
<string>c166bbd8787a68c1a4ba75179c58dda6</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/87792/805936/googlemock-1.7.0.563853-windows64-563853.tar.bz2</string>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109525/952878/googlemock-1.7.0.577708-windows64-577708.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.7.0.563853</string>
|
||||
<string>1.7.0.577708</string>
|
||||
</map>
|
||||
<key>gstreamer</key>
|
||||
<map>
|
||||
|
|
@ -1491,6 +1491,62 @@
|
|||
<key>version</key>
|
||||
<string>2012.1-2</string>
|
||||
</map>
|
||||
<key>icu4c</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-icu4c</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 1995-2011 International Business Machines Corporation and others <http://source.icu-project.org></string>
|
||||
<key>description</key>
|
||||
<string>ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.</string>
|
||||
<key>license</key>
|
||||
<string>ICU, permissive non-copyleft free software license</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/icu.txt</string>
|
||||
<key>name</key>
|
||||
<string>icu4c</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>635f18fa4de7f38308d10da0cb645a4d</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109596/953629/icu4c-4.8.1-darwin64-577750.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>2a2cc981da2565d0e797c7af19891a9b</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109597/953636/icu4c-4.8.1-windows-577750.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>d30663c985b40a638a9a58ba21745fe2</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109598/953645/icu4c-4.8.1-windows64-577750.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>4.8.1</string>
|
||||
</map>
|
||||
<key>jpegencoderbasic</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
@ -2426,6 +2482,74 @@
|
|||
<key>version</key>
|
||||
<string>3.0.2.569217</string>
|
||||
</map>
|
||||
<key>nanosvg</key>
|
||||
<map>
|
||||
<key>canonical_repo</key>
|
||||
<string>https://bitbucket.org/lindenlab/3p-nanosvg</string>
|
||||
<key>copyright</key>
|
||||
<string>Copyright (c) 2013-14 Mikko Mononen</string>
|
||||
<key>description</key>
|
||||
<string>NanoSVG is a simple single-header-file SVG parser and rasterizer</string>
|
||||
<key>license</key>
|
||||
<string>Zlib</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/nanosvg.txt</string>
|
||||
<key>name</key>
|
||||
<string>nanosvg</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>bee6bf71cec184ab26c89c486fc5f427</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109526/952883/nanosvg-2022.09.27-darwin64-577709.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>linux</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>c5a2ae5ecc8ade5a85b674e4426d6403</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/107186/935576/nanosvg-2022.09.27-linux-576467.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b7d1baa8003f64bed4efc2c163ee7e26</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109529/952902/nanosvg-2022.09.27-windows-577709.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b8b51ad6b65be5bbc1470ee939c6bfae</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109528/952895/nanosvg-2022.09.27-windows64-577709.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>2022.09.27</string>
|
||||
</map>
|
||||
<key>nghttp2</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
@ -3177,6 +3301,60 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
|
|||
<key>version</key>
|
||||
<string>0.9.4</string>
|
||||
</map>
|
||||
<key>viewer-fonts</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
<string>Copyright various</string>
|
||||
<key>description</key>
|
||||
<string>Viewer fonts</string>
|
||||
<key>license</key>
|
||||
<string>Various open source</string>
|
||||
<key>license_file</key>
|
||||
<string>LICENSES/fonts.txt</string>
|
||||
<key>name</key>
|
||||
<string>viewer-fonts</string>
|
||||
<key>platforms</key>
|
||||
<map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>7846ea2be3ee6f991f181ec451b02ef5</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109530/952907/viewer_fonts-1.577710-darwin64-577710.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
</map>
|
||||
<key>windows</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6c41e98423d0fdc29b80f5c2d9ccd8bf</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109532/952921/viewer_fonts-1.577710-windows-577710.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
</map>
|
||||
<key>windows64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>48e4986d8c61e80d672439507602cbba</string>
|
||||
<key>url</key>
|
||||
<string>https://automated-builds-secondlife-com.s3.amazonaws.com/ct2/109531/952914/viewer_fonts-1.577710-windows64-577710.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>1.577710</string>
|
||||
</map>
|
||||
<key>viewer-manager</key>
|
||||
<map>
|
||||
<key>copyright</key>
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ set(cmake_SOURCE_FILES
|
|||
FindFMODSTUDIO.cmake
|
||||
FindGLH.cmake
|
||||
FindHUNSPELL.cmake
|
||||
FindICU4C.cmake
|
||||
FindJsonCpp.cmake
|
||||
FindNDOF.cmake
|
||||
FindOpenJPEG.cmake
|
||||
|
|
@ -46,6 +47,7 @@ set(cmake_SOURCE_FILES
|
|||
Growl.cmake
|
||||
Havok.cmake
|
||||
Hunspell.cmake
|
||||
ICU4C.cmake
|
||||
JPEG.cmake
|
||||
JsonCpp.cmake
|
||||
LLAddBuildTest.cmake
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
# - Find ICU4C
|
||||
# This module defines
|
||||
# ICU4C_INCLUDE_DIR, where to find headers
|
||||
# ICU4C_LIBRARY, the library needed to use ICU4C.
|
||||
# ICU4C_FOUND, If false, do not try to use ICU4C.
|
||||
|
||||
find_path(ICU4C_INCLUDE_DIR uchar.h
|
||||
PATH_SUFFIXES unicode
|
||||
)
|
||||
|
||||
set(ICU4C_NAMES ${ICU4C_NAMES} icuuc)
|
||||
find_library(ICU4C_LIBRARY
|
||||
NAMES ${ICU4C_NAMES}
|
||||
)
|
||||
|
||||
if (ICU4C_LIBRARY AND ICU4C_INCLUDE_DIR)
|
||||
set(ICU4C_FOUND "YES")
|
||||
else (ICU4C_LIBRARY AND ICU4C_INCLUDE_DIR)
|
||||
set(ICU4C_FOUND "NO")
|
||||
endif (ICU4C_LIBRARY AND ICU4C_INCLUDE_DIR)
|
||||
|
||||
if (ICU4C_FOUND)
|
||||
message(STATUS "Found ICU4C: Library in '${ICU4C_LIBRARY}' and header in '${ICU4C_INCLUDE_DIR}' ")
|
||||
else (ICU4C_FOUND)
|
||||
message(FATAL_ERROR " * * *\nCould not find ICU4C library! * * *")
|
||||
endif (ICU4C_FOUND)
|
||||
|
||||
mark_as_advanced(
|
||||
ICU4C_LIBRARY
|
||||
ICU4C_INCLUDE_DIR
|
||||
)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
# -*- cmake -*-
|
||||
include(Prebuilt)
|
||||
|
||||
set(ICU4C_FIND_QUIETLY ON)
|
||||
set(ICU4C_FIND_REQUIRED ON)
|
||||
|
||||
if (USESYSTEMLIBS)
|
||||
include(FindICU4C)
|
||||
else (USESYSTEMLIBS)
|
||||
use_prebuilt_binary(icu4c)
|
||||
if (WINDOWS)
|
||||
set(ICU4C_LIBRARY icuuc)
|
||||
#elseif(DARWIN)
|
||||
# set(ICU4C_LIBRARY ...)
|
||||
#elseif(LINUX)
|
||||
# set(ICU4C_LIBRARY ...)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid platform")
|
||||
endif()
|
||||
set(ICU4C_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/unicode)
|
||||
use_prebuilt_binary(dictionaries)
|
||||
endif (USESYSTEMLIBS)
|
||||
|
|
@ -12,3 +12,5 @@ if (NOT USESYSTEMLIBS)
|
|||
# use_prebuilt_binary(libidn)
|
||||
endif(NOT USESYSTEMLIBS)
|
||||
|
||||
use_prebuilt_binary(nanosvg)
|
||||
use_prebuilt_binary(viewer-fonts)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
project(llcommon)
|
||||
|
||||
include(00-Common)
|
||||
include(ICU4C)
|
||||
include(LLCommon)
|
||||
include(bugsplat)
|
||||
include(Linking)
|
||||
|
|
@ -343,6 +344,7 @@ target_link_libraries(
|
|||
${APRUTIL_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${EXPAT_LIBRARIES}
|
||||
${ICU4C_LIBRARY}
|
||||
${JSONCPP_LIBRARIES}
|
||||
${ZLIBNG_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "llerror.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "llsd.h"
|
||||
#include <unicode/uchar.h>
|
||||
#include <vector>
|
||||
|
||||
#if LL_WINDOWS
|
||||
|
|
@ -905,6 +906,31 @@ std::string LLStringOps::sDayFormat;
|
|||
std::string LLStringOps::sAM;
|
||||
std::string LLStringOps::sPM;
|
||||
|
||||
// static
|
||||
bool LLStringOps::isEmoji(llwchar wch)
|
||||
{
|
||||
switch (ublock_getCode(wch))
|
||||
{
|
||||
case UBLOCK_MISCELLANEOUS_SYMBOLS:
|
||||
case UBLOCK_DINGBATS:
|
||||
case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS:
|
||||
case UBLOCK_EMOTICONS:
|
||||
case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS:
|
||||
#if U_ICU_VERSION_MAJOR_NUM > 56
|
||||
// Boost uses ICU so we can't update it independently
|
||||
case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS:
|
||||
#endif // U_ICU_VERSION_MAJOR_NUM > 56
|
||||
return true;
|
||||
default:
|
||||
#if U_ICU_VERSION_MAJOR_NUM > 56
|
||||
return false;
|
||||
#else
|
||||
// See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs
|
||||
return wch >= 0x1F900 && wch <= 0x1F9FF;
|
||||
#endif // U_ICU_VERSION_MAJOR_NUM > 56
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
S32 LLStringOps::collate(const llwchar* a, const llwchar* b)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -198,6 +198,8 @@ public:
|
|||
static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
|
||||
static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
|
||||
|
||||
static bool isEmoji(llwchar wch);
|
||||
|
||||
static S32 collate(const char* a, const char* b) { return strcoll(a, b); }
|
||||
static S32 collate(const llwchar* a, const llwchar* b);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ set(llrender_SOURCE_FILES
|
|||
llcubemap.cpp
|
||||
llfontbitmapcache.cpp
|
||||
llfontfreetype.cpp
|
||||
llfontfreetypesvg.cpp
|
||||
llfontgl.cpp
|
||||
llfontregistry.cpp
|
||||
llgl.cpp
|
||||
|
|
@ -60,6 +61,7 @@ set(llrender_HEADER_FILES
|
|||
llcubemap.h
|
||||
llfontgl.h
|
||||
llfontfreetype.h
|
||||
llfontfreetypesvg.h
|
||||
llfontbitmapcache.h
|
||||
llfontregistry.h
|
||||
llgl.h
|
||||
|
|
|
|||
|
|
@ -30,14 +30,7 @@
|
|||
#include "llfontbitmapcache.h"
|
||||
|
||||
LLFontBitmapCache::LLFontBitmapCache()
|
||||
: mNumComponents(0),
|
||||
mBitmapWidth(0),
|
||||
mBitmapHeight(0),
|
||||
mBitmapNum(-1),
|
||||
mMaxCharWidth(0),
|
||||
mMaxCharHeight(0),
|
||||
mCurrentOffsetX(1),
|
||||
mCurrentOffsetY(1)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -45,121 +38,135 @@ LLFontBitmapCache::~LLFontBitmapCache()
|
|||
{
|
||||
}
|
||||
|
||||
void LLFontBitmapCache::init(S32 num_components,
|
||||
S32 max_char_width,
|
||||
void LLFontBitmapCache::init(S32 max_char_width,
|
||||
S32 max_char_height)
|
||||
{
|
||||
reset();
|
||||
|
||||
mNumComponents = num_components;
|
||||
mMaxCharWidth = max_char_width;
|
||||
mMaxCharHeight = max_char_height;
|
||||
}
|
||||
|
||||
LLImageRaw *LLFontBitmapCache::getImageRaw(U32 bitmap_num) const
|
||||
{
|
||||
if (bitmap_num >= mImageRawVec.size())
|
||||
return NULL;
|
||||
|
||||
return mImageRawVec[bitmap_num];
|
||||
}
|
||||
|
||||
LLImageGL *LLFontBitmapCache::getImageGL(U32 bitmap_num) const
|
||||
{
|
||||
if (bitmap_num >= mImageGLVec.size())
|
||||
return NULL;
|
||||
|
||||
return mImageGLVec[bitmap_num];
|
||||
}
|
||||
|
||||
|
||||
BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitmap_num)
|
||||
{
|
||||
if ((mBitmapNum<0) || (mCurrentOffsetX + width + 1) > mBitmapWidth)
|
||||
S32 image_width = mMaxCharWidth * 20;
|
||||
S32 pow_iw = 2;
|
||||
while (pow_iw < image_width)
|
||||
{
|
||||
if ((mBitmapNum<0) || (mCurrentOffsetY + 2*mMaxCharHeight + 2) > mBitmapHeight)
|
||||
pow_iw <<= 1;
|
||||
}
|
||||
image_width = pow_iw;
|
||||
image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
|
||||
|
||||
mBitmapWidth = image_width;
|
||||
mBitmapHeight = image_width;
|
||||
}
|
||||
|
||||
LLImageRaw *LLFontBitmapCache::getImageRaw(EFontGlyphType bitmap_type, U32 bitmap_num) const
|
||||
{
|
||||
const U32 bitmap_idx = static_cast<U32>(bitmap_type);
|
||||
if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageRawVec[bitmap_idx].size())
|
||||
return nullptr;
|
||||
|
||||
return mImageRawVec[bitmap_idx][bitmap_num];
|
||||
}
|
||||
|
||||
LLImageGL *LLFontBitmapCache::getImageGL(EFontGlyphType bitmap_type, U32 bitmap_num) const
|
||||
{
|
||||
const U32 bitmap_idx = static_cast<U32>(bitmap_type);
|
||||
if (bitmap_type >= EFontGlyphType::Count || bitmap_num >= mImageGLVec[bitmap_idx].size())
|
||||
return nullptr;
|
||||
|
||||
return mImageGLVec[bitmap_idx][bitmap_num];
|
||||
}
|
||||
|
||||
|
||||
BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyphType bitmap_type, U32& bitmap_num)
|
||||
{
|
||||
if (bitmap_type >= EFontGlyphType::Count)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const U32 bitmap_idx = static_cast<U32>(bitmap_type);
|
||||
if (mImageRawVec[bitmap_idx].empty() || (mCurrentOffsetX[bitmap_idx] + width + 1) > mBitmapWidth)
|
||||
{
|
||||
if ((mImageRawVec[bitmap_idx].empty()) || (mCurrentOffsetY[bitmap_idx] + 2*mMaxCharHeight + 2) > mBitmapHeight)
|
||||
{
|
||||
// We're out of space in the current image, or no image
|
||||
// has been allocated yet. Make a new one.
|
||||
|
||||
mImageRawVec.push_back(new LLImageRaw);
|
||||
mBitmapNum = mImageRawVec.size()-1;
|
||||
LLImageRaw *image_raw = getImageRaw(mBitmapNum);
|
||||
S32 num_components = getNumComponents(bitmap_type);
|
||||
mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components));
|
||||
bitmap_num = mImageRawVec[bitmap_idx].size() - 1;
|
||||
|
||||
LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num);
|
||||
if (EFontGlyphType::Grayscale == bitmap_type)
|
||||
{
|
||||
image_raw->clear(255, 0);
|
||||
}
|
||||
|
||||
// Make corresponding GL image.
|
||||
mImageGLVec.push_back(new LLImageGL(FALSE));
|
||||
LLImageGL *image_gl = getImageGL(mBitmapNum);
|
||||
|
||||
S32 image_width = mMaxCharWidth * 20;
|
||||
S32 pow_iw = 2;
|
||||
while (pow_iw < image_width)
|
||||
{
|
||||
pow_iw *= 2;
|
||||
}
|
||||
image_width = pow_iw;
|
||||
image_width = llmin(512, image_width); // Don't make bigger than 512x512, ever.
|
||||
S32 image_height = image_width;
|
||||
|
||||
image_raw->resize(image_width, image_height, mNumComponents);
|
||||
|
||||
mBitmapWidth = image_width;
|
||||
mBitmapHeight = image_height;
|
||||
|
||||
switch (mNumComponents)
|
||||
{
|
||||
case 1:
|
||||
image_raw->clear();
|
||||
break;
|
||||
case 2:
|
||||
image_raw->clear(255, 0);
|
||||
break;
|
||||
}
|
||||
mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false));
|
||||
LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num);
|
||||
|
||||
// Start at beginning of the new image.
|
||||
mCurrentOffsetX = 1;
|
||||
mCurrentOffsetY = 1;
|
||||
mCurrentOffsetX[bitmap_idx] = 1;
|
||||
mCurrentOffsetY[bitmap_idx] = 1;
|
||||
|
||||
// Attach corresponding GL texture.
|
||||
image_gl->createGLTexture(0, image_raw);
|
||||
// Attach corresponding GL texture. (*TODO: is this needed?)
|
||||
gGL.getTexUnit(0)->bind(image_gl);
|
||||
image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Move to next row in current image.
|
||||
mCurrentOffsetX = 1;
|
||||
mCurrentOffsetY += mMaxCharHeight + 1;
|
||||
mCurrentOffsetX[bitmap_idx] = 1;
|
||||
mCurrentOffsetY[bitmap_idx] += mMaxCharHeight + 1;
|
||||
}
|
||||
}
|
||||
|
||||
pos_x = mCurrentOffsetX;
|
||||
pos_y = mCurrentOffsetY;
|
||||
bitmap_num = mBitmapNum;
|
||||
pos_x = mCurrentOffsetX[bitmap_idx];
|
||||
pos_y = mCurrentOffsetY[bitmap_idx];
|
||||
bitmap_num = getNumBitmaps(bitmap_type) - 1;
|
||||
|
||||
mCurrentOffsetX += width + 1;
|
||||
mCurrentOffsetX[bitmap_idx] += width + 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLFontBitmapCache::destroyGL()
|
||||
{
|
||||
for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin();
|
||||
it != mImageGLVec.end(); ++it)
|
||||
for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++)
|
||||
{
|
||||
(*it)->destroyGLTexture();
|
||||
for (LLImageGL* image_gl : mImageGLVec[idx])
|
||||
{
|
||||
image_gl->destroyGLTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontBitmapCache::reset()
|
||||
{
|
||||
mImageRawVec.clear();
|
||||
|
||||
mImageGLVec.clear();
|
||||
for (U32 idx = 0, cnt = static_cast<U32>(EFontGlyphType::Count); idx < cnt; idx++)
|
||||
{
|
||||
mImageRawVec[idx].clear();
|
||||
mImageGLVec[idx].clear();
|
||||
mCurrentOffsetX[idx] = 1;
|
||||
mCurrentOffsetY[idx] = 1;
|
||||
}
|
||||
|
||||
mBitmapWidth = 0;
|
||||
mBitmapHeight = 0;
|
||||
mBitmapNum = -1;
|
||||
mCurrentOffsetX = 1;
|
||||
mCurrentOffsetY = 1;
|
||||
}
|
||||
|
||||
//static
|
||||
U32 LLFontBitmapCache::getNumComponents(EFontGlyphType bitmap_type)
|
||||
{
|
||||
switch (bitmap_type)
|
||||
{
|
||||
case EFontGlyphType::Grayscale:
|
||||
return 2;
|
||||
case EFontGlyphType::Color:
|
||||
return 4;
|
||||
default:
|
||||
llassert(false);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,14 @@
|
|||
#include <vector>
|
||||
#include "lltrace.h"
|
||||
|
||||
enum class EFontGlyphType : U32
|
||||
{
|
||||
Grayscale = 0,
|
||||
Color,
|
||||
Count,
|
||||
Unspecified,
|
||||
};
|
||||
|
||||
// Maintain a collection of bitmaps containing rendered glyphs.
|
||||
// Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL.
|
||||
class LLFontBitmapCache
|
||||
|
|
@ -39,35 +47,35 @@ public:
|
|||
~LLFontBitmapCache();
|
||||
|
||||
// Need to call this once, before caching any glyphs.
|
||||
void init(S32 num_components,
|
||||
S32 max_char_width,
|
||||
void init(S32 max_char_width,
|
||||
S32 max_char_height);
|
||||
|
||||
void reset();
|
||||
|
||||
BOOL nextOpenPos(S32 width, S32 &posX, S32 &posY, S32 &bitmapNum);
|
||||
BOOL nextOpenPos(S32 width, S32& posX, S32& posY, EFontGlyphType bitmapType, U32& bitmapNum);
|
||||
|
||||
void destroyGL();
|
||||
|
||||
LLImageRaw *getImageRaw(U32 bitmapNum = 0) const;
|
||||
LLImageGL *getImageGL(U32 bitmapNum = 0) const;
|
||||
|
||||
LLImageRaw* getImageRaw(EFontGlyphType bitmapType, U32 bitmapNum) const;
|
||||
LLImageGL* getImageGL(EFontGlyphType bitmapType, U32 bitmapNum) const;
|
||||
|
||||
S32 getMaxCharWidth() const { return mMaxCharWidth; }
|
||||
S32 getNumComponents() const { return mNumComponents; }
|
||||
U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? mImageRawVec[static_cast<U32>(bitmapType)].size() : 0; }
|
||||
S32 getBitmapWidth() const { return mBitmapWidth; }
|
||||
S32 getBitmapHeight() const { return mBitmapHeight; }
|
||||
|
||||
protected:
|
||||
static U32 getNumComponents(EFontGlyphType bitmap_type);
|
||||
|
||||
private:
|
||||
S32 mNumComponents;
|
||||
S32 mBitmapWidth;
|
||||
S32 mBitmapHeight;
|
||||
S32 mBitmapNum;
|
||||
S32 mMaxCharWidth;
|
||||
S32 mMaxCharHeight;
|
||||
S32 mCurrentOffsetX;
|
||||
S32 mCurrentOffsetY;
|
||||
std::vector<LLPointer<LLImageRaw> > mImageRawVec;
|
||||
std::vector<LLPointer<LLImageGL> > mImageGLVec;
|
||||
S32 mBitmapWidth = 0;
|
||||
S32 mBitmapHeight = 0;
|
||||
S32 mCurrentOffsetX[static_cast<U32>(EFontGlyphType::Count)] = { 1 };
|
||||
S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 };
|
||||
S32 mMaxCharWidth = 0;
|
||||
S32 mMaxCharHeight = 0;
|
||||
std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)];
|
||||
std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)];
|
||||
};
|
||||
|
||||
#endif //LL_LLFONTBITMAPCACHE_H
|
||||
|
|
|
|||
|
|
@ -34,14 +34,17 @@
|
|||
#ifdef LL_WINDOWS
|
||||
#include <freetype2\freetype\ftsystem.h>
|
||||
#endif
|
||||
#include "llfontfreetypesvg.h"
|
||||
|
||||
// For some reason, this won't work if it's not wrapped in the ifdef
|
||||
#ifdef FT_FREETYPE_H
|
||||
#include FT_FREETYPE_H
|
||||
#endif
|
||||
|
||||
#include "lldir.h"
|
||||
#include "llerror.h"
|
||||
#include "llimage.h"
|
||||
#include "llimagepng.h"
|
||||
//#include "llimagej2c.h"
|
||||
#include "llmath.h" // Linden math
|
||||
#include "llstring.h"
|
||||
|
|
@ -51,6 +54,8 @@
|
|||
|
||||
#include "llapr.h"
|
||||
|
||||
#define ENABLE_OT_SVG_SUPPORT
|
||||
|
||||
FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL;
|
||||
|
||||
LLFontManager *gFontManagerp = NULL;
|
||||
|
|
@ -83,6 +88,16 @@ LLFontManager::LLFontManager()
|
|||
LL_ERRS() << "Freetype initialization failure!" << LL_ENDL;
|
||||
FT_Done_FreeType(gFTLibrary);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OT_SVG_SUPPORT
|
||||
SVG_RendererHooks hooks = {
|
||||
LLFontFreeTypeSvgRenderer::OnInit,
|
||||
LLFontFreeTypeSvgRenderer::OnFree,
|
||||
LLFontFreeTypeSvgRenderer::OnRender,
|
||||
LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot,
|
||||
};
|
||||
FT_Property_Set(gFTLibrary, "ot-svg", "svg-hooks", &hooks);
|
||||
#endif
|
||||
}
|
||||
|
||||
LLFontManager::~LLFontManager()
|
||||
|
|
@ -92,8 +107,9 @@ LLFontManager::~LLFontManager()
|
|||
}
|
||||
|
||||
|
||||
LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
|
||||
LLFontGlyphInfo::LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type)
|
||||
: mGlyphIndex(index),
|
||||
mGlyphType(glyph_type),
|
||||
mWidth(0), // In pixels
|
||||
mHeight(0), // In pixels
|
||||
mXAdvance(0.f), // In pixels
|
||||
|
|
@ -102,10 +118,25 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index)
|
|||
mYBitmapOffset(0), // Offset to the origin in the bitmap
|
||||
mXBearing(0), // Distance from baseline to left in pixels
|
||||
mYBearing(0), // Distance from baseline to top in pixels
|
||||
mBitmapNum(0) // Which bitmap in the bitmap cache contains this glyph
|
||||
mBitmapEntry(std::make_pair(EFontGlyphType::Unspecified, -1)) // Which bitmap in the bitmap cache contains this glyph
|
||||
{
|
||||
}
|
||||
|
||||
LLFontGlyphInfo::LLFontGlyphInfo(const LLFontGlyphInfo& fgi)
|
||||
: mGlyphIndex(fgi.mGlyphIndex)
|
||||
, mGlyphType(fgi.mGlyphType)
|
||||
, mWidth(fgi.mWidth)
|
||||
, mHeight(fgi.mHeight)
|
||||
, mXAdvance(fgi.mXAdvance)
|
||||
, mYAdvance(fgi.mYAdvance)
|
||||
, mXBitmapOffset(fgi.mXBitmapOffset)
|
||||
, mYBitmapOffset(fgi.mYBitmapOffset)
|
||||
, mXBearing(fgi.mXBearing)
|
||||
, mYBearing(fgi.mYBearing)
|
||||
{
|
||||
mBitmapEntry = fgi.mBitmapEntry;
|
||||
}
|
||||
|
||||
LLFontFreetype::LLFontFreetype()
|
||||
: mFontBitmapCachep(new LLFontBitmapCache),
|
||||
mAscender(0.f),
|
||||
|
|
@ -172,7 +203,7 @@ void ft_close_cb(FT_Stream stream) {
|
|||
}
|
||||
#endif
|
||||
|
||||
BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
|
||||
BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n)
|
||||
{
|
||||
// Don't leak face objects. This is also needed to deal with
|
||||
// changed font file names.
|
||||
|
|
@ -255,7 +286,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
|
|||
S32 max_char_width = ll_round(0.5f + (x_max - x_min));
|
||||
S32 max_char_height = ll_round(0.5f + (y_max - y_min));
|
||||
|
||||
mFontBitmapCachep->init(components, max_char_width, max_char_height);
|
||||
mFontBitmapCachep->init(max_char_width, max_char_height);
|
||||
|
||||
if (!mFTFace->charmap)
|
||||
{
|
||||
|
|
@ -266,7 +297,7 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v
|
|||
if (!mIsFallback)
|
||||
{
|
||||
// Add the default glyph
|
||||
addGlyphFromFont(this, 0, 0);
|
||||
addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);
|
||||
}
|
||||
|
||||
mName = filename;
|
||||
|
|
@ -377,14 +408,11 @@ void LLFontFreetype::clearFontStreams()
|
|||
}
|
||||
#endif
|
||||
|
||||
void LLFontFreetype::setFallbackFonts(const font_vector_t &font)
|
||||
void LLFontFreetype::addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor)
|
||||
{
|
||||
mFallbackFonts = font;
|
||||
}
|
||||
|
||||
const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const
|
||||
{
|
||||
return mFallbackFonts;
|
||||
// Insert functor fallbacks before generic fallbacks
|
||||
mFallbackFonts.insert((functor) ? std::find_if(mFallbackFonts.begin(), mFallbackFonts.end(), [](const fallback_font_t& fe) { return !fe.second; }) : mFallbackFonts.end(),
|
||||
std::make_pair(fallback_font, functor));
|
||||
}
|
||||
|
||||
F32 LLFontFreetype::getLineHeight() const
|
||||
|
|
@ -408,7 +436,7 @@ F32 LLFontFreetype::getXAdvance(llwchar wch) const
|
|||
return 0.0;
|
||||
|
||||
// Return existing info only if it is current
|
||||
LLFontGlyphInfo* gi = getGlyphInfo(wch);
|
||||
LLFontGlyphInfo* gi = getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
if (gi)
|
||||
{
|
||||
return gi->mXAdvance;
|
||||
|
|
@ -440,10 +468,10 @@ F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const
|
|||
return 0.0;
|
||||
|
||||
//llassert(!mIsFallback);
|
||||
LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left);;
|
||||
LLFontGlyphInfo* left_glyph_info = getGlyphInfo(char_left, EFontGlyphType::Unspecified);;
|
||||
U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0;
|
||||
// Kern this puppy.
|
||||
LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right);
|
||||
LLFontGlyphInfo* right_glyph_info = getGlyphInfo(char_right, EFontGlyphType::Unspecified);
|
||||
U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0;
|
||||
|
||||
// <FS:ND> Use cached kerning if possible, only do so for glyphs < 256 for now
|
||||
|
|
@ -517,60 +545,91 @@ BOOL LLFontFreetype::hasGlyph(llwchar wch) const
|
|||
return(mCharGlyphInfoMap.find(wch) != mCharGlyphInfoMap.end());
|
||||
}
|
||||
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch, EFontGlyphType glyph_type) const
|
||||
{
|
||||
if (mFTFace == NULL)
|
||||
return FALSE;
|
||||
|
||||
llassert(!mIsFallback);
|
||||
llassert(glyph_type < EFontGlyphType::Count);
|
||||
//LL_DEBUGS() << "Adding new glyph for " << wch << " to font" << LL_ENDL;
|
||||
|
||||
FT_UInt glyph_index;
|
||||
|
||||
// Fallback fonts with a functor have precedence over everything else
|
||||
fallback_font_vector_t::const_iterator it_fallback = mFallbackFonts.cbegin();
|
||||
for (; it_fallback != mFallbackFonts.cend() && it_fallback->second; ++it_fallback)
|
||||
{
|
||||
if (it_fallback->second(wch))
|
||||
{
|
||||
glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
|
||||
if (glyph_index)
|
||||
{
|
||||
return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize char to glyph map
|
||||
glyph_index = FT_Get_Char_Index(mFTFace, wch);
|
||||
if (glyph_index == 0)
|
||||
{
|
||||
//LL_INFOS() << "Trying to add glyph from fallback font!" << LL_ENDL;
|
||||
font_vector_t::const_iterator iter;
|
||||
for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++)
|
||||
for (; it_fallback != mFallbackFonts.cend(); ++it_fallback)
|
||||
{
|
||||
glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch);
|
||||
glyph_index = FT_Get_Char_Index(it_fallback->first->mFTFace, wch);
|
||||
if (glyph_index)
|
||||
{
|
||||
return addGlyphFromFont(*iter, wch, glyph_index);
|
||||
return addGlyphFromFont(it_fallback->first, wch, glyph_index, glyph_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
|
||||
if (iter == mCharGlyphInfoMap.end())
|
||||
std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch);
|
||||
char_glyph_info_map_t::iterator iter =
|
||||
std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; });
|
||||
if (iter == range_it.second)
|
||||
{
|
||||
return addGlyphFromFont(this, wch, glyph_index);
|
||||
return addGlyphFromFont(this, wch, glyph_index, glyph_type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const
|
||||
LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType requested_glyph_type) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
if (mFTFace == NULL)
|
||||
return NULL;
|
||||
|
||||
llassert(!mIsFallback);
|
||||
fontp->renderGlyph(glyph_index);
|
||||
fontp->renderGlyph(requested_glyph_type, glyph_index);
|
||||
|
||||
EFontGlyphType bitmap_glyph_type = EFontGlyphType::Unspecified;
|
||||
switch (fontp->mFTFace->glyph->bitmap.pixel_mode)
|
||||
{
|
||||
case FT_PIXEL_MODE_MONO:
|
||||
case FT_PIXEL_MODE_GRAY:
|
||||
bitmap_glyph_type = EFontGlyphType::Grayscale;
|
||||
break;
|
||||
case FT_PIXEL_MODE_BGRA:
|
||||
bitmap_glyph_type = EFontGlyphType::Color;
|
||||
break;
|
||||
default:
|
||||
llassert_always(true);
|
||||
break;
|
||||
}
|
||||
S32 width = fontp->mFTFace->glyph->bitmap.width;
|
||||
S32 height = fontp->mFTFace->glyph->bitmap.rows;
|
||||
|
||||
S32 pos_x, pos_y;
|
||||
S32 bitmap_num;
|
||||
mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num);
|
||||
U32 bitmap_num;
|
||||
mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num);
|
||||
mAddGlyphCount++;
|
||||
|
||||
LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index);
|
||||
LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type);
|
||||
gi->mXBitmapOffset = pos_x;
|
||||
gi->mYBitmapOffset = pos_y;
|
||||
gi->mBitmapNum = bitmap_num;
|
||||
gi->mBitmapEntry = std::make_pair(bitmap_glyph_type, bitmap_num);
|
||||
gi->mWidth = width;
|
||||
gi->mHeight = height;
|
||||
gi->mXBearing = fontp->mFTFace->glyph->bitmap_left;
|
||||
|
|
@ -581,8 +640,12 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
|
|||
|
||||
insertGlyphInfo(wch, gi);
|
||||
|
||||
llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
|
||||
|| fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
|
||||
if (requested_glyph_type != bitmap_glyph_type)
|
||||
{
|
||||
LLFontGlyphInfo* gi_temp = new LLFontGlyphInfo(*gi);
|
||||
gi_temp->mGlyphType = bitmap_glyph_type;
|
||||
insertGlyphInfo(wch, gi_temp);
|
||||
}
|
||||
|
||||
if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO
|
||||
|| fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)
|
||||
|
|
@ -617,84 +680,91 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l
|
|||
buffer_row_stride = width;
|
||||
}
|
||||
|
||||
switch (mFontBitmapCachep->getNumComponents())
|
||||
{
|
||||
case 1:
|
||||
mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x,
|
||||
pos_y,
|
||||
width,
|
||||
height,
|
||||
buffer_data,
|
||||
buffer_row_stride,
|
||||
TRUE);
|
||||
break;
|
||||
case 2:
|
||||
setSubImageLuminanceAlpha(pos_x,
|
||||
pos_y,
|
||||
bitmap_num,
|
||||
width,
|
||||
height,
|
||||
buffer_data,
|
||||
buffer_row_stride);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
setSubImageLuminanceAlpha(pos_x,
|
||||
pos_y,
|
||||
bitmap_num,
|
||||
width,
|
||||
height,
|
||||
buffer_data,
|
||||
buffer_row_stride);
|
||||
|
||||
if (tmp_graydata)
|
||||
delete[] tmp_graydata;
|
||||
}
|
||||
else if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
|
||||
{
|
||||
setSubImageBGRA(pos_x,
|
||||
pos_y,
|
||||
bitmap_num,
|
||||
fontp->mFTFace->glyph->bitmap.width,
|
||||
fontp->mFTFace->glyph->bitmap.rows,
|
||||
fontp->mFTFace->glyph->bitmap.buffer,
|
||||
llabs(fontp->mFTFace->glyph->bitmap.pitch));
|
||||
} else {
|
||||
// we don't know how to handle this pixel format from FreeType;
|
||||
// omit it from the font-image.
|
||||
llassert(false);
|
||||
}
|
||||
|
||||
LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
|
||||
LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_glyph_type, bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_glyph_type, bitmap_num);
|
||||
image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight());
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const
|
||||
LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const
|
||||
{
|
||||
char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
|
||||
if (iter != mCharGlyphInfoMap.end())
|
||||
std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch);
|
||||
|
||||
char_glyph_info_map_t::iterator iter = (EFontGlyphType::Unspecified != glyph_type)
|
||||
? std::find_if(range_it.first, range_it.second, [&glyph_type](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == glyph_type; })
|
||||
: range_it.first;
|
||||
if (iter != range_it.second)
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this glyph doesn't yet exist, so render it and return the result
|
||||
return addGlyph(wch);
|
||||
return addGlyph(wch, (EFontGlyphType::Unspecified != glyph_type) ? glyph_type : EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const
|
||||
{
|
||||
char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch);
|
||||
if (iter != mCharGlyphInfoMap.end())
|
||||
llassert(gi->mGlyphType < EFontGlyphType::Count);
|
||||
std::pair<char_glyph_info_map_t::iterator, char_glyph_info_map_t::iterator> range_it = mCharGlyphInfoMap.equal_range(wch);
|
||||
|
||||
char_glyph_info_map_t::iterator iter =
|
||||
std::find_if(range_it.first, range_it.second, [&gi](const char_glyph_info_map_t::value_type& entry) { return entry.second->mGlyphType == gi->mGlyphType; });
|
||||
if (iter != range_it.second)
|
||||
{
|
||||
delete iter->second;
|
||||
iter->second = gi;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCharGlyphInfoMap[wch] = gi;
|
||||
mCharGlyphInfoMap.insert(std::make_pair(wch, gi));
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontFreetype::renderGlyph(U32 glyph_index) const
|
||||
void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const
|
||||
{
|
||||
if (mFTFace == NULL)
|
||||
return;
|
||||
|
||||
FT_Int32 load_flags = FT_LOAD_FORCE_AUTOHINT;
|
||||
if (EFontGlyphType::Color == bitmap_type)
|
||||
{
|
||||
// We may not actually get a color render so our caller should always examine mFTFace->glyph->bitmap.pixel_mode
|
||||
load_flags |= FT_LOAD_COLOR;
|
||||
}
|
||||
|
||||
// <FS:ND> try to load given glyph, if that fails, fallback to ?. This can happen with invalid unicode codepoints.
|
||||
if( 0 != FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) )
|
||||
if( 0 != FT_Load_Glyph(mFTFace, glyph_index, load_flags) )
|
||||
glyph_index = FT_Get_Char_Index( mFTFace, L'?');
|
||||
// </FS:ND>
|
||||
|
||||
llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_FORCE_AUTOHINT) );
|
||||
llassert_always(! FT_Load_Glyph(mFTFace, glyph_index, load_flags) );
|
||||
|
||||
llassert_always(! FT_Render_Glyph(mFTFace->glyph, gFontRenderMode) );
|
||||
|
||||
|
|
@ -704,7 +774,7 @@ void LLFontFreetype::renderGlyph(U32 glyph_index) const
|
|||
void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
|
||||
{
|
||||
resetBitmapCache();
|
||||
loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback);
|
||||
loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mIsFallback, 0);
|
||||
if (!mIsFallback)
|
||||
{
|
||||
// This is the head of the list - need to rebuild ourself and all fallbacks.
|
||||
|
|
@ -714,11 +784,9 @@ void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi)
|
|||
}
|
||||
else
|
||||
{
|
||||
for(font_vector_t::iterator it = mFallbackFonts.begin();
|
||||
it != mFallbackFonts.end();
|
||||
++it)
|
||||
for (fallback_font_vector_t::iterator it = mFallbackFonts.begin(); it != mFallbackFonts.end(); ++it)
|
||||
{
|
||||
(*it)->reset(vert_dpi, horz_dpi);
|
||||
it->first->reset(vert_dpi, horz_dpi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -740,7 +808,7 @@ void LLFontFreetype::resetBitmapCache()
|
|||
if(!mIsFallback)
|
||||
{
|
||||
// Add the empty glyph
|
||||
addGlyphFromFont(this, 0, 0);
|
||||
addGlyphFromFont(this, 0, 0, EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -754,6 +822,34 @@ const std::string &LLFontFreetype::getName() const
|
|||
return mName;
|
||||
}
|
||||
|
||||
static void dumpFontBitmap(const LLImageRaw* image_raw, const std::string& file_name)
|
||||
{
|
||||
LLPointer<LLImagePNG> tmpImage = new LLImagePNG();
|
||||
if ( (tmpImage->encode(image_raw, 0.0f)) && (tmpImage->save(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name))) )
|
||||
{
|
||||
LL_INFOS("Font") << "Successfully saved " << file_name << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS("Font") << "Failed to save " << file_name << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontFreetype::dumpFontBitmaps() const
|
||||
{
|
||||
// Dump all the regular bitmaps (if any)
|
||||
for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Grayscale); idx < cnt; idx++)
|
||||
{
|
||||
dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, idx), llformat("%s_%d_%d_%d.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx));
|
||||
}
|
||||
|
||||
// Dump all the color bitmaps (if any)
|
||||
for (int idx = 0, cnt = mFontBitmapCachep->getNumBitmaps(EFontGlyphType::Color); idx < cnt; idx++)
|
||||
{
|
||||
dumpFontBitmap(mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, idx), llformat("%s_%d_%d_%d_clr.png", mFTFace->family_name, (int)(mPointSize * 10), mStyle, idx));
|
||||
}
|
||||
}
|
||||
|
||||
const LLFontBitmapCache* LLFontFreetype::getFontBitmapCache() const
|
||||
{
|
||||
return mFontBitmapCachep;
|
||||
|
|
@ -769,9 +865,38 @@ U8 LLFontFreetype::getStyle() const
|
|||
return mStyle;
|
||||
}
|
||||
|
||||
bool LLFontFreetype::setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const
|
||||
{
|
||||
LLImageRaw* image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Color, bitmap_num);
|
||||
llassert(!mIsFallback);
|
||||
llassert(image_raw && (image_raw->getComponents() == 4));
|
||||
|
||||
// NOTE: inspired by LLImageRaw::setSubImage()
|
||||
U32* image_data = (U32*)image_raw->getData();
|
||||
if (!image_data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (U32 idxRow = 0; idxRow < height; idxRow++)
|
||||
{
|
||||
const U32 nSrcRow = height - 1 - idxRow;
|
||||
const U32 nSrcOffset = nSrcRow * width * image_raw->getComponents();
|
||||
const U32 nDstOffset = (y + idxRow) * image_raw->getWidth() + x;
|
||||
|
||||
for (U32 idxCol = 0; idxCol < width; idxCol++)
|
||||
{
|
||||
U32 nTemp = nSrcOffset + idxCol * 4;
|
||||
image_data[nDstOffset + idxCol] = data[nTemp + 3] << 24 | data[nTemp] << 16 | data[nTemp + 1] << 8 | data[nTemp + 2];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const
|
||||
{
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num);
|
||||
LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(EFontGlyphType::Grayscale, bitmap_num);
|
||||
|
||||
llassert(!mIsFallback);
|
||||
llassert(image_raw && (image_raw->getComponents() == 2));
|
||||
|
|
|
|||
|
|
@ -74,9 +74,11 @@ private:
|
|||
|
||||
struct LLFontGlyphInfo
|
||||
{
|
||||
LLFontGlyphInfo(U32 index);
|
||||
LLFontGlyphInfo(U32 index, EFontGlyphType glyph_type);
|
||||
LLFontGlyphInfo(const LLFontGlyphInfo& fgi);
|
||||
|
||||
U32 mGlyphIndex;
|
||||
EFontGlyphType mGlyphType;
|
||||
|
||||
// Metrics
|
||||
S32 mWidth; // In pixels
|
||||
|
|
@ -89,7 +91,7 @@ struct LLFontGlyphInfo
|
|||
S32 mYBitmapOffset; // Offset to the origin in the bitmap
|
||||
S32 mXBearing; // Distance from baseline to left in pixels
|
||||
S32 mYBearing; // Distance from baseline to top in pixels
|
||||
S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph
|
||||
std::pair<EFontGlyphType, S32> mBitmapEntry; // Which bitmap in the bitmap cache contains this glyph
|
||||
};
|
||||
|
||||
extern LLFontManager *gFontManagerp;
|
||||
|
|
@ -102,7 +104,7 @@ public:
|
|||
|
||||
// is_fallback should be true for fallback fonts that aren't used
|
||||
// to render directly (Unicode backup, primarily)
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n = 0);
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, bool is_fallback, S32 face_n);
|
||||
|
||||
S32 getNumFaces(const std::string& filename);
|
||||
|
||||
|
|
@ -111,10 +113,8 @@ public:
|
|||
void clearFontStreams();
|
||||
#endif
|
||||
|
||||
typedef std::vector<LLPointer<LLFontFreetype> > font_vector_t;
|
||||
|
||||
void setFallbackFonts(const font_vector_t &font);
|
||||
const font_vector_t &getFallbackFonts() const;
|
||||
typedef std::function<bool(llwchar)> char_functor_t;
|
||||
void addFallbackFont(const LLPointer<LLFontFreetype>& fallback_font, const char_functor_t& functor = nullptr);
|
||||
|
||||
// Global font metrics - in units of pixels
|
||||
F32 getLineHeight() const;
|
||||
|
|
@ -153,7 +153,7 @@ public:
|
|||
F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters
|
||||
F32 getXKerning(const LLFontGlyphInfo* left_glyph_info, const LLFontGlyphInfo* right_glyph_info) const; // Get the kerning between the two characters
|
||||
|
||||
LLFontGlyphInfo* getGlyphInfo(llwchar wch) const;
|
||||
LLFontGlyphInfo* getGlyphInfo(llwchar wch, EFontGlyphType glyph_type) const;
|
||||
|
||||
void reset(F32 vert_dpi, F32 horz_dpi);
|
||||
|
||||
|
|
@ -161,6 +161,7 @@ public:
|
|||
|
||||
const std::string& getName() const;
|
||||
|
||||
void dumpFontBitmaps() const;
|
||||
const LLFontBitmapCache* getFontBitmapCache() const;
|
||||
|
||||
void setStyle(U8 style);
|
||||
|
|
@ -169,10 +170,11 @@ public:
|
|||
private:
|
||||
void resetBitmapCache();
|
||||
void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const;
|
||||
bool setSubImageBGRA(U32 x, U32 y, U32 bitmap_num, U16 width, U16 height, const U8* data, U32 stride) const;
|
||||
BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character
|
||||
LLFontGlyphInfo* addGlyph(llwchar wch) const; // Add a new character to the font if necessary
|
||||
LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
|
||||
void renderGlyph(U32 glyph_index) const;
|
||||
LLFontGlyphInfo* addGlyph(llwchar wch, EFontGlyphType glyph_type) const; // Add a new character to the font if necessary
|
||||
LLFontGlyphInfo* addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index, EFontGlyphType bitmap_type) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found)
|
||||
void renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index) const;
|
||||
void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const;
|
||||
|
||||
std::string mName;
|
||||
|
|
@ -192,9 +194,12 @@ private:
|
|||
#endif
|
||||
|
||||
BOOL mIsFallback;
|
||||
font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
|
||||
typedef std::pair<LLPointer<LLFontFreetype>, char_functor_t> fallback_font_t;
|
||||
typedef std::vector<fallback_font_t> fallback_font_vector_t;
|
||||
fallback_font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars)
|
||||
|
||||
typedef boost::unordered_map<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
|
||||
// *NOTE: the same glyph can be present with multiple representations (but the pointer is always unique)
|
||||
typedef boost::unordered_multimap<llwchar, LLFontGlyphInfo*> char_glyph_info_map_t;
|
||||
mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap
|
||||
|
||||
mutable LLFontBitmapCache* mFontBitmapCachep;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,205 @@
|
|||
/**
|
||||
* @file llfontfreetypesvg.cpp
|
||||
* @brief Freetype font library SVG glyph rendering
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfontfreetypesvg.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable : 4702)
|
||||
#endif
|
||||
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#include <nanosvg/nanosvg.h>
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
#include <nanosvg/nanosvgrast.h>
|
||||
|
||||
#if LL_WINDOWS
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
struct LLSvgRenderData
|
||||
{
|
||||
FT_UInt GlyphIndex = 0;
|
||||
FT_Error Error = FT_Err_Ok; // FreeType currently (@2.12.1) ignores the error value returned by the preset glyph slot callback so we return it at render time
|
||||
// (See https://github.com/freetype/freetype/blob/5faa1df8b93ebecf0f8fd5fe8fda7b9082eddced/src/base/ftobjs.c#L1170)
|
||||
NSVGimage* pNSvgImage = nullptr;
|
||||
float Scale = 0.f;
|
||||
};
|
||||
|
||||
// static
|
||||
FT_Error LLFontFreeTypeSvgRenderer::OnInit(FT_Pointer* state)
|
||||
{
|
||||
// The SVG driver hook state is shared across all callback invocations; since our state is lightweight
|
||||
// we store it in the glyph instead.
|
||||
*state = nullptr;
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontFreeTypeSvgRenderer::OnFree(FT_Pointer* state)
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontFreeTypeSvgRenderer::OnDataFinalizer(void* objectp)
|
||||
{
|
||||
FT_GlyphSlot glyph_slot = static_cast<FT_GlyphSlot>(objectp);
|
||||
|
||||
LLSvgRenderData* pData = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
|
||||
glyph_slot->generic.data = nullptr;
|
||||
glyph_slot->generic.finalizer = nullptr;
|
||||
delete(pData);
|
||||
}
|
||||
|
||||
//static
|
||||
FT_Error LLFontFreeTypeSvgRenderer::OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer*)
|
||||
{
|
||||
FT_SVG_Document document = static_cast<FT_SVG_Document>(glyph_slot->other);
|
||||
|
||||
llassert(!glyph_slot->generic.data || !cache || glyph_slot->glyph_index == ((LLSvgRenderData*)glyph_slot->generic.data)->GlyphIndex);
|
||||
if (!glyph_slot->generic.data)
|
||||
{
|
||||
glyph_slot->generic.data = new LLSvgRenderData();
|
||||
glyph_slot->generic.finalizer = LLFontFreeTypeSvgRenderer::OnDataFinalizer;
|
||||
}
|
||||
LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
|
||||
if (!cache)
|
||||
{
|
||||
datap->GlyphIndex = glyph_slot->glyph_index;
|
||||
datap->Error = FT_Err_Ok;
|
||||
}
|
||||
|
||||
// NOTE: nsvgParse modifies the input string so we need a temporary copy
|
||||
llassert(!datap->pNSvgImage || cache);
|
||||
if (!datap->pNSvgImage)
|
||||
{
|
||||
char* document_buffer = new char[document->svg_document_length + 1];
|
||||
memcpy(document_buffer, document->svg_document, document->svg_document_length);
|
||||
document_buffer[document->svg_document_length] = '\0';
|
||||
|
||||
datap->pNSvgImage = nsvgParse(document_buffer, "px", 0.);
|
||||
|
||||
delete[] document_buffer;
|
||||
}
|
||||
|
||||
if (!datap->pNSvgImage)
|
||||
{
|
||||
datap->Error = FT_Err_Invalid_SVG_Document;
|
||||
return FT_Err_Invalid_SVG_Document;
|
||||
}
|
||||
|
||||
// We don't (currently) support transformations so test for an identity rotation matrix + zero translation
|
||||
if (document->transform.xx != 1 << 16 || document->transform.yx != 0 ||
|
||||
document->transform.xy != 0 || document->transform.yy != 1 << 16 ||
|
||||
document->delta.x > 0 || document->delta.y > 0)
|
||||
{
|
||||
datap->Error = FT_Err_Unimplemented_Feature;
|
||||
return FT_Err_Unimplemented_Feature;
|
||||
}
|
||||
|
||||
float svg_width = datap->pNSvgImage->width;
|
||||
float svg_height = datap->pNSvgImage->height;
|
||||
if (svg_width == 0.f || svg_height == 0.f)
|
||||
{
|
||||
svg_width = document->units_per_EM;
|
||||
svg_height = document->units_per_EM;
|
||||
}
|
||||
|
||||
float svg_x_scale = (float)document->metrics.x_ppem / floorf(svg_width);
|
||||
float svg_y_scale = (float)document->metrics.y_ppem / floorf(svg_height);
|
||||
float svg_scale = llmin(svg_x_scale, svg_y_scale);
|
||||
datap->Scale = svg_scale;
|
||||
|
||||
glyph_slot->bitmap.width = floorf(svg_width) * svg_scale;
|
||||
glyph_slot->bitmap.rows = floorf(svg_height) * svg_scale;
|
||||
glyph_slot->bitmap_left = (document->metrics.x_ppem - glyph_slot->bitmap.width) / 2;
|
||||
glyph_slot->bitmap_top = glyph_slot->face->size->metrics.ascender / 64.f;
|
||||
glyph_slot->bitmap.pitch = glyph_slot->bitmap.width * 4;
|
||||
glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
|
||||
/* Copied as-is from fcft (MIT license) */
|
||||
|
||||
// Compute all the bearings and set them correctly. The outline is scaled already, we just need to use the bounding box.
|
||||
float horiBearingX = 0.;
|
||||
float horiBearingY = -glyph_slot->bitmap_top;
|
||||
|
||||
// XXX parentheses correct?
|
||||
float vertBearingX = glyph_slot->metrics.horiBearingX / 64.0f - glyph_slot->metrics.horiAdvance / 64.0f / 2;
|
||||
float vertBearingY = (glyph_slot->metrics.vertAdvance / 64.0f - glyph_slot->metrics.height / 64.0f) / 2;
|
||||
|
||||
// Do conversion in two steps to avoid 'bad function cast' warning
|
||||
glyph_slot->metrics.width = glyph_slot->bitmap.width * 64;
|
||||
glyph_slot->metrics.height = glyph_slot->bitmap.rows * 64;
|
||||
glyph_slot->metrics.horiBearingX = horiBearingX * 64;
|
||||
glyph_slot->metrics.horiBearingY = horiBearingY * 64;
|
||||
glyph_slot->metrics.vertBearingX = vertBearingX * 64;
|
||||
glyph_slot->metrics.vertBearingY = vertBearingY * 64;
|
||||
if (glyph_slot->metrics.vertAdvance == 0)
|
||||
{
|
||||
glyph_slot->metrics.vertAdvance = glyph_slot->bitmap.rows * 1.2f * 64;
|
||||
}
|
||||
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
||||
// static
|
||||
FT_Error LLFontFreeTypeSvgRenderer::OnRender(FT_GlyphSlot glyph_slot, FT_Pointer*)
|
||||
{
|
||||
LLSvgRenderData* datap = static_cast<LLSvgRenderData*>(glyph_slot->generic.data);
|
||||
llassert(FT_Err_Ok == datap->Error);
|
||||
if (FT_Err_Ok != datap->Error)
|
||||
{
|
||||
return datap->Error;
|
||||
}
|
||||
|
||||
// Render to glyph bitmap
|
||||
NSVGrasterizer* nsvgRasterizer = nsvgCreateRasterizer();
|
||||
nsvgRasterize(nsvgRasterizer, datap->pNSvgImage, 0, 0, datap->Scale, glyph_slot->bitmap.buffer, glyph_slot->bitmap.width, glyph_slot->bitmap.rows, glyph_slot->bitmap.pitch);
|
||||
nsvgDeleteRasterizer(nsvgRasterizer);
|
||||
nsvgDelete(datap->pNSvgImage);
|
||||
datap->pNSvgImage = nullptr;
|
||||
|
||||
// Convert from RGBA to BGRA
|
||||
U32* pixel_buffer = (U32*)glyph_slot->bitmap.buffer; U8* byte_buffer = glyph_slot->bitmap.buffer;
|
||||
for (size_t y = 0, h = glyph_slot->bitmap.rows; y < h; y++)
|
||||
{
|
||||
for (size_t x = 0, w = glyph_slot->bitmap.pitch / 4; x < w; x++)
|
||||
{
|
||||
size_t pixel_idx = y * w + x;
|
||||
size_t byte_idx = pixel_idx * 4;
|
||||
U8 alpha = byte_buffer[byte_idx + 3];
|
||||
// Store as ARGB (*TODO - do we still have to care about endianness?)
|
||||
pixel_buffer[y * w + x] = alpha << 24 | (byte_buffer[byte_idx] * alpha / 0xFF) << 16 | (byte_buffer[byte_idx + 1] * alpha / 0xFF) << 8 | (byte_buffer[byte_idx + 2] * alpha / 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
glyph_slot->format = FT_GLYPH_FORMAT_BITMAP;
|
||||
glyph_slot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
|
||||
return FT_Err_Ok;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @file llfontfreetypesvg.h
|
||||
* @brief Freetype font library SVG glyph rendering
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_TYPES_H
|
||||
#include FT_MODULE_H
|
||||
#include FT_OTSVG_H
|
||||
|
||||
// See https://freetype.org/freetype2/docs/reference/ft2-svg_fonts.html
|
||||
class LLFontFreeTypeSvgRenderer
|
||||
{
|
||||
public:
|
||||
// Called when the very first OT-SVG glyph is rendered (across the entire lifetime of our FT_Library object)
|
||||
static FT_Error OnInit(FT_Pointer* state);
|
||||
|
||||
// Called when the ot-svg module is being freed (but only called if the init hook was called previously)
|
||||
static void OnFree(FT_Pointer* state);
|
||||
|
||||
// Called to preset the glyph slot, twice per glyph:
|
||||
// - when FT_Load_Glyph needs to preset the glyph slot (with cache == false)
|
||||
// - right before the svg module calls the render callback hook. (with cache == true)
|
||||
static FT_Error OnPresetGlypthSlot(FT_GlyphSlot glyph_slot, FT_Bool cache, FT_Pointer* state);
|
||||
|
||||
// Called to render an OT-SVG glyph (right after the preset hook OnPresetGlypthSlot was called with cache set to TRUE)
|
||||
static FT_Error OnRender(FT_GlyphSlot glyph_slot, FT_Pointer* state);
|
||||
|
||||
// Called to deallocate our per glyph slot data
|
||||
static void OnDataFinalizer(void* objectp);
|
||||
};
|
||||
|
|
@ -89,14 +89,14 @@ void LLFontGL::destroyGL()
|
|||
mFontFreetype->destroyGL();
|
||||
}
|
||||
|
||||
BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
|
||||
BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n)
|
||||
{
|
||||
if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
|
||||
{
|
||||
mFontFreetype = new LLFontFreetype;
|
||||
}
|
||||
|
||||
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback, face_n);
|
||||
return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, is_fallback, face_n);
|
||||
}
|
||||
|
||||
S32 LLFontGL::getNumFaces(const std::string& filename)
|
||||
|
|
@ -110,14 +110,14 @@ S32 LLFontGL::getNumFaces(const std::string& filename)
|
|||
}
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
LLRectf rect_float(rect.mLeft, rect.mTop, rect.mRight, rect.mBottom);
|
||||
return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses);
|
||||
return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color);
|
||||
}
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
|
||||
ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
F32 x = rect.mLeft;
|
||||
F32 y = 0.f;
|
||||
|
|
@ -138,12 +138,12 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec
|
|||
y = rect.mBottom;
|
||||
break;
|
||||
}
|
||||
return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses);
|
||||
return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses, use_color);
|
||||
}
|
||||
|
||||
|
||||
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
|
||||
ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
|
||||
ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI;
|
||||
|
||||
|
|
@ -283,7 +283,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
|
||||
LLColor4U text_color(color);
|
||||
|
||||
S32 bitmap_num = -1;
|
||||
std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1);
|
||||
S32 glyph_count = 0;
|
||||
for (i = begin_offset; i < begin_offset + length; i++)
|
||||
{
|
||||
|
|
@ -293,7 +293,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
next_glyph = NULL;
|
||||
if(!fgi)
|
||||
{
|
||||
fgi = mFontFreetype->getGlyphInfo(wch);
|
||||
fgi = mFontFreetype->getGlyphInfo(wch, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color);
|
||||
}
|
||||
if (!fgi)
|
||||
{
|
||||
|
|
@ -301,8 +301,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
break;
|
||||
}
|
||||
// Per-glyph bitmap texture.
|
||||
S32 next_bitmap_num = fgi->mBitmapNum;
|
||||
if (next_bitmap_num != bitmap_num)
|
||||
std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry;
|
||||
if (next_bitmap_entry != bitmap_entry)
|
||||
{
|
||||
// Actually draw the queued glyphs before switching their texture;
|
||||
// otherwise the queued glyphs will be taken from wrong textures.
|
||||
|
|
@ -323,8 +323,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
glyph_count = 0;
|
||||
}
|
||||
|
||||
bitmap_num = next_bitmap_num;
|
||||
LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
|
||||
bitmap_entry = next_bitmap_entry;
|
||||
LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second);
|
||||
gGL.getTexUnit(0)->bind(font_image);
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +364,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
glyph_count = 0;
|
||||
}
|
||||
|
||||
drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);
|
||||
drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, (bitmap_entry.first == EFontGlyphType::Grayscale) ? text_color : LLColor4U::white, style_to_add, shadow, drop_shadow_strength);
|
||||
|
||||
chars_drawn++;
|
||||
cur_x += fgi->mXAdvance;
|
||||
|
|
@ -374,7 +374,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
if (next_char && (next_char < LAST_CHARACTER))
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char, (!use_color) ? EFontGlyphType::Grayscale : EFontGlyphType::Color);
|
||||
cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
|
||||
}
|
||||
|
||||
|
|
@ -435,7 +435,8 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
|
|||
shadow,
|
||||
S32_MAX, max_pixels,
|
||||
right_x,
|
||||
FALSE);
|
||||
FALSE,
|
||||
use_color);
|
||||
gGL.popUIMatrix();
|
||||
}
|
||||
|
||||
|
|
@ -449,19 +450,19 @@ S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, cons
|
|||
return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const
|
||||
{
|
||||
return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses);
|
||||
return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE, FALSE);
|
||||
}
|
||||
|
||||
S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const
|
||||
{
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE, FALSE);
|
||||
}
|
||||
|
||||
// font metrics - override for LLFontFreetype that returns units of virtual pixels
|
||||
|
|
@ -538,7 +539,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
|
|||
next_glyph = NULL;
|
||||
if(!fgi)
|
||||
{
|
||||
fgi = mFontFreetype->getGlyphInfo(wch);
|
||||
fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
}
|
||||
|
||||
F32 advance = mFontFreetype->getXAdvance(fgi);
|
||||
|
|
@ -558,7 +559,7 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars
|
|||
&& (next_char < LAST_CHARACTER))
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(next_char, EFontGlyphType::Unspecified);
|
||||
cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
|
||||
}
|
||||
// Round after kerning.
|
||||
|
|
@ -576,7 +577,7 @@ void LLFontGL::generateASCIIglyphs()
|
|||
LL_PROFILE_ZONE_SCOPED_CATEGORY_UI
|
||||
for (U32 i = 32; (i < 127); i++)
|
||||
{
|
||||
mFontFreetype->getGlyphInfo(i);
|
||||
mFontFreetype->getGlyphInfo(i, EFontGlyphType::Grayscale);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -650,7 +651,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
|
|||
next_glyph = NULL;
|
||||
if(!fgi)
|
||||
{
|
||||
fgi = mFontFreetype->getGlyphInfo(wch);
|
||||
fgi = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
|
||||
if (NULL == fgi)
|
||||
{
|
||||
|
|
@ -675,7 +676,7 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch
|
|||
if (((i+1) < max_chars) && wchars[i+1])
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1], EFontGlyphType::Unspecified);
|
||||
cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
|
||||
}
|
||||
|
||||
|
|
@ -722,7 +723,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_
|
|||
{
|
||||
llwchar wch = wchars[i];
|
||||
|
||||
const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);
|
||||
const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
|
||||
// last character uses character width, since the whole character needs to be visible
|
||||
// other characters just use advance
|
||||
|
|
@ -797,7 +798,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t
|
|||
next_glyph = NULL;
|
||||
if(!glyph)
|
||||
{
|
||||
glyph = mFontFreetype->getGlyphInfo(wch);
|
||||
glyph = mFontFreetype->getGlyphInfo(wch, EFontGlyphType::Unspecified);
|
||||
}
|
||||
|
||||
F32 char_width = mFontFreetype->getXAdvance(glyph);
|
||||
|
|
@ -827,7 +828,7 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 t
|
|||
&& (wchars[(pos + 1)]))
|
||||
{
|
||||
// Kern this puppy.
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]);
|
||||
next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1], EFontGlyphType::Unspecified);
|
||||
cur_x += mFontFreetype->getXKerning(glyph, next_glyph);
|
||||
}
|
||||
|
||||
|
|
@ -897,6 +898,26 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st
|
|||
LLFontGL::loadDefaultFonts();
|
||||
}
|
||||
|
||||
void LLFontGL::dumpTextures()
|
||||
{
|
||||
if (mFontFreetype.notNull())
|
||||
{
|
||||
mFontFreetype->dumpFontBitmaps();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontGL::dumpFonts()
|
||||
{
|
||||
sFontRegistry->dump();
|
||||
}
|
||||
|
||||
// static
|
||||
void LLFontGL::dumpFontTextures()
|
||||
{
|
||||
sFontRegistry->dumpTextures();
|
||||
}
|
||||
|
||||
// Force standard fonts to get generated up front.
|
||||
// This is primarily for error detection purposes.
|
||||
// Don't do this during initClass because it can be slow and we want to get
|
||||
|
|
@ -1063,6 +1084,13 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
|
|||
return gl_vfont_align;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontEmoji()
|
||||
{
|
||||
static LLFontGL* fontp = getFont(LLFontDescriptor("Emoji", "Large", 0));
|
||||
return fontp;;
|
||||
}
|
||||
|
||||
//static
|
||||
LLFontGL* LLFontGL::getFontMonospace()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ public:
|
|||
|
||||
void destroyGL();
|
||||
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback, S32 face_n = 0);
|
||||
BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n);
|
||||
|
||||
S32 getNumFaces(const std::string& filename);
|
||||
|
||||
|
|
@ -98,7 +98,8 @@ public:
|
|||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
BOOL use_ellipses = FALSE,
|
||||
BOOL use_color = FALSE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset,
|
||||
const LLRectf& rect,
|
||||
|
|
@ -107,7 +108,8 @@ public:
|
|||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
BOOL use_ellipses = FALSE,
|
||||
BOOL use_color = FALSE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset,
|
||||
F32 x, F32 y,
|
||||
|
|
@ -116,12 +118,13 @@ public:
|
|||
U8 style = NORMAL, ShadowType shadow = NO_SHADOW,
|
||||
S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX,
|
||||
F32* right_x=NULL,
|
||||
BOOL use_ellipses = FALSE) const;
|
||||
BOOL use_ellipses = FALSE,
|
||||
BOOL use_color = FALSE) const;
|
||||
|
||||
S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const;
|
||||
|
||||
// renderUTF8 does a conversion, so is slower!
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses, BOOL use_color) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const;
|
||||
S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const;
|
||||
|
||||
|
|
@ -165,6 +168,10 @@ public:
|
|||
|
||||
static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::string& fonts_file, F32 size_mod = 0, bool create_gl_textures = true);
|
||||
|
||||
void dumpTextures();
|
||||
static void dumpFonts();
|
||||
static void dumpFontTextures();
|
||||
|
||||
// Load sans-serif, sans-serif-small, etc.
|
||||
// Slow, requires multiple seconds to load fonts.
|
||||
static bool loadDefaultFonts();
|
||||
|
|
@ -187,6 +194,7 @@ public:
|
|||
|
||||
static void setFontDisplay(BOOL flag) { sDisplayFont = flag; }
|
||||
|
||||
static LLFontGL* getFontEmoji();
|
||||
static LLFontGL* getFontMonospace();
|
||||
static LLFontGL* getFontSansSerifSmall();
|
||||
static LLFontGL* getFontSansSerif();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node);
|
|||
const std::string MACOSX_FONT_PATH_LIBRARY = "/Library/Fonts/";
|
||||
const std::string MACOSX_FONT_SUPPLEMENTAL = "Supplemental/";
|
||||
|
||||
LLFontDescriptor::char_functor_map_t LLFontDescriptor::mCharFunctors({
|
||||
{ "is_emoji", LLStringOps::isEmoji }
|
||||
});
|
||||
|
||||
LLFontDescriptor::LLFontDescriptor():
|
||||
mStyle(0)
|
||||
{
|
||||
|
|
@ -55,22 +59,22 @@ LLFontDescriptor::LLFontDescriptor():
|
|||
LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
||||
const std::string& size,
|
||||
const U8 style,
|
||||
const string_vec_t& file_names):
|
||||
const font_file_info_vec_t& font_files):
|
||||
mName(name),
|
||||
mSize(size),
|
||||
mStyle(style),
|
||||
mFileNames(file_names)
|
||||
mFontFiles(font_files)
|
||||
{
|
||||
}
|
||||
|
||||
LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
||||
const std::string& size,
|
||||
const U8 style,
|
||||
const string_vec_t& file_names,
|
||||
const string_vec_t& ft_collection_listections) :
|
||||
LLFontDescriptor(name, size, style, file_names)
|
||||
const font_file_info_vec_t& font_list,
|
||||
const font_file_info_vec_t& font_collection_files) :
|
||||
LLFontDescriptor(name, size, style, font_list)
|
||||
{
|
||||
mFontCollectionsList = ft_collection_listections;
|
||||
mFontCollectionFiles = font_collection_files;
|
||||
}
|
||||
|
||||
LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
||||
|
|
@ -82,7 +86,6 @@ LLFontDescriptor::LLFontDescriptor(const std::string& name,
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
|
||||
{
|
||||
if (mName < b.mName)
|
||||
|
|
@ -181,7 +184,19 @@ LLFontDescriptor LLFontDescriptor::normalize() const
|
|||
if (removeSubString(new_name,"Italic"))
|
||||
new_style |= LLFontGL::ITALIC;
|
||||
|
||||
return LLFontDescriptor(new_name,new_size,new_style,getFileNames(),getFontCollectionsList());
|
||||
return LLFontDescriptor(new_name,new_size,new_style, getFontFiles(), getFontCollectionFiles());
|
||||
}
|
||||
|
||||
void LLFontDescriptor::addFontFile(const std::string& file_name, const std::string& char_functor)
|
||||
{
|
||||
char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
|
||||
mFontFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
|
||||
}
|
||||
|
||||
void LLFontDescriptor::addFontCollectionFile(const std::string& file_name, const std::string& char_functor)
|
||||
{
|
||||
char_functor_map_t::const_iterator it = mCharFunctors.find(char_functor);
|
||||
mFontCollectionFiles.push_back(LLFontFileInfo(file_name, (mCharFunctors.end() != it) ? it->second : nullptr));
|
||||
}
|
||||
|
||||
LLFontRegistry::LLFontRegistry(bool create_gl_textures, F32 size_mod)
|
||||
|
|
@ -308,17 +323,24 @@ bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
|
|||
if (child->hasName("file"))
|
||||
{
|
||||
std::string font_file_name = child->getTextContents();
|
||||
desc.getFileNames().push_back(font_file_name);
|
||||
|
||||
std::string char_functor;
|
||||
|
||||
if (child->hasAttribute("functor"))
|
||||
{
|
||||
child->getAttributeString("functor", char_functor);
|
||||
}
|
||||
|
||||
if (child->hasAttribute("load_collection"))
|
||||
{
|
||||
BOOL col = FALSE;
|
||||
child->getAttributeBOOL("load_collection", col);
|
||||
if (col)
|
||||
{
|
||||
desc.getFontCollectionsList().push_back(font_file_name);
|
||||
desc.addFontCollectionFile(font_file_name, char_functor);
|
||||
}
|
||||
}
|
||||
|
||||
desc.addFontFile(font_file_name, char_functor);
|
||||
}
|
||||
else if (child->hasName("os"))
|
||||
{
|
||||
|
|
@ -361,19 +383,19 @@ bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node)
|
|||
// A little roundabout because the map key is const,
|
||||
// so we have to fetch it, make a new map key, and
|
||||
// replace the old entry.
|
||||
string_vec_t match_file_names = match_desc->getFileNames();
|
||||
match_file_names.insert(match_file_names.begin(),
|
||||
desc.getFileNames().begin(),
|
||||
desc.getFileNames().end());
|
||||
font_file_info_vec_t font_files = match_desc->getFontFiles();
|
||||
font_files.insert(font_files.begin(),
|
||||
desc.getFontFiles().begin(),
|
||||
desc.getFontFiles().end());
|
||||
|
||||
string_vec_t collections_list = match_desc->getFontCollectionsList();
|
||||
collections_list.insert(collections_list.begin(),
|
||||
desc.getFontCollectionsList().begin(),
|
||||
desc.getFontCollectionsList().end());
|
||||
font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles();
|
||||
font_collection_files.insert(font_collection_files.begin(),
|
||||
desc.getFontCollectionFiles().begin(),
|
||||
desc.getFontCollectionFiles().end());
|
||||
|
||||
LLFontDescriptor new_desc = *match_desc;
|
||||
new_desc.getFileNames() = match_file_names;
|
||||
new_desc.getFontCollectionsList() = collections_list;
|
||||
new_desc.setFontFiles(font_files);
|
||||
new_desc.setFontCollectionFiles(font_collection_files);
|
||||
registry->mFontMap.erase(*match_desc);
|
||||
registry->mFontMap[new_desc] = NULL;
|
||||
}
|
||||
|
|
@ -460,86 +482,82 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
|
|||
|
||||
// Build list of font names to look for.
|
||||
// Files specified for this font come first, followed by those from the default descriptor.
|
||||
string_vec_t file_names = match_desc->getFileNames();
|
||||
string_vec_t ft_collection_list = match_desc->getFontCollectionsList();
|
||||
string_vec_t default_file_names;
|
||||
font_file_info_vec_t font_files = match_desc->getFontFiles();
|
||||
font_file_info_vec_t font_collection_files = match_desc->getFontCollectionFiles();
|
||||
LLFontDescriptor default_desc("default",s_template_string,0);
|
||||
const LLFontDescriptor *match_default_desc = getMatchingFontDesc(default_desc);
|
||||
if (match_default_desc)
|
||||
{
|
||||
file_names.insert(file_names.end(),
|
||||
match_default_desc->getFileNames().begin(),
|
||||
match_default_desc->getFileNames().end());
|
||||
ft_collection_list.insert(ft_collection_list.end(),
|
||||
match_default_desc->getFontCollectionsList().begin(),
|
||||
match_default_desc->getFontCollectionsList().end());
|
||||
font_files.insert(font_files.end(),
|
||||
match_default_desc->getFontFiles().begin(),
|
||||
match_default_desc->getFontFiles().end());
|
||||
font_collection_files.insert(font_collection_files.end(),
|
||||
match_default_desc->getFontCollectionFiles().begin(),
|
||||
match_default_desc->getFontCollectionFiles().end());
|
||||
}
|
||||
|
||||
// Add ultimate fallback list - generated dynamically on linux,
|
||||
// null elsewhere.
|
||||
file_names.insert(file_names.end(),
|
||||
getUltimateFallbackList().begin(),
|
||||
getUltimateFallbackList().end());
|
||||
std::transform(getUltimateFallbackList().begin(), getUltimateFallbackList().end(), std::back_inserter(font_files),
|
||||
[](const std::string& file_name) { return LLFontFileInfo(file_name); });
|
||||
|
||||
// Load fonts based on names.
|
||||
if (file_names.empty())
|
||||
if (font_files.empty())
|
||||
{
|
||||
LL_WARNS() << "createFont failed, no file names specified" << LL_ENDL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLFontFreetype::font_vector_t fontlist;
|
||||
LLFontGL *result = NULL;
|
||||
|
||||
// Snarf all fonts we can into fontlist. First will get pulled
|
||||
// off the list and become the "head" font, set to non-fallback.
|
||||
// The first font will get pulled will be the "head" font, set to non-fallback.
|
||||
// Rest will consitute the fallback list.
|
||||
BOOL is_first_found = TRUE;
|
||||
|
||||
std::string local_path = LLFontGL::getFontPathLocal();
|
||||
std::string sys_path = LLFontGL::getFontPathSystem();
|
||||
string_vec_t font_search_paths;
|
||||
font_search_paths.push_back(LLFontGL::getFontPathLocal());
|
||||
font_search_paths.push_back(LLFontGL::getFontPathSystem());
|
||||
// <FS:Kadah> User fonts: Also load from user_settings/fonts
|
||||
std::string usr_path = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "fonts", "");
|
||||
|
||||
font_search_paths.push_back(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "fonts", ""));
|
||||
#if LL_DARWIN
|
||||
font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY);
|
||||
font_search_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL);
|
||||
font_search_paths.push_back(sys_path + MACOSX_FONT_SUPPLEMENTAL);
|
||||
#endif
|
||||
|
||||
// The fontname string may contain multiple font file names separated by semicolons.
|
||||
// Break it apart and try loading each one, in order.
|
||||
for(string_vec_t::iterator file_name_it = file_names.begin();
|
||||
file_name_it != file_names.end();
|
||||
++file_name_it)
|
||||
for(font_file_info_vec_t::iterator font_file_it = font_files.begin();
|
||||
font_file_it != font_files.end();
|
||||
++font_file_it)
|
||||
{
|
||||
LLFontGL *fontp = NULL;
|
||||
string_vec_t font_paths;
|
||||
font_paths.push_back(local_path + *file_name_it);
|
||||
font_paths.push_back(sys_path + *file_name_it);
|
||||
// <FS:Kadah> User fonts: Also load from user_settings/fonts
|
||||
font_paths.push_back(usr_path + *file_name_it);
|
||||
#if LL_DARWIN
|
||||
font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + *file_name_it);
|
||||
font_paths.push_back(MACOSX_FONT_PATH_LIBRARY + MACOSX_FONT_SUPPLEMENTAL + *file_name_it);
|
||||
font_paths.push_back(sys_path + MACOSX_FONT_SUPPLEMENTAL + *file_name_it);
|
||||
#endif
|
||||
|
||||
bool is_ft_collection = (std::find(ft_collection_list.begin(), ft_collection_list.end(), *file_name_it) != ft_collection_list.end());
|
||||
|
||||
bool is_ft_collection = (std::find_if(font_collection_files.begin(), font_collection_files.end(),
|
||||
[&font_file_it](const LLFontFileInfo& ffi) { return font_file_it->FileName == ffi.FileName; }) != font_collection_files.end());
|
||||
|
||||
// *HACK: Fallback fonts don't render, so we can use that to suppress
|
||||
// creation of OpenGL textures for test apps. JC
|
||||
BOOL is_fallback = !is_first_found || !mCreateGLTextures;
|
||||
F32 extra_scale = (is_fallback)?fallback_scale:1.0;
|
||||
F32 point_size_scale = extra_scale * point_size;
|
||||
bool is_font_loaded = false;
|
||||
for(string_vec_t::iterator font_paths_it = font_paths.begin();
|
||||
font_paths_it != font_paths.end();
|
||||
++font_paths_it)
|
||||
for(string_vec_t::iterator font_search_path_it = font_search_paths.begin();
|
||||
font_search_path_it != font_search_paths.end();
|
||||
++font_search_path_it)
|
||||
{
|
||||
const std::string font_path = *font_search_path_it + font_file_it->FileName;
|
||||
|
||||
fontp = new LLFontGL;
|
||||
S32 num_faces = is_ft_collection ? fontp->getNumFaces(*font_paths_it) : 1;
|
||||
S32 num_faces = is_ft_collection ? fontp->getNumFaces(font_path) : 1;
|
||||
for (S32 i = 0; i < num_faces; i++)
|
||||
{
|
||||
if (fontp == NULL)
|
||||
{
|
||||
fontp = new LLFontGL;
|
||||
}
|
||||
if (fontp->loadFace(*font_paths_it, point_size_scale,
|
||||
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback, i))
|
||||
if (fontp->loadFace(font_path, point_size_scale,
|
||||
LLFontGL::sVertDPI, LLFontGL::sHorizDPI, is_fallback, i))
|
||||
{
|
||||
is_font_loaded = true;
|
||||
if (is_first_found)
|
||||
|
|
@ -549,7 +567,8 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
|
|||
}
|
||||
else
|
||||
{
|
||||
fontlist.push_back(fontp->mFontFreetype);
|
||||
result->mFontFreetype->addFallbackFont(fontp->mFontFreetype, font_file_it->CharFunctor);
|
||||
|
||||
delete fontp;
|
||||
fontp = NULL;
|
||||
}
|
||||
|
|
@ -564,17 +583,12 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc)
|
|||
}
|
||||
if(!is_font_loaded)
|
||||
{
|
||||
LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << *file_name_it << LL_ENDL;
|
||||
LL_INFOS_ONCE("LLFontRegistry") << "Couldn't load font " << font_file_it->FileName << LL_ENDL;
|
||||
delete fontp;
|
||||
fontp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (result && !fontlist.empty())
|
||||
{
|
||||
result->mFontFreetype->setFallbackFonts(fontlist);
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
result->mFontDescriptor = desc;
|
||||
|
|
@ -761,11 +775,22 @@ void LLFontRegistry::dump()
|
|||
<< " size=[" << desc.getSize() << "]"
|
||||
<< " fileNames="
|
||||
<< LL_ENDL;
|
||||
for (string_vec_t::const_iterator file_it=desc.getFileNames().begin();
|
||||
file_it != desc.getFileNames().end();
|
||||
for (font_file_info_vec_t::const_iterator file_it=desc.getFontFiles().begin();
|
||||
file_it != desc.getFontFiles().end();
|
||||
++file_it)
|
||||
{
|
||||
LL_INFOS() << " file: " << *file_it <<LL_ENDL;
|
||||
LL_INFOS() << " file: " << file_it->FileName << LL_ENDL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLFontRegistry::dumpTextures()
|
||||
{
|
||||
for (const auto& fontEntry : mFontMap)
|
||||
{
|
||||
if (fontEntry.second)
|
||||
{
|
||||
fontEntry.second->dumpTextures();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,32 @@ class LLFontGL;
|
|||
|
||||
typedef std::vector<std::string> string_vec_t;
|
||||
|
||||
struct LLFontFileInfo
|
||||
{
|
||||
LLFontFileInfo(const std::string& file_name, const std::function<bool(llwchar)>& char_functor = nullptr)
|
||||
: FileName(file_name)
|
||||
, CharFunctor(char_functor)
|
||||
{
|
||||
}
|
||||
|
||||
LLFontFileInfo(const LLFontFileInfo& ffi)
|
||||
: FileName(ffi.FileName)
|
||||
, CharFunctor(ffi.CharFunctor)
|
||||
{
|
||||
}
|
||||
|
||||
std::string FileName;
|
||||
std::function<bool(llwchar)> CharFunctor;
|
||||
};
|
||||
typedef std::vector<LLFontFileInfo> font_file_info_vec_t;
|
||||
|
||||
class LLFontDescriptor
|
||||
{
|
||||
public:
|
||||
LLFontDescriptor();
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const string_vec_t& file_names, const string_vec_t& font_collections);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list);
|
||||
LLFontDescriptor(const std::string& name, const std::string& size, const U8 style, const font_file_info_vec_t& font_list, const font_file_info_vec_t& font_collection_list);
|
||||
LLFontDescriptor normalize() const;
|
||||
|
||||
bool operator<(const LLFontDescriptor& b) const;
|
||||
|
|
@ -51,19 +70,26 @@ public:
|
|||
void setName(const std::string& name) { mName = name; }
|
||||
const std::string& getSize() const { return mSize; }
|
||||
void setSize(const std::string& size) { mSize = size; }
|
||||
const std::vector<std::string>& getFileNames() const { return mFileNames; }
|
||||
std::vector<std::string>& getFileNames() { return mFileNames; }
|
||||
const std::vector<std::string>& getFontCollectionsList() const { return mFontCollectionsList; }
|
||||
std::vector<std::string>& getFontCollectionsList() { return mFontCollectionsList; }
|
||||
|
||||
void addFontFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
|
||||
const font_file_info_vec_t & getFontFiles() const { return mFontFiles; }
|
||||
void setFontFiles(const font_file_info_vec_t& font_files) { mFontFiles = font_files; }
|
||||
void addFontCollectionFile(const std::string& file_name, const std::string& char_functor = LLStringUtil::null);
|
||||
const font_file_info_vec_t& getFontCollectionFiles() const { return mFontCollectionFiles; }
|
||||
void setFontCollectionFiles(const font_file_info_vec_t& font_collection_files) { mFontCollectionFiles = font_collection_files; }
|
||||
|
||||
const U8 getStyle() const { return mStyle; }
|
||||
void setStyle(U8 style) { mStyle = style; }
|
||||
|
||||
private:
|
||||
std::string mName;
|
||||
std::string mSize;
|
||||
string_vec_t mFileNames;
|
||||
string_vec_t mFontCollectionsList;
|
||||
font_file_info_vec_t mFontFiles;
|
||||
font_file_info_vec_t mFontCollectionFiles;
|
||||
U8 mStyle;
|
||||
|
||||
typedef std::map<std::string, std::function<bool(llwchar)>> char_functor_map_t;
|
||||
static char_functor_map_t mCharFunctors;
|
||||
};
|
||||
|
||||
class LLFontRegistry
|
||||
|
|
@ -94,6 +120,7 @@ public:
|
|||
bool nameToSize(const std::string& size_name, F32& size);
|
||||
|
||||
void dump();
|
||||
void dumpTextures();
|
||||
|
||||
const string_vec_t& getUltimateFallbackList() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ set(llui_SOURCE_FILES
|
|||
lldockcontrol.cpp
|
||||
lldraghandle.cpp
|
||||
lleditmenuhandler.cpp
|
||||
llemojidictionary.cpp
|
||||
llemojihelper.cpp
|
||||
llf32uictrl.cpp
|
||||
llfiltereditor.cpp
|
||||
llflashtimer.cpp
|
||||
|
|
@ -167,6 +169,8 @@ set(llui_HEADER_FILES
|
|||
lldockablefloater.h
|
||||
lldockcontrol.h
|
||||
lleditmenuhandler.h
|
||||
llemojidictionary.h
|
||||
llemojihelper.h
|
||||
llf32uictrl.h
|
||||
llfiltereditor.h
|
||||
llflashtimer.h
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
* @file llemojidictionary.cpp
|
||||
* @brief Implementation of LLEmojiDictionary
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "lldir.h"
|
||||
#include "llemojidictionary.h"
|
||||
#include "llsdserialize.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/range/adaptor/filtered.hpp>
|
||||
#include <boost/range/algorithm/transform.hpp>
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
//
|
||||
|
||||
constexpr char SKINNED_EMOJI_FILENAME[] = "emoji_characters.xml";
|
||||
|
||||
// ============================================================================
|
||||
// Helper functions
|
||||
//
|
||||
|
||||
template<class T>
|
||||
std::list<T> llsd_array_to_list(const LLSD& sd, std::function<void(T&)> mutator = {});
|
||||
|
||||
template<>
|
||||
std::list<std::string> llsd_array_to_list(const LLSD& sd, std::function<void(std::string&)> mutator)
|
||||
{
|
||||
std::list<std::string> result;
|
||||
for (LLSD::array_const_iterator it = sd.beginArray(), end = sd.endArray(); it != end; ++it)
|
||||
{
|
||||
const LLSD& entry = *it;
|
||||
if (!entry.isString())
|
||||
continue;
|
||||
|
||||
result.push_back(entry.asStringRef());
|
||||
if (mutator)
|
||||
{
|
||||
mutator(result.back());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
LLEmojiDescriptor::LLEmojiDescriptor(const LLSD& descriptor_sd)
|
||||
{
|
||||
Name = descriptor_sd["Name"].asStringRef();
|
||||
|
||||
const LLWString emoji_string = utf8str_to_wstring(descriptor_sd["Character"].asString());
|
||||
Character = (1 == emoji_string.size()) ? emoji_string[0] : L'\0'; // We don't currently support character composition
|
||||
|
||||
auto toLower = [](std::string& str) { LLStringUtil::toLower(str); };
|
||||
ShortCodes = llsd_array_to_list<std::string>(descriptor_sd["ShortCodes"], toLower);
|
||||
Categories = llsd_array_to_list<std::string>(descriptor_sd["Categories"], toLower);
|
||||
|
||||
if (Name.empty())
|
||||
{
|
||||
Name = ShortCodes.front();
|
||||
}
|
||||
}
|
||||
|
||||
bool LLEmojiDescriptor::isValid() const
|
||||
{
|
||||
return
|
||||
Character &&
|
||||
!ShortCodes.empty() &&
|
||||
!Categories.empty();
|
||||
}
|
||||
|
||||
struct emoji_filter_base
|
||||
{
|
||||
emoji_filter_base(const std::string& needle)
|
||||
{
|
||||
// Search without the colon (if present) so the user can type ':food' and see all emojis in the 'Food' category
|
||||
mNeedle = (boost::starts_with(needle, ":")) ? needle.substr(1) : needle;
|
||||
LLStringUtil::toLower(mNeedle);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string mNeedle;
|
||||
};
|
||||
|
||||
struct emoji_filter_shortcode_or_category_contains : public emoji_filter_base
|
||||
{
|
||||
emoji_filter_shortcode_or_category_contains(const std::string& needle) : emoji_filter_base(needle) {}
|
||||
|
||||
bool operator()(const LLEmojiDescriptor& descr) const
|
||||
{
|
||||
for (const auto& short_code : descr.ShortCodes)
|
||||
{
|
||||
if (boost::icontains(short_code, mNeedle))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const auto& category : descr.Categories)
|
||||
{
|
||||
if (boost::icontains(category, mNeedle))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiDictionary class
|
||||
//
|
||||
|
||||
LLEmojiDictionary::LLEmojiDictionary()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
void LLEmojiDictionary::initClass()
|
||||
{
|
||||
LLEmojiDictionary* pThis = &LLEmojiDictionary::initParamSingleton();
|
||||
|
||||
LLSD data;
|
||||
|
||||
const std::string filename = gDirUtilp->findSkinnedFilenames(LLDir::XUI, SKINNED_EMOJI_FILENAME, LLDir::CURRENT_SKIN).front();
|
||||
llifstream file(filename.c_str());
|
||||
if (file.is_open())
|
||||
{
|
||||
LL_DEBUGS() << "Loading emoji characters file at " << filename << LL_ENDL;
|
||||
LLSDSerialize::fromXML(data, file);
|
||||
}
|
||||
|
||||
if (data.isUndefined())
|
||||
{
|
||||
LL_WARNS() << "Emoji file characters missing or ill-formed" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
for (LLSD::array_const_iterator descriptor_it = data.beginArray(), descriptor_end = data.endArray(); descriptor_it != descriptor_end; ++descriptor_it)
|
||||
{
|
||||
LLEmojiDescriptor descriptor(*descriptor_it);
|
||||
if (!descriptor.isValid())
|
||||
{
|
||||
LL_WARNS() << "Skipping invalid emoji descriptor " << descriptor.Character << LL_ENDL;
|
||||
continue;
|
||||
}
|
||||
pThis->addEmoji(std::move(descriptor));
|
||||
}
|
||||
}
|
||||
|
||||
LLWString LLEmojiDictionary::findMatchingEmojis(const std::string& needle) const
|
||||
{
|
||||
LLWString result;
|
||||
boost::transform(mEmojis | boost::adaptors::filtered(emoji_filter_shortcode_or_category_contains(needle)),
|
||||
std::back_inserter(result), [](const auto& descr) { return descr.Character; });
|
||||
return result;
|
||||
}
|
||||
|
||||
const LLEmojiDescriptor* LLEmojiDictionary::getDescriptorFromShortCode(const std::string& short_code) const
|
||||
{
|
||||
const auto it = mShortCode2Descr.find(short_code);
|
||||
return (mShortCode2Descr.end() != it) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
std::string LLEmojiDictionary::getNameFromEmoji(llwchar ch) const
|
||||
{
|
||||
const auto it = mEmoji2Descr.find(ch);
|
||||
return (mEmoji2Descr.end() != it) ? it->second->Name : LLStringUtil::null;
|
||||
}
|
||||
|
||||
void LLEmojiDictionary::addEmoji(LLEmojiDescriptor&& descr)
|
||||
{
|
||||
mEmojis.push_back(descr);
|
||||
mEmoji2Descr.insert(std::make_pair(descr.Character, &mEmojis.back()));
|
||||
for (const std::string& shortCode : descr.ShortCodes)
|
||||
{
|
||||
mShortCode2Descr.insert(std::make_pair(shortCode, &mEmojis.back()));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file llemojidictionary.h
|
||||
* @brief Header file for LLEmojiDictionary
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lldictionary.h"
|
||||
#include "llinitdestroyclass.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiDescriptor class
|
||||
//
|
||||
|
||||
struct LLEmojiDescriptor
|
||||
{
|
||||
LLEmojiDescriptor(const LLSD& descriptor_sd);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
std::string Name;
|
||||
llwchar Character;
|
||||
std::list<std::string> ShortCodes;
|
||||
std::list<std::string> Categories;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiDictionary class
|
||||
//
|
||||
|
||||
class LLEmojiDictionary : public LLParamSingleton<LLEmojiDictionary>, public LLInitClass<LLEmojiDictionary>
|
||||
{
|
||||
LLSINGLETON(LLEmojiDictionary);
|
||||
~LLEmojiDictionary() override {};
|
||||
|
||||
public:
|
||||
static void initClass();
|
||||
LLWString findMatchingEmojis(const std::string& needle) const;
|
||||
const LLEmojiDescriptor* getDescriptorFromShortCode(const std::string& short_code) const;
|
||||
std::string getNameFromEmoji(llwchar ch) const;
|
||||
|
||||
private:
|
||||
void addEmoji(LLEmojiDescriptor&& descr);
|
||||
|
||||
private:
|
||||
std::list<LLEmojiDescriptor> mEmojis;
|
||||
std::map<llwchar, const LLEmojiDescriptor*> mEmoji2Descr;
|
||||
std::map<std::string, const LLEmojiDescriptor*> mShortCode2Descr;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
/**
|
||||
* @file llemojihelper.h
|
||||
* @brief Header file for LLEmojiHelper
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llemojidictionary.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "llfloater.h"
|
||||
#include "llfloaterreg.h"
|
||||
#include "lluictrl.h"
|
||||
|
||||
// ============================================================================
|
||||
// Constants
|
||||
//
|
||||
|
||||
constexpr char DEFAULT_EMOJI_HELPER_FLOATER[] = "emoji_complete";
|
||||
constexpr S32 HELPER_FLOATER_OFFSET_X = 20;
|
||||
constexpr S32 HELPER_FLOATER_OFFSET_Y = 0;
|
||||
|
||||
// ============================================================================
|
||||
// LLEmojiHelper
|
||||
//
|
||||
|
||||
std::string LLEmojiHelper::getToolTip(llwchar ch) const
|
||||
{
|
||||
return LLEmojiDictionary::instance().getNameFromEmoji(ch);
|
||||
}
|
||||
|
||||
bool LLEmojiHelper::isActive(const LLUICtrl* ctrl_p) const
|
||||
{
|
||||
return mHostHandle.get() == ctrl_p;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLEmojiHelper::isCursorInEmojiCode(const LLWString& wtext, S32 cursorPos, S32* pShortCodePos)
|
||||
{
|
||||
// If the cursor is currently on a colon start the check one character further back
|
||||
S32 shortCodePos = (cursorPos == 0 || L':' != wtext[cursorPos - 1]) ? cursorPos : cursorPos - 1;
|
||||
|
||||
auto isPartOfShortcode = [](llwchar ch) {
|
||||
switch (ch)
|
||||
{
|
||||
case L'-':
|
||||
case L'_':
|
||||
case L'+':
|
||||
return true;
|
||||
default:
|
||||
return LLStringOps::isAlnum(ch);
|
||||
}
|
||||
};
|
||||
while (shortCodePos > 1 && isPartOfShortcode(wtext[shortCodePos - 1]))
|
||||
{
|
||||
shortCodePos--;
|
||||
}
|
||||
|
||||
bool isShortCode = (L':' == wtext[shortCodePos - 1]) && (cursorPos - shortCodePos >= 2);
|
||||
if (pShortCodePos)
|
||||
*pShortCodePos = (isShortCode) ? shortCodePos - 1 : -1;
|
||||
return isShortCode;
|
||||
}
|
||||
|
||||
void LLEmojiHelper::showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(LLWString)> cb)
|
||||
{
|
||||
// Commit immediately if the user already typed a full shortcode
|
||||
if (const auto* emojiDescrp = LLEmojiDictionary::instance().getDescriptorFromShortCode(short_code))
|
||||
{
|
||||
cb(LLWString(1, emojiDescrp->Character));
|
||||
hideHelper();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHelperHandle.isDead())
|
||||
{
|
||||
LLFloater* pHelperFloater = LLFloaterReg::getInstance(DEFAULT_EMOJI_HELPER_FLOATER);
|
||||
mHelperHandle = pHelperFloater->getHandle();
|
||||
mHelperCommitConn = pHelperFloater->setCommitCallback(std::bind([&](const LLSD& sdValue) { onCommitEmoji(utf8str_to_wstring(sdValue.asStringRef())); }, std::placeholders::_2));
|
||||
}
|
||||
setHostCtrl(hostctrl_p);
|
||||
mEmojiCommitCb = cb;
|
||||
|
||||
S32 floater_x, floater_y;
|
||||
if (!hostctrl_p->localPointToOtherView(local_x, local_y, &floater_x, &floater_y, gFloaterView))
|
||||
{
|
||||
LL_ERRS() << "Cannot show emoji helper for non-floater controls." << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater* pHelperFloater = mHelperHandle.get();
|
||||
LLRect rct = pHelperFloater->getRect();
|
||||
rct.setLeftTopAndSize(floater_x - HELPER_FLOATER_OFFSET_X, floater_y - HELPER_FLOATER_OFFSET_Y + rct.getHeight(), rct.getWidth(), rct.getHeight());
|
||||
pHelperFloater->setRect(rct);
|
||||
pHelperFloater->openFloater(LLSD().with("hint", short_code));
|
||||
}
|
||||
|
||||
void LLEmojiHelper::hideHelper(const LLUICtrl* ctrl_p)
|
||||
{
|
||||
if (ctrl_p && !isActive(ctrl_p))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setHostCtrl(nullptr);
|
||||
}
|
||||
|
||||
bool LLEmojiHelper::handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask)
|
||||
{
|
||||
if (mHelperHandle.isDead() || !isActive(ctrl_p))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return mHelperHandle.get()->handleKey(key, mask, true);
|
||||
}
|
||||
|
||||
void LLEmojiHelper::onCommitEmoji(const LLWString& wstr)
|
||||
{
|
||||
if (!mHostHandle.isDead() && mEmojiCommitCb)
|
||||
{
|
||||
mEmojiCommitCb(wstr);
|
||||
}
|
||||
}
|
||||
|
||||
void LLEmojiHelper::setHostCtrl(LLUICtrl* hostctrl_p)
|
||||
{
|
||||
const LLUICtrl* pCurHostCtrl = mHostHandle.get();
|
||||
if (pCurHostCtrl != hostctrl_p)
|
||||
{
|
||||
mHostCtrlFocusLostConn.disconnect();
|
||||
mHostHandle.markDead();
|
||||
mEmojiCommitCb = {};
|
||||
|
||||
if (!mHelperHandle.isDead())
|
||||
{
|
||||
mHelperHandle.get()->closeFloater();
|
||||
}
|
||||
|
||||
if (hostctrl_p)
|
||||
{
|
||||
mHostHandle = hostctrl_p->getHandle();
|
||||
mHostCtrlFocusLostConn = hostctrl_p->setFocusLostCallback(std::bind([&]() { hideHelper(getHostCtrl()); }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* @file llemojihelper.h
|
||||
* @brief Header file for LLEmojiHelper
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "llhandle.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
class LLFloater;
|
||||
class LLUICtrl;
|
||||
|
||||
class LLEmojiHelper : public LLSingleton<LLEmojiHelper>
|
||||
{
|
||||
LLSINGLETON(LLEmojiHelper) {}
|
||||
~LLEmojiHelper() override {}
|
||||
|
||||
public:
|
||||
// General
|
||||
std::string getToolTip(llwchar ch) const;
|
||||
bool isActive(const LLUICtrl* ctrl_p) const;
|
||||
static bool isCursorInEmojiCode(const LLWString& wtext, S32 cursor_pos, S32* short_code_pos_p = nullptr);
|
||||
void showHelper(LLUICtrl* hostctrl_p, S32 local_x, S32 local_y, const std::string& short_code, std::function<void(LLWString)> commit_cb);
|
||||
void hideHelper(const LLUICtrl* ctrl_p = nullptr);
|
||||
|
||||
// Eventing
|
||||
bool handleKey(const LLUICtrl* ctrl_p, KEY key, MASK mask);
|
||||
void onCommitEmoji(const LLWString& wstr);
|
||||
|
||||
protected:
|
||||
LLUICtrl* getHostCtrl() const { return mHostHandle.get(); }
|
||||
void setHostCtrl(LLUICtrl* hostctrl_p);
|
||||
|
||||
private:
|
||||
LLHandle<LLUICtrl> mHostHandle;
|
||||
LLHandle<LLFloater> mHelperHandle;
|
||||
boost::signals2::connection mHostCtrlFocusLostConn;
|
||||
boost::signals2::connection mHelperCommitConn;
|
||||
std::function<void(LLWString)> mEmojiCommitCb;
|
||||
};
|
||||
|
|
@ -2699,7 +2699,7 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore
|
|||
|
||||
if (mFrontChildHandle.get() == child)
|
||||
{
|
||||
if (give_focus && !gFocusMgr.childHasKeyboardFocus(child))
|
||||
if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))
|
||||
{
|
||||
child->setFocus(TRUE);
|
||||
}
|
||||
|
|
@ -3373,7 +3373,34 @@ void LLFloaterView::syncFloaterTabOrder()
|
|||
LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);
|
||||
if (gFocusMgr.childHasKeyboardFocus(floaterp))
|
||||
{
|
||||
bringToFront(floaterp, FALSE);
|
||||
if (mFrontChildHandle.get() != floaterp)
|
||||
{
|
||||
// Grab a list of the top floaters that want to stay on top of the focused floater
|
||||
std::list<LLFloater*> listTop;
|
||||
if (mFrontChildHandle.get() && !mFrontChildHandle.get()->canFocusStealFrontmost())
|
||||
{
|
||||
for (LLView* childp : *getChildList())
|
||||
{
|
||||
LLFloater* child_floaterp = static_cast<LLFloater*>(childp);
|
||||
if (child_floaterp->canFocusStealFrontmost())
|
||||
break;
|
||||
listTop.push_back(child_floaterp);
|
||||
}
|
||||
}
|
||||
|
||||
bringToFront(floaterp, FALSE);
|
||||
|
||||
// Restore top floaters
|
||||
if (!listTop.empty())
|
||||
{
|
||||
for (LLView* childp : listTop)
|
||||
{
|
||||
sendChildToFront(childp);
|
||||
}
|
||||
mFrontChildHandle = listTop.back()->getHandle();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,6 +330,9 @@ public:
|
|||
/*virtual*/ void setVisible(BOOL visible); // do not override
|
||||
/*virtual*/ void onVisibilityChange ( BOOL new_visibility ); // do not override
|
||||
|
||||
bool canFocusStealFrontmost() const { return mFocusStealsFrontmost; }
|
||||
void setFocusStealsFrontmost(bool wants_frontmost) { mFocusStealsFrontmost = wants_frontmost; }
|
||||
|
||||
void setFrontmost(BOOL take_focus = TRUE, BOOL restore = TRUE);
|
||||
virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE, const LLSD& key = LLSD());
|
||||
|
||||
|
|
@ -510,6 +513,7 @@ private:
|
|||
BOOL mCanTearOff;
|
||||
BOOL mCanMinimize;
|
||||
BOOL mCanClose;
|
||||
bool mFocusStealsFrontmost = true; // FALSE if we don't want the currently focused floater to cover this floater without user interaction
|
||||
BOOL mDragOnLeft;
|
||||
BOOL mResizable;
|
||||
BOOL mCanSnooze; // <FS:Ansariel> FIRE-11724: Snooze group chat
|
||||
|
|
|
|||
|
|
@ -943,7 +943,7 @@ void LLFolderViewItem::drawLabel(const LLFontGL * font, const F32 x, const F32 y
|
|||
//
|
||||
font->renderUTF8(mLabel, 0, x, y, color,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, TRUE);
|
||||
S32_MAX, getRect().getWidth() - (S32) x - mLabelPaddingRight, &right_x, /*use_ellipses*/TRUE, /*use_color*/FALSE);
|
||||
}
|
||||
|
||||
void LLFolderViewItem::draw()
|
||||
|
|
@ -1023,7 +1023,7 @@ void LLFolderViewItem::draw()
|
|||
static const std::string locked_string = " (" + LLTrans::getString("LockedFolder") + ") ";
|
||||
font->renderUTF8(locked_string, 0, right_x, y, sProtectedColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE);
|
||||
S32_MAX, S32_MAX, &right_x, FALSE, FALSE);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
|
|
@ -1033,7 +1033,7 @@ void LLFolderViewItem::draw()
|
|||
static const std::string protected_string = " (" + LLTrans::getString("ProtectedFolder") + ") ";
|
||||
font->renderUTF8(protected_string, 0, right_x, y, sProtectedColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE);
|
||||
S32_MAX, S32_MAX, &right_x, FALSE, FALSE);
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
|
|
@ -1044,7 +1044,7 @@ void LLFolderViewItem::draw()
|
|||
{
|
||||
font->renderUTF8( mLabelSuffix, 0, right_x, y, isFadeItem() ? color : (LLColor4)sSuffixColor,
|
||||
LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, &right_x, FALSE );
|
||||
S32_MAX, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------//
|
||||
|
|
@ -1057,7 +1057,7 @@ void LLFolderViewItem::draw()
|
|||
F32 yy = (F32)getRect().getHeight() - font->getLineHeight() - (F32)mTextPad - (F32)TOP_PAD;
|
||||
font->renderUTF8( combined_string, filter_offset, match_string_left, yy,
|
||||
sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
filter_string_length, S32_MAX, &right_x, FALSE );
|
||||
filter_string_length, S32_MAX, &right_x, /*use_ellipses*/FALSE, /*use_color*/FALSE );
|
||||
}
|
||||
|
||||
//Gilbert Linden 9-20-2012: Although this should be legal, removing it because it causes the mLabelSuffix rendering to
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "lltextbase.h"
|
||||
|
||||
#include "llemojihelper.h"
|
||||
#include "lllocalcliprect.h"
|
||||
#include "llmenugl.h"
|
||||
#include "llscrollcontainer.h"
|
||||
|
|
@ -180,10 +181,12 @@ LLTextBase::Params::Params()
|
|||
line_spacing("line_spacing"),
|
||||
max_text_length("max_length", 255),
|
||||
font_shadow("font_shadow"),
|
||||
text_valign("text_valign"),
|
||||
wrap("wrap"),
|
||||
trusted_content("trusted_content", true),
|
||||
always_show_icons("always_show_icons", false),
|
||||
use_ellipses("use_ellipses", false),
|
||||
use_color("use_color", false),
|
||||
// <FS:Ansariel> Optional icon position
|
||||
icon_positioning("icon_positioning", LLTextBaseEnums::RIGHT),
|
||||
// </FS:Ansariel> Optional icon position
|
||||
|
|
@ -233,6 +236,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mVPad(p.v_pad),
|
||||
mHAlign(p.font_halign),
|
||||
mVAlign(p.font_valign),
|
||||
mTextVAlign(p.text_valign.isProvided() ? p.text_valign.getValue() : p.font_valign.getValue()),
|
||||
mLineSpacingMult(p.line_spacing.multiple),
|
||||
mLineSpacingPixels(p.line_spacing.pixels),
|
||||
mClip(p.clip),
|
||||
|
|
@ -247,6 +251,7 @@ LLTextBase::LLTextBase(const LLTextBase::Params &p)
|
|||
mPlainText ( p.plain_text ),
|
||||
mWordWrap(p.wrap),
|
||||
mUseEllipses( p.use_ellipses ),
|
||||
mUseColor(p.use_color),
|
||||
mParseHTML(p.parse_urls),
|
||||
mForceUrlsExternal(p.force_urls_external),
|
||||
mParseHighlights(p.parse_highlights),
|
||||
|
|
@ -719,7 +724,7 @@ void LLTextBase::drawCursor()
|
|||
fontp = segmentp->getStyle()->getFont();
|
||||
fontp->render(text, mCursorPos, cursor_rect,
|
||||
LLColor4(1.f - text_color.mV[VRED], 1.f - text_color.mV[VGREEN], 1.f - text_color.mV[VBLUE], alpha),
|
||||
LLFontGL::LEFT, mVAlign,
|
||||
LLFontGL::LEFT, mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
1);
|
||||
|
|
@ -1039,6 +1044,25 @@ S32 LLTextBase::insertStringNoUndo(S32 pos, const LLWString &wstr, LLTextBase::s
|
|||
}
|
||||
}
|
||||
|
||||
// Insert special segments where necessary (insertSegment takes care of splitting normal text segments around them for us)
|
||||
{
|
||||
LLStyleSP emoji_style;
|
||||
for (S32 text_kitty = 0, text_len = wstr.size(); text_kitty < text_len; text_kitty++)
|
||||
{
|
||||
if (LLStringOps::isEmoji(wstr[text_kitty]))
|
||||
{
|
||||
if (!emoji_style)
|
||||
{
|
||||
emoji_style = new LLStyle(getStyleParams());
|
||||
emoji_style->setFont(LLFontGL::getFontEmoji());
|
||||
}
|
||||
|
||||
S32 new_seg_start = pos + text_kitty;
|
||||
insertSegment(new LLEmojiTextSegment(emoji_style, new_seg_start, new_seg_start + 1, *this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getViewModel()->getEditableDisplay().insert(pos, wstr);
|
||||
|
||||
if ( truncate() )
|
||||
|
|
@ -2159,8 +2183,6 @@ LLTextBase::segment_set_t::iterator LLTextBase::getSegIterContaining(S32 index)
|
|||
text_len = mLabel.getWString().length();
|
||||
}
|
||||
|
||||
if (index > text_len) { return mSegments.end(); }
|
||||
|
||||
// when there are no segments, we return the end iterator, which must be checked by caller
|
||||
if (mSegments.size() <= 1) { return mSegments.begin(); }
|
||||
|
||||
|
|
@ -2185,8 +2207,6 @@ LLTextBase::segment_set_t::const_iterator LLTextBase::getSegIterContaining(S32 i
|
|||
text_len = mLabel.getWString().length();
|
||||
}
|
||||
|
||||
if (index > text_len) { return mSegments.end(); }
|
||||
|
||||
// when there are no segments, we return the end iterator, which must be checked by caller
|
||||
if (mSegments.size() <= 1) { return mSegments.begin(); }
|
||||
|
||||
|
|
@ -3664,12 +3684,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
|
|||
font->render(text, start,
|
||||
rect,
|
||||
color,
|
||||
LLFontGL::LEFT, mEditor.mVAlign,
|
||||
LLFontGL::LEFT, mEditor.mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
mStyle->getShadowType(),
|
||||
length,
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(),
|
||||
mEditor.getUseColor());
|
||||
}
|
||||
rect.mLeft = right_x;
|
||||
|
||||
|
|
@ -3683,12 +3704,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
|
|||
font->render(text, start,
|
||||
rect,
|
||||
mStyle->getSelectedColor().get(),
|
||||
LLFontGL::LEFT, mEditor.mVAlign,
|
||||
LLFontGL::LEFT, mEditor.mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
LLFontGL::NO_SHADOW,
|
||||
length,
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(),
|
||||
mEditor.getUseColor());
|
||||
}
|
||||
rect.mLeft = right_x;
|
||||
if( selection_end < seg_end )
|
||||
|
|
@ -3700,12 +3722,13 @@ F32 LLNormalTextSegment::drawClippedSegment(S32 seg_start, S32 seg_end, S32 sele
|
|||
font->render(text, start,
|
||||
rect,
|
||||
color,
|
||||
LLFontGL::LEFT, mEditor.mVAlign,
|
||||
LLFontGL::LEFT, mEditor.mTextVAlign,
|
||||
LLFontGL::NORMAL,
|
||||
mStyle->getShadowType(),
|
||||
length,
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(),
|
||||
mEditor.getUseColor());
|
||||
}
|
||||
return right_x;
|
||||
}
|
||||
|
|
@ -3949,6 +3972,33 @@ const S32 LLLabelTextSegment::getLength() const
|
|||
return mEditor.getWlabel().length();
|
||||
}
|
||||
|
||||
//
|
||||
// LLEmojiTextSegment
|
||||
//
|
||||
LLEmojiTextSegment::LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor)
|
||||
: LLNormalTextSegment(style, start, end, editor)
|
||||
{
|
||||
}
|
||||
|
||||
LLEmojiTextSegment::LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible)
|
||||
: LLNormalTextSegment(color, start, end, editor, is_visible)
|
||||
{
|
||||
}
|
||||
|
||||
BOOL LLEmojiTextSegment::handleToolTip(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
if (mTooltip.empty())
|
||||
{
|
||||
LLWString emoji = getWText().substr(getStart(), getEnd() - getStart());
|
||||
if (!emoji.empty())
|
||||
{
|
||||
mTooltip = LLEmojiHelper::instance().getToolTip(emoji[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return LLNormalTextSegment::handleToolTip(x, y, mask);
|
||||
}
|
||||
|
||||
//
|
||||
// LLOnHoverChangeableTextSegment
|
||||
//
|
||||
|
|
|
|||
|
|
@ -178,6 +178,18 @@ protected:
|
|||
/*virtual*/ const S32 getLength() const;
|
||||
};
|
||||
|
||||
// Text segment that represents a single emoji character that has a different style (=font size) than the rest of
|
||||
// the document it belongs to
|
||||
class LLEmojiTextSegment : public LLNormalTextSegment
|
||||
{
|
||||
public:
|
||||
LLEmojiTextSegment(LLStyleConstSP style, S32 start, S32 end, LLTextBase& editor);
|
||||
LLEmojiTextSegment(const LLColor4& color, S32 start, S32 end, LLTextBase& editor, BOOL is_visible = TRUE);
|
||||
|
||||
bool canEdit() const override { return false; }
|
||||
BOOL handleToolTip(S32 x, S32 y, MASK mask);
|
||||
};
|
||||
|
||||
// Text segment that changes it's style depending of mouse pointer position ( is it inside or outside segment)
|
||||
class LLOnHoverChangeableTextSegment : public LLNormalTextSegment
|
||||
{
|
||||
|
|
@ -340,6 +352,7 @@ public:
|
|||
plain_text,
|
||||
wrap,
|
||||
use_ellipses,
|
||||
use_color,
|
||||
parse_urls,
|
||||
force_urls_external,
|
||||
parse_highlights,
|
||||
|
|
@ -359,6 +372,8 @@ public:
|
|||
|
||||
Optional<LLFontGL::ShadowType> font_shadow;
|
||||
|
||||
Optional<LLFontGL::VAlign> text_valign;
|
||||
|
||||
// <FS:Ansariel> Optional icon position
|
||||
Optional<LLTextBaseEnums::EIconPositioning> icon_positioning;
|
||||
|
||||
|
|
@ -421,6 +436,7 @@ public:
|
|||
// used by LLTextSegment layout code
|
||||
bool getWordWrap() { return mWordWrap; }
|
||||
bool getUseEllipses() { return mUseEllipses; }
|
||||
bool getUseColor() { return mUseColor; }
|
||||
bool truncate(); // returns true of truncation occurred
|
||||
|
||||
bool isContentTrusted() {return mTrustedContent;}
|
||||
|
|
@ -745,8 +761,9 @@ protected:
|
|||
// configuration
|
||||
S32 mHPad; // padding on left of text
|
||||
S32 mVPad; // padding above text
|
||||
LLFontGL::HAlign mHAlign;
|
||||
LLFontGL::VAlign mVAlign;
|
||||
LLFontGL::HAlign mHAlign; // horizontal alignment of the document in its entirety
|
||||
LLFontGL::VAlign mVAlign; // vertical alignment of the document in its entirety
|
||||
LLFontGL::VAlign mTextVAlign; // vertical alignment of a text segment within a single line of text
|
||||
F32 mLineSpacingMult; // multiple of line height used as space for a single line of text (e.g. 1.5 to get 50% padding)
|
||||
S32 mLineSpacingPixels; // padding between lines
|
||||
bool mBorderVisible;
|
||||
|
|
@ -755,6 +772,7 @@ protected:
|
|||
bool mParseHighlights; // highlight user-defined keywords
|
||||
bool mWordWrap;
|
||||
bool mUseEllipses;
|
||||
bool mUseColor;
|
||||
bool mTrackEnd; // if true, keeps scroll position at end of document during resize
|
||||
bool mReadOnly;
|
||||
bool mBGVisible; // render background?
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include "llmath.h"
|
||||
|
||||
#include "llclipboard.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "llscrollbar.h"
|
||||
#include "llstl.h"
|
||||
#include "llstring.h"
|
||||
|
|
@ -238,6 +239,7 @@ LLTextEditor::Params::Params()
|
|||
default_color("default_color"),
|
||||
commit_on_focus_lost("commit_on_focus_lost", false),
|
||||
show_context_menu("show_context_menu"),
|
||||
show_emoji_helper("show_emoji_helper"),
|
||||
enable_tooltip_paste("enable_tooltip_paste"),
|
||||
enable_tab_remove("enable_tab_remove", true) // <FS:Ansariel> FIRE-15591: Optional tab remove
|
||||
{
|
||||
|
|
@ -260,6 +262,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
|
|||
mPrevalidateFunc(p.prevalidate_callback()),
|
||||
mContextMenu(NULL),
|
||||
mShowContextMenu(p.show_context_menu),
|
||||
mShowEmojiHelper(p.show_emoji_helper),
|
||||
mEnableTooltipPaste(p.enable_tooltip_paste),
|
||||
mPassDelete(FALSE),
|
||||
mKeepSelectionOnReturn(false),
|
||||
|
|
@ -551,6 +554,15 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out,
|
|||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::setShowEmojiHelper(bool show) {
|
||||
if (!mShowEmojiHelper)
|
||||
{
|
||||
LLEmojiHelper::instance().hideHelper(this);
|
||||
}
|
||||
|
||||
mShowEmojiHelper = show;
|
||||
}
|
||||
|
||||
BOOL LLTextEditor::selectionContainsLineBreaks()
|
||||
{
|
||||
if (hasSelection())
|
||||
|
|
@ -715,6 +727,21 @@ void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_p
|
|||
endSelection();
|
||||
}
|
||||
|
||||
void LLTextEditor::handleEmojiCommit(const LLWString& wstr)
|
||||
{
|
||||
LLWString wtext(getWText()); S32 shortCodePos;
|
||||
if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos))
|
||||
{
|
||||
remove(shortCodePos, mCursorPos - shortCodePos, true);
|
||||
|
||||
auto styleParams = LLStyle::Params();
|
||||
styleParams.font = LLFontGL::getFontEmoji();
|
||||
insert(shortCodePos, wstr, false, new LLEmojiTextSegment(new LLStyle(styleParams), shortCodePos, shortCodePos + wstr.size(), *this));
|
||||
|
||||
setCursorPos(shortCodePos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
BOOL handled = FALSE;
|
||||
|
|
@ -988,6 +1015,12 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
|
|||
|
||||
S32 LLTextEditor::execute( TextCmd* cmd )
|
||||
{
|
||||
if (!mReadOnly && mShowEmojiHelper)
|
||||
{
|
||||
// Any change to our contents should always hide the helper
|
||||
LLEmojiHelper::instance().hideHelper(this);
|
||||
}
|
||||
|
||||
S32 delta = 0;
|
||||
if( cmd->execute(this, &delta) )
|
||||
{
|
||||
|
|
@ -1214,6 +1247,17 @@ void LLTextEditor::addChar(llwchar wc)
|
|||
|
||||
setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
|
||||
|
||||
if (!mReadOnly && mShowEmojiHelper)
|
||||
{
|
||||
LLWString wtext(getWText()); S32 shortCodePos;
|
||||
if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos))
|
||||
{
|
||||
const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos - 1);
|
||||
const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos - shortCodePos);
|
||||
LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode), std::bind(&LLTextEditor::handleEmojiCommit, this, std::placeholders::_1));
|
||||
}
|
||||
}
|
||||
|
||||
if (!mReadOnly && mAutoreplaceCallback != NULL)
|
||||
{
|
||||
// autoreplace the text, if necessary
|
||||
|
|
@ -1956,6 +2000,11 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (mEnableTooltipPaste &&
|
||||
LLToolTipMgr::instance().toolTipVisible() &&
|
||||
KEY_TAB == key)
|
||||
|
|
@ -1997,6 +2046,12 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
|
|||
{
|
||||
resetCursorBlink();
|
||||
needsScroll();
|
||||
|
||||
if (mShowEmojiHelper)
|
||||
{
|
||||
// Dismiss the helper whenever we handled a key that it didn't
|
||||
LLEmojiHelper::instance().hideHelper(this);
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public:
|
|||
ignore_tab,
|
||||
commit_on_focus_lost,
|
||||
show_context_menu,
|
||||
show_emoji_helper,
|
||||
enable_tooltip_paste,
|
||||
enable_tab_remove, // <FS:Ansariel> FIRE-15591: Optional tab remove
|
||||
auto_indent;
|
||||
|
|
@ -92,6 +93,8 @@ public:
|
|||
|
||||
static S32 spacesPerTab();
|
||||
|
||||
void handleEmojiCommit(const LLWString& wstr);
|
||||
|
||||
// mousehandler overrides
|
||||
virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
|
||||
virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
|
||||
|
|
@ -212,6 +215,9 @@ public:
|
|||
void setShowContextMenu(bool show) { mShowContextMenu = show; }
|
||||
bool getShowContextMenu() const { return mShowContextMenu; }
|
||||
|
||||
void setShowEmojiHelper(bool show);
|
||||
bool getShowEmojiHelper() const { return mShowEmojiHelper; }
|
||||
|
||||
void setPassDelete(BOOL b) { mPassDelete = b; }
|
||||
|
||||
protected:
|
||||
|
|
@ -333,6 +339,7 @@ private:
|
|||
|
||||
BOOL mAllowEmbeddedItems;
|
||||
bool mShowContextMenu;
|
||||
bool mShowEmojiHelper;
|
||||
bool mEnableTooltipPaste;
|
||||
bool mPassDelete;
|
||||
bool mKeepSelectionOnReturn; // disabling of removing selected text after pressing of Enter
|
||||
|
|
|
|||
|
|
@ -1380,7 +1380,7 @@ void LLView::drawDebugRect()
|
|||
debug_rect.getWidth(), debug_rect.getHeight());
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(debug_text, 0, (F32)x, (F32)y, border_color,
|
||||
LLFontGL::HCENTER, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
|
||||
S32_MAX, S32_MAX, NULL, FALSE);
|
||||
S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
}
|
||||
}
|
||||
LLUI::popMatrix();
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ include(EXPAT)
|
|||
include(FMODSTUDIO)
|
||||
include(GLOD) # <FS:Beq/> restore GLOD
|
||||
include(Hunspell)
|
||||
include(ICU4C)
|
||||
include(JPEGEncoderBasic)
|
||||
include(JsonCpp)
|
||||
include(LLAppearance)
|
||||
|
|
@ -568,6 +569,7 @@ set(viewer_SOURCE_FILES
|
|||
llpaneleditsky.cpp
|
||||
llpaneleditwater.cpp
|
||||
llpaneleditwearable.cpp
|
||||
llpanelemojicomplete.cpp
|
||||
llpanelenvironment.cpp
|
||||
llpanelexperiencelisteditor.cpp
|
||||
llpanelexperiencelog.cpp
|
||||
|
|
@ -1341,6 +1343,7 @@ set(viewer_HEADER_FILES
|
|||
llpaneleditsky.h
|
||||
llpaneleditwater.h
|
||||
llpaneleditwearable.h
|
||||
llpanelemojicomplete.h
|
||||
llpanelenvironment.h
|
||||
llpanelexperiencelisteditor.h
|
||||
llpanelexperiencelog.h
|
||||
|
|
@ -1896,6 +1899,12 @@ if (WINDOWS)
|
|||
set(viewer_SOURCE_FILES "${viewer_SOURCE_FILES}" llviewerprecompiledheaders.cpp)
|
||||
endif(USE_PRECOMPILED_HEADERS)
|
||||
|
||||
message("Copying fonts")
|
||||
file(GLOB FONT_FILE_GLOB_LIST
|
||||
"${AUTOBUILD_INSTALL_DIR}/fonts/*"
|
||||
)
|
||||
file(COPY ${FONT_FILE_GLOB_LIST} DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/fonts")
|
||||
|
||||
# Replace the icons with the appropriate ones for the channel
|
||||
# ('test' is the default)
|
||||
set(ICON_PATH "private")
|
||||
|
|
@ -2513,6 +2522,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
|
|||
${NDOF_LIBRARY}
|
||||
${NVAPI_LIBRARY}
|
||||
${HUNSPELL_LIBRARY}
|
||||
${ICU4C_LIBRARY}
|
||||
${viewer_LIBRARIES}
|
||||
${BOOST_PROGRAM_OPTIONS_LIBRARY}
|
||||
${BOOST_REGEX_LIBRARY}
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
Bitstream Vera Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute the
|
||||
Font Software, including without limitation the rights to use, copy, merge,
|
||||
publish, distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice shall
|
||||
be included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional glyphs or characters may be added to the Fonts, only if the fonts
|
||||
are renamed to names not containing either the words "Bitstream" or the word
|
||||
"Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or Font
|
||||
Software that has been modified and is distributed under the "Bitstream
|
||||
Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but no
|
||||
copy of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
||||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
||||
FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font Software
|
||||
without prior written authorization from the Gnome Foundation or Bitstream
|
||||
Inc., respectively. For further information, contact: fonts at gnome dot
|
||||
org.
|
||||
|
||||
Arev Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and
|
||||
associated documentation files (the "Font Software"), to reproduce
|
||||
and distribute the modifications to the Bitstream Vera Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Tavmjong Bah" or the word "Arev".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Tavmjong Bah Arev" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Tavmjong Bah shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Font Software without prior written authorization
|
||||
from Tavmjong Bah. For further information, contact: tavmjong @ free
|
||||
. fr.
|
||||
|
||||
$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DejaVuSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>DejaVuSans-BoldOblique.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>CascadiaCode-Light.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>CascadiaCode-Light.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>CascadiaCode-Light.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>CelestiaMediumRedux1.55.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>CelestiaMediumRedux1.55.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DejaVuSansAllCaps.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -74,6 +75,11 @@
|
|||
<file>DejaVuSansAllCaps-BoldOblique.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansAllCapsMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DroidSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>DroidSerif-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DroidSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>MobiSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>opendyslexic-bolditalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>SourceCodePro-Regular.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>LiberationSans-Regular.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>LiberationSans-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>LiberationMono-Regular.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>MobiSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>MobiSans-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>MobiSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>NotoSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>NotoSans-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>NotoMono-Regular.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DroidSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>Roboto-BoldItalic.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>MobiSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>Ubuntu-R.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>meiryo.TTC</file>
|
||||
<file>YuGothR.ttc</file>
|
||||
|
|
@ -76,6 +77,11 @@
|
|||
<file>Ubuntu-MI.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>UbuntuMono-R.ttf</file>
|
||||
|
|
|
|||
|
|
@ -1257,6 +1257,8 @@ FSChatHistory::FSChatHistory(const FSChatHistory::Params& p)
|
|||
mUnreadChatSources(0)
|
||||
{
|
||||
mLineSpacingPixels = llclamp(gSavedSettings.getS32("FSFontChatLineSpacingPixels"), 0, 36);
|
||||
mTextVAlign = LLFontGL::VAlign::VCENTER;
|
||||
mUseColor = true;
|
||||
|
||||
setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1134,6 +1134,8 @@ LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)
|
|||
editor_params.enabled = false; // read only
|
||||
editor_params.show_context_menu = "true";
|
||||
editor_params.trusted_content = false;
|
||||
editor_params.text_valign = LLFontGL::VAlign::VCENTER;
|
||||
editor_params.use_color = true;
|
||||
mEditor = LLUICtrlFactory::create<LLTextEditor>(editor_params, this);
|
||||
mEditor->setIsFriendCallback(LLAvatarActions::isFriend);
|
||||
mEditor->setIsObjectBlockedCallback(boost::bind(&LLMuteList::isMuted, LLMuteList::getInstance(), _1, _2, 0));
|
||||
|
|
|
|||
|
|
@ -79,7 +79,9 @@ static S32 cube_channel = -1;
|
|||
static S32 diffuse_channel = -1;
|
||||
static S32 bump_channel = -1;
|
||||
|
||||
#define LL_BUMPLIST_MULTITHREADED 0 // TODO -- figure out why this doesn't work
|
||||
// Enabled after changing LLViewerTexture::mNeedsCreateTexture to an
|
||||
// LLAtomicBool; this should work just fine, now. HB
|
||||
#define LL_BUMPLIST_MULTITHREADED 1
|
||||
|
||||
|
||||
// static
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public:
|
|||
mStyle->getShadowType(),
|
||||
end - start, draw_rect.getWidth(),
|
||||
&right_x,
|
||||
mEditor.getUseEllipses());
|
||||
mEditor.getUseEllipses(), mEditor.getUseColor());
|
||||
return right_x;
|
||||
}
|
||||
/*virtual*/ bool canEdit() const { return false; }
|
||||
|
|
|
|||
|
|
@ -1632,7 +1632,7 @@ void LLOverlapPanel::draw()
|
|||
LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5
|
||||
LLView::sDrawPreviewHighlights = FALSE;
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1650,7 +1650,7 @@ void LLOverlapPanel::draw()
|
|||
std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)");
|
||||
S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10;
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
// widen panel enough to fit this text
|
||||
LLRect rect = getRect();
|
||||
setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop));
|
||||
|
|
@ -1716,7 +1716,7 @@ void LLOverlapPanel::draw()
|
|||
// draw currently-selected element at top of overlappers
|
||||
LLUI::translate(0,-mSpacing);
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height
|
||||
LLView::sPreviewClickedElement->draw();
|
||||
|
||||
|
|
@ -1731,7 +1731,7 @@ void LLOverlapPanel::draw()
|
|||
// draw name
|
||||
LLUI::translate(0,-mSpacing);
|
||||
LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color,
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
|
||||
// draw element
|
||||
LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent,
|
|||
LLUI::translate((F32) winX*1.0f/LLFontGL::sScaleX, (F32) winY*1.0f/(LLFontGL::sScaleY), -(((F32) winZ*2.f)-1.f));
|
||||
F32 right_x;
|
||||
|
||||
font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x);
|
||||
font.render(wstr, 0, 0, 1, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x, /*use_ellipses*/false, /*use_color*/true);
|
||||
|
||||
LLUI::popMatrix();
|
||||
gGL.popMatrix();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,321 @@
|
|||
/**
|
||||
* @file llpanelemojicomplete.h
|
||||
* @brief Header file for LLPanelEmojiComplete
|
||||
*
|
||||
* $LicenseInfo:firstyear=2012&license=lgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "llemojidictionary.h"
|
||||
#include "llemojihelper.h"
|
||||
#include "llpanelemojicomplete.h"
|
||||
#include "lluictrlfactory.h"
|
||||
|
||||
constexpr U32 MIN_MOUSE_MOVE_DELTA = 4;
|
||||
|
||||
// ============================================================================
|
||||
// LLPanelEmojiComplete
|
||||
//
|
||||
|
||||
static LLDefaultChildRegistry::Register<LLPanelEmojiComplete> r("emoji_complete");
|
||||
|
||||
LLPanelEmojiComplete::Params::Params()
|
||||
: autosize("autosize")
|
||||
, max_emoji("max_emoji")
|
||||
, padding("padding")
|
||||
, selected_image("selected_image")
|
||||
{
|
||||
}
|
||||
|
||||
LLPanelEmojiComplete::LLPanelEmojiComplete(const LLPanelEmojiComplete::Params& p)
|
||||
: LLUICtrl(p)
|
||||
, mAutoSize(p.autosize)
|
||||
, mMaxVisible(p.max_emoji)
|
||||
, mPadding(p.padding)
|
||||
, mSelectedImage(p.selected_image)
|
||||
{
|
||||
setFont(p.font);
|
||||
}
|
||||
|
||||
LLPanelEmojiComplete::~LLPanelEmojiComplete()
|
||||
{
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::draw()
|
||||
{
|
||||
if (!mEmojis.empty())
|
||||
{
|
||||
const S32 centerY = mRenderRect.getCenterY();
|
||||
const size_t firstVisibleIdx = mScrollPos, lastVisibleIdx = llmin(mScrollPos + mVisibleEmojis, mEmojis.size()) - 1;
|
||||
|
||||
if (mCurSelected >= firstVisibleIdx && mCurSelected <= lastVisibleIdx)
|
||||
{
|
||||
const S32 emoji_left = mRenderRect.mLeft + (mCurSelected - firstVisibleIdx) * mEmojiWidth;
|
||||
const S32 emoji_height = mFont->getLineHeight() + mPadding;
|
||||
mSelectedImage->draw(emoji_left, centerY - emoji_height / 2, mEmojiWidth, emoji_height);
|
||||
}
|
||||
|
||||
U32 left = mRenderRect.mLeft + mPadding;
|
||||
for (U32 curIdx = firstVisibleIdx; curIdx <= lastVisibleIdx; curIdx++)
|
||||
{
|
||||
mFont->render(
|
||||
mEmojis, curIdx,
|
||||
left, centerY,
|
||||
LLColor4::white, LLFontGL::LEFT, LLFontGL::VCENTER, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW_SOFT,
|
||||
1, S32_MAX, nullptr, false, true);
|
||||
left += mEmojiWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLPanelEmojiComplete::handleHover(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
LLVector2 curHover(x, y);
|
||||
if ((mLastHover - curHover).lengthSquared() > MIN_MOUSE_MOVE_DELTA)
|
||||
{
|
||||
mCurSelected = posToIndex(x, y);
|
||||
mLastHover = curHover;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLPanelEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
bool handled = false;
|
||||
if (MASK_NONE == mask)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KEY_LEFT:
|
||||
case KEY_UP:
|
||||
selectPrevious();
|
||||
handled = true;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
case KEY_DOWN:
|
||||
selectNext();
|
||||
handled = true;
|
||||
break;
|
||||
case KEY_RETURN:
|
||||
if (!mEmojis.empty())
|
||||
{
|
||||
onCommit();
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
return LLUICtrl::handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
BOOL LLPanelEmojiComplete::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mCurSelected = posToIndex(x, y);
|
||||
mLastHover = LLVector2(x, y);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL LLPanelEmojiComplete::handleMouseUp(S32 x, S32 y, MASK mask)
|
||||
{
|
||||
mCurSelected = posToIndex(x, y);
|
||||
onCommit();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::onCommit()
|
||||
{
|
||||
if (npos != mCurSelected)
|
||||
{
|
||||
LLWString wstr;
|
||||
wstr.push_back(mEmojis.at(mCurSelected));
|
||||
setValue(wstring_to_utf8str(wstr));
|
||||
LLUICtrl::onCommit();
|
||||
}
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
LLUICtrl::reshape(width, height, called_from_parent);
|
||||
updateConstraints();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::setEmojiHint(const std::string& hint)
|
||||
{
|
||||
llwchar curEmoji = (mCurSelected < mEmojis.size()) ? mEmojis.at(mCurSelected) : 0;
|
||||
|
||||
mEmojis = LLEmojiDictionary::instance().findMatchingEmojis(hint);
|
||||
size_t curEmojiIdx = (curEmoji) ? mEmojis.find(curEmoji) : std::string::npos;
|
||||
mCurSelected = (std::string::npos != curEmojiIdx) ? curEmojiIdx : 0;
|
||||
|
||||
if (mAutoSize)
|
||||
{
|
||||
mVisibleEmojis = (U16)std::min(mEmojis.size(), mMaxVisible);
|
||||
reshape(mVisibleEmojis * mEmojiWidth, getRect().getHeight(), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
updateConstraints();
|
||||
}
|
||||
|
||||
mScrollPos = llmin(mScrollPos, mEmojis.size());
|
||||
}
|
||||
|
||||
size_t LLPanelEmojiComplete::posToIndex(S32 x, S32 y) const
|
||||
{
|
||||
if (mRenderRect.pointInRect(x, y))
|
||||
{
|
||||
return mScrollPos + llmin((size_t)x / mEmojiWidth, mEmojis.size() - 1);
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::select(size_t emoji_idx)
|
||||
{
|
||||
mCurSelected = llclamp<size_t>(emoji_idx, 0, mEmojis.size());
|
||||
updateScrollPos();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::selectNext()
|
||||
{
|
||||
select(mCurSelected + 1 < mEmojis.size() ? mCurSelected + 1 : 0);
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::selectPrevious()
|
||||
{
|
||||
select(mCurSelected - 1 >= 0 ? mCurSelected - 1 : mEmojis.size() - 1);
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::setFont(const LLFontGL* fontp)
|
||||
{
|
||||
mFont = fontp;
|
||||
updateConstraints();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::updateConstraints()
|
||||
{
|
||||
const S32 ctrlWidth = getLocalRect().getWidth();
|
||||
|
||||
mEmojiWidth = mFont->getWidthF32(u8"\U0001F431") + mPadding * 2;
|
||||
mVisibleEmojis = ctrlWidth / mEmojiWidth;
|
||||
mRenderRect = getLocalRect().stretch((ctrlWidth - mVisibleEmojis * mEmojiWidth) / -2, 0);
|
||||
|
||||
updateScrollPos();
|
||||
}
|
||||
|
||||
void LLPanelEmojiComplete::updateScrollPos()
|
||||
{
|
||||
const size_t cntEmoji = mEmojis.size();
|
||||
if (0 == cntEmoji || cntEmoji < mVisibleEmojis || 0 == mCurSelected)
|
||||
{
|
||||
mScrollPos = 0;
|
||||
}
|
||||
else if (cntEmoji - 1 == mCurSelected)
|
||||
{
|
||||
mScrollPos = mCurSelected - mVisibleEmojis + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mScrollPos = mCurSelected - ((float)mCurSelected / (cntEmoji - 2) * (mVisibleEmojis - 2));
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// LLFloaterEmojiComplete
|
||||
//
|
||||
|
||||
LLFloaterEmojiComplete::LLFloaterEmojiComplete(const LLSD& sdKey)
|
||||
: LLFloater(sdKey)
|
||||
{
|
||||
// This floater should hover on top of our dependent (with the dependent having the focus)
|
||||
setFocusStealsFrontmost(false);
|
||||
setAutoFocus(false);
|
||||
setBackgroundVisible(false);
|
||||
setIsChrome(true);
|
||||
}
|
||||
|
||||
BOOL LLFloaterEmojiComplete::handleKey(KEY key, MASK mask, BOOL called_from_parent)
|
||||
{
|
||||
bool handled = false;
|
||||
if (MASK_NONE == mask)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case KEY_ESCAPE:
|
||||
LLEmojiHelper::instance().hideHelper();
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return TRUE;
|
||||
return LLFloater::handleKey(key, mask, called_from_parent);
|
||||
}
|
||||
|
||||
void LLFloaterEmojiComplete::onOpen(const LLSD& key)
|
||||
{
|
||||
mEmojiCtrl->setEmojiHint(key["hint"].asString());
|
||||
if (0 == mEmojiCtrl->getEmojiCount())
|
||||
{
|
||||
LLEmojiHelper::instance().hideHelper();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL LLFloaterEmojiComplete::postBuild()
|
||||
{
|
||||
mEmojiCtrl = findChild<LLPanelEmojiComplete>("emoji_complete_ctrl");
|
||||
mEmojiCtrl->setCommitCallback(
|
||||
std::bind([&](const LLSD& sdValue)
|
||||
{
|
||||
setValue(sdValue);
|
||||
onCommit();
|
||||
}, std::placeholders::_2));
|
||||
mEmojiCtrlHorz = getRect().getWidth() - mEmojiCtrl->getRect().getWidth();
|
||||
|
||||
return LLFloater::postBuild();
|
||||
}
|
||||
|
||||
void LLFloaterEmojiComplete::reshape(S32 width, S32 height, BOOL called_from_parent)
|
||||
{
|
||||
if (!called_from_parent)
|
||||
{
|
||||
LLRect rctFloater = getRect(), rctCtrl = mEmojiCtrl->getRect();
|
||||
rctFloater.mRight = rctFloater.mLeft + rctCtrl.getWidth() + mEmojiCtrlHorz;
|
||||
setRect(rctFloater);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
LLFloater::reshape(width, height, called_from_parent);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* @file llpanelemojicomplete.h
|
||||
* @brief Header file for LLPanelEmojiComplete
|
||||
*
|
||||
* $LicenseInfo:firstyear=2014&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "llfloater.h"
|
||||
#include "lluictrl.h"
|
||||
|
||||
// ============================================================================
|
||||
// LLPanelEmojiComplete
|
||||
//
|
||||
|
||||
class LLPanelEmojiComplete : public LLUICtrl
|
||||
{
|
||||
friend class LLUICtrlFactory;
|
||||
public:
|
||||
struct Params : public LLInitParam::Block<Params, LLUICtrl::Params>
|
||||
{
|
||||
Optional<bool> autosize;
|
||||
Optional<S32> max_emoji,
|
||||
padding;
|
||||
|
||||
Optional<LLUIImage*> selected_image;
|
||||
|
||||
Params();
|
||||
};
|
||||
|
||||
protected:
|
||||
LLPanelEmojiComplete(const LLPanelEmojiComplete::Params&);
|
||||
public:
|
||||
virtual ~LLPanelEmojiComplete();
|
||||
|
||||
void draw() override;
|
||||
BOOL handleHover(S32 x, S32 y, MASK mask) override;
|
||||
BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override;
|
||||
BOOL handleMouseDown(S32 x, S32 y, MASK mask) override;
|
||||
BOOL handleMouseUp(S32 x, S32 y, MASK mask) override;
|
||||
void onCommit() override;
|
||||
void reshape(S32 width, S32 height, BOOL called_from_parent) override;
|
||||
|
||||
public:
|
||||
size_t getEmojiCount() const { return mEmojis.size(); }
|
||||
void setEmojiHint(const std::string& hint);
|
||||
protected:
|
||||
size_t posToIndex(S32 x, S32 y) const;
|
||||
void select(size_t emoji_idx);
|
||||
void selectNext();
|
||||
void selectPrevious();
|
||||
void setFont(const LLFontGL* fontp);
|
||||
void updateConstraints();
|
||||
void updateScrollPos();
|
||||
|
||||
protected:
|
||||
static constexpr auto npos = std::numeric_limits<size_t>::max();
|
||||
|
||||
bool mAutoSize = false;
|
||||
const LLFontGL* mFont;
|
||||
U16 mEmojiWidth = 0;
|
||||
size_t mMaxVisible = 0;
|
||||
S32 mPadding = 8;
|
||||
LLRect mRenderRect;
|
||||
LLUIImagePtr mSelectedImage;
|
||||
|
||||
LLWString mEmojis;
|
||||
U16 mVisibleEmojis = 0;
|
||||
size_t mFirstVisible = 0;
|
||||
size_t mScrollPos = 0;
|
||||
size_t mCurSelected = 0;
|
||||
LLVector2 mLastHover;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// LLFloaterEmojiComplete
|
||||
//
|
||||
|
||||
class LLFloaterEmojiComplete : public LLFloater
|
||||
{
|
||||
public:
|
||||
LLFloaterEmojiComplete(const LLSD& sdKey);
|
||||
|
||||
public:
|
||||
BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent) override;
|
||||
void onOpen(const LLSD& key) override;
|
||||
BOOL postBuild() override;
|
||||
void reshape(S32 width, S32 height, BOOL called_from_parent) override;
|
||||
|
||||
protected:
|
||||
LLPanelEmojiComplete* mEmojiCtrl = nullptr;
|
||||
S32 mEmojiCtrlHorz = 0;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
|
@ -740,7 +740,7 @@ void LLGLTexMemBar::draw()
|
|||
LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3,
|
||||
text_color, LLFontGL::LEFT, LLFontGL::TOP,
|
||||
LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX,
|
||||
&x_right, FALSE);
|
||||
&x_right, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
|
||||
// <FS:Ansariel> Move BW figures further to the right to prevent overlapping
|
||||
left = 575;
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@
|
|||
// <FS:Ansariel> [FS communication UI]
|
||||
#include "llpanelblockedlist.h"
|
||||
#include "llpanelprofileclassifieds.h"
|
||||
#include "llpanelemojicomplete.h"
|
||||
#include "llpreviewanim.h"
|
||||
#include "llpreviewgesture.h"
|
||||
#include "llpreviewnotecard.h"
|
||||
|
|
@ -315,6 +316,7 @@ void LLViewerFloaterReg::registerFloaters()
|
|||
LLFloaterReg::add("delete_pref_preset", "floater_delete_pref_preset.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDeletePrefPreset>);
|
||||
LLFloaterReg::add("destinations", "floater_destinations.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterDestinations>);
|
||||
|
||||
LLFloaterReg::add("emoji_complete", "floater_emoji_complete.xml", &LLFloaterReg::build<LLFloaterEmojiComplete>);
|
||||
LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPostProcess>);
|
||||
|
||||
LLFloaterReg::add("env_fixed_environmentent_water", "floater_fixedenvironment.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFixedEnvironmentWater>);
|
||||
|
|
|
|||
|
|
@ -12373,6 +12373,10 @@ void initialize_menus()
|
|||
//Develop (clear cache immediately)
|
||||
commit.add("Develop.ClearCache", boost::bind(&handle_cache_clear_immediately) );
|
||||
|
||||
// Develop (Fonts debugging)
|
||||
commit.add("Develop.Fonts.Dump", boost::bind(&LLFontGL::dumpFonts));
|
||||
commit.add("Develop.Fonts.DumpTextures", boost::bind(&LLFontGL::dumpFontTextures));
|
||||
|
||||
// <FS:Beq/> Add telemetry controls to the viewer Develop menu (Toggle profiling)
|
||||
view_listener_t::addMenu(new FSProfilerToggle(), "Develop.ToggleProfiling");
|
||||
view_listener_t::addMenu(new FSProfilerCheckEnabled(), "Develop.EnableProfiling");
|
||||
|
|
|
|||
|
|
@ -1191,7 +1191,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
|
|||
mLoadedCallbackDesiredDiscardLevel = S8_MAX;
|
||||
mPauseLoadedCallBacks = FALSE;
|
||||
|
||||
mNeedsCreateTexture = FALSE;
|
||||
mNeedsCreateTexture = false;
|
||||
|
||||
mIsRawImageValid = FALSE;
|
||||
mRawDiscardLevel = INVALID_DISCARD_LEVEL;
|
||||
|
|
@ -1478,12 +1478,12 @@ void LLViewerFetchedTexture::addToCreateTexture()
|
|||
{
|
||||
//just update some variables, not to create a real GL texture.
|
||||
createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE);
|
||||
mNeedsCreateTexture = FALSE;
|
||||
mNeedsCreateTexture = false;
|
||||
destroyRawImage();
|
||||
}
|
||||
else if(!force_update && getDiscardLevel() > -1 && getDiscardLevel() <= mRawDiscardLevel)
|
||||
{
|
||||
mNeedsCreateTexture = FALSE;
|
||||
mNeedsCreateTexture = false;
|
||||
destroyRawImage();
|
||||
}
|
||||
else
|
||||
|
|
@ -1519,7 +1519,7 @@ void LLViewerFetchedTexture::addToCreateTexture()
|
|||
mRawDiscardLevel += i;
|
||||
if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)
|
||||
{
|
||||
mNeedsCreateTexture = FALSE;
|
||||
mNeedsCreateTexture = false;
|
||||
destroyRawImage();
|
||||
return;
|
||||
}
|
||||
|
|
@ -1551,7 +1551,7 @@ BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/)
|
|||
destroyRawImage();
|
||||
return FALSE;
|
||||
}
|
||||
mNeedsCreateTexture = FALSE;
|
||||
mNeedsCreateTexture = false;
|
||||
|
||||
if (mRawImage.isNull())
|
||||
{
|
||||
|
|
@ -1723,14 +1723,14 @@ void LLViewerFetchedTexture::postCreateTexture()
|
|||
destroyRawImage();
|
||||
}
|
||||
|
||||
mNeedsCreateTexture = FALSE;
|
||||
mNeedsCreateTexture = false;
|
||||
}
|
||||
|
||||
void LLViewerFetchedTexture::scheduleCreateTexture()
|
||||
{
|
||||
if (!mNeedsCreateTexture)
|
||||
{
|
||||
mNeedsCreateTexture = TRUE;
|
||||
mNeedsCreateTexture = true;
|
||||
if (preCreateTexture())
|
||||
{
|
||||
#if LL_IMAGEGL_THREAD_CHECK
|
||||
|
|
@ -1744,7 +1744,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
|
|||
memcpy(data_copy, data, size);
|
||||
}
|
||||
#endif
|
||||
mNeedsCreateTexture = TRUE;
|
||||
mNeedsCreateTexture = true;
|
||||
auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
|
||||
if (mainq)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#ifndef LL_LLVIEWERTEXTURE_H
|
||||
#define LL_LLVIEWERTEXTURE_H
|
||||
|
||||
#include "llatomic.h"
|
||||
#include "llgltexture.h"
|
||||
#include "lltimer.h"
|
||||
#include "llframetimer.h"
|
||||
|
|
@ -571,7 +572,9 @@ protected:
|
|||
LLFrameTimer mStopFetchingTimer; // Time since mDecodePriority == 0.f.
|
||||
|
||||
BOOL mInImageList; // TRUE if image is in list (in which case don't reset priority!)
|
||||
BOOL mNeedsCreateTexture;
|
||||
// This needs to be atomic, since it is written both in the main thread
|
||||
// and in the GL image worker thread... HB
|
||||
LLAtomicBool mNeedsCreateTexture;
|
||||
|
||||
BOOL mForSculpt ; //a flag if the texture is used as sculpt data.
|
||||
BOOL mIsFetched ; //is loaded from remote or from cache, not generated locally.
|
||||
|
|
|
|||
|
|
@ -1108,7 +1108,7 @@ public:
|
|||
const Line& line = *iter;
|
||||
LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
|
||||
LLFontGL::LEFT, LLFontGL::TOP,
|
||||
LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
|
||||
LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, /*use_ellipses*/FALSE, /*use_color*/FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -639,7 +639,8 @@ void LLWorldMapView::draw()
|
|||
S32_MAX, //max_chars
|
||||
mMapScale, //max_pixels
|
||||
NULL,
|
||||
TRUE); //use ellipses
|
||||
/*use_ellipses*/TRUE,
|
||||
/*use_color*/FALSE);
|
||||
|
||||
if (drawAdvancedRegionInfo)
|
||||
{
|
||||
|
|
@ -670,7 +671,8 @@ void LLWorldMapView::draw()
|
|||
S32_MAX, //max_chars
|
||||
mMapScale, //max_pixels
|
||||
NULL,
|
||||
TRUE); //use ellipses
|
||||
TRUE, //use ellipses
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
// <FS:CR> Show the grid coordinates (in units of regions)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<floater
|
||||
can_close="false"
|
||||
can_dock="false"
|
||||
can_drag_on_left="false"
|
||||
can_minimize="false"
|
||||
can_resize="false"
|
||||
can_tear_off="false"
|
||||
header_height="0"
|
||||
layout="topleft"
|
||||
legacy_header_height="0"
|
||||
height="40"
|
||||
single_instance="true"
|
||||
width="240"
|
||||
>
|
||||
<emoji_complete
|
||||
autosize="true"
|
||||
height="30"
|
||||
follows="top|left"
|
||||
layout="topleft"
|
||||
left="5"
|
||||
max_emoji="7"
|
||||
name="emoji_complete_ctrl"
|
||||
top="5"
|
||||
width="230"
|
||||
>
|
||||
</emoji_complete>
|
||||
</floater>
|
||||
|
|
@ -80,6 +80,8 @@
|
|||
spellcheck="true"
|
||||
tab_group="1"
|
||||
top="46"
|
||||
use_color="true"
|
||||
show_emoji_helper="true"
|
||||
width="392"
|
||||
word_wrap="true">
|
||||
Loading...
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
<font name="default" comment="default font files (global fallbacks)">
|
||||
<file>DejaVuSans.ttf</file>
|
||||
<file functor="is_emoji">TwemojiSVG.ttf</file>
|
||||
<os name="Windows">
|
||||
<file>MSNeoGothic.ttf</file>
|
||||
<file>meiryo.TTC</file>
|
||||
|
|
@ -69,6 +70,11 @@
|
|||
<file>DejaVuSans-BoldOblique.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Emoji"
|
||||
comment="Name of emoji font">
|
||||
<file>TwemojiSVG.ttf</file>
|
||||
</font>
|
||||
|
||||
<font name="Monospace"
|
||||
comment="Name of monospace font">
|
||||
<file>DejaVuSansMono.ttf</file>
|
||||
|
|
|
|||
|
|
@ -193,6 +193,32 @@
|
|||
parameter="ui_preview" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator />
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
label="Fonts"
|
||||
name="Fonts"
|
||||
tear_off="true">
|
||||
<menu_item_call
|
||||
label="Show Font Test"
|
||||
name="Show Font Test">
|
||||
<menu_item_call.on_click
|
||||
function="Floater.Show"
|
||||
parameter="font_test" />
|
||||
</menu_item_call>
|
||||
<menu_item_separator />
|
||||
<menu_item_call
|
||||
label="Dump Fonts"
|
||||
name="Dump Fonts">
|
||||
<menu_item_call.on_click
|
||||
function="Develop.Fonts.Dump" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Dump Font Textures"
|
||||
name="Dump Font Textures">
|
||||
<menu_item_call.on_click
|
||||
function="Develop.Fonts.DumpTextures" />
|
||||
</menu_item_call>
|
||||
</menu>
|
||||
<menu
|
||||
create_jump_keys="true"
|
||||
label="UI Tests"
|
||||
|
|
|
|||
|
|
@ -4807,6 +4807,18 @@
|
|||
function="Advanced.WebContentTest"
|
||||
parameter="https://cryptic-ridge-1632.herokuapp.com/"/>
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Dump Fonts"
|
||||
name="Dump Fonts">
|
||||
<menu_item_call.on_click
|
||||
function="Develop.Fonts.Dump" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Dump Font Textures"
|
||||
name="Dump Font Textures">
|
||||
<menu_item_call.on_click
|
||||
function="Develop.Fonts.DumpTextures" />
|
||||
</menu_item_call>
|
||||
<menu_item_call
|
||||
label="Dump SelectMgr"
|
||||
name="Dump SelectMgr">
|
||||
|
|
|
|||
|
|
@ -2,4 +2,6 @@
|
|||
<chat_editor
|
||||
name="chat_editor"
|
||||
enable_tab_remove="false"
|
||||
show_context_menu="true"/>
|
||||
show_emoji_helper="true"
|
||||
use_color="true"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
|
||||
<emoji_complete
|
||||
autosize="false"
|
||||
font="EmojiHuge"
|
||||
hover_image="ListItem_Over"
|
||||
max_emoji="7"
|
||||
padding="8"
|
||||
selected_image="ListItem_Select"
|
||||
>
|
||||
</emoji_complete>
|
||||
|
|
@ -176,7 +176,7 @@ class ViewerManifest(LLManifest,FSViewerManifest):
|
|||
self.path("*.tga")
|
||||
|
||||
# Include our fonts
|
||||
with self.prefix(src_dst="fonts"):
|
||||
with self.prefix(src="../packages/fonts",src_dst="fonts"):
|
||||
self.path("*.ttf")
|
||||
self.path("*.txt")
|
||||
self.path("*.xml")
|
||||
|
|
|
|||
Loading…
Reference in New Issue