mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Several crashes fixes for HTML loading.
This commit is contained in:
@@ -274,6 +274,12 @@ class EE_API FontTrueType : public Font {
|
||||
bool setFontFace( void* face );
|
||||
|
||||
void updateMonospaceState() const;
|
||||
|
||||
void disconnectBoldFont();
|
||||
|
||||
void disconnectItalicFont();
|
||||
|
||||
void disconnectBoldItalicFont();
|
||||
};
|
||||
|
||||
}} // namespace EE::Graphics
|
||||
|
||||
@@ -105,8 +105,6 @@ Font* FontManager::getByInternalId( Uint32 internalId ) const {
|
||||
}
|
||||
|
||||
FontTrueType* FontManager::getOrLoadSystemFallbackFont( const FontDesc& desc ) {
|
||||
static constexpr Uint32 MAX_SYSTEM_FALLBACK_FONTS = 32;
|
||||
|
||||
if ( desc.path.empty() )
|
||||
return nullptr;
|
||||
|
||||
@@ -126,12 +124,6 @@ FontTrueType* FontManager::getOrLoadSystemFallbackFont( const FontDesc& desc ) {
|
||||
|
||||
mSystemFallbackFonts.push_back( ttf );
|
||||
|
||||
if ( mSystemFallbackFonts.size() > MAX_SYSTEM_FALLBACK_FONTS ) {
|
||||
Font* oldest = mSystemFallbackFonts.front();
|
||||
mSystemFallbackFonts.erase( mSystemFallbackFonts.begin() );
|
||||
eeSAFE_DELETE( oldest );
|
||||
}
|
||||
|
||||
return ttf;
|
||||
}
|
||||
|
||||
|
||||
@@ -359,10 +359,12 @@ bool FontTrueType::loadFromFile( const std::string& filename, Uint32 faceIndex )
|
||||
|
||||
// Load the new font face from the specified file
|
||||
FT_Face face;
|
||||
if ( FT_New_Face( static_cast<FT_Library>( mLibrary ), filename.c_str(),
|
||||
static_cast<FT_Long>( mFaceIndex ), &face ) != 0 ) {
|
||||
Log::error( "Failed to load font \"%s\" (%s) (failed to create the font face)",
|
||||
filename.c_str(), mFontName.c_str() );
|
||||
FT_Error err = FT_New_Face( static_cast<FT_Library>( mLibrary ), filename.c_str(),
|
||||
static_cast<FT_Long>( mFaceIndex ), &face );
|
||||
if ( err != 0 ) {
|
||||
const char* err_str = FT_Error_String( err );
|
||||
Log::error( "Failed to load font \"%s\" (%s, face index %zu) - %s (code %d)", filename,
|
||||
mFontName, mFaceIndex, err_str ? err_str : "Unknown error", err );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -397,11 +399,14 @@ bool FontTrueType::loadFromMemory( const void* data, std::size_t sizeInBytes, bo
|
||||
|
||||
// Load the new font face from the specified file
|
||||
FT_Face face;
|
||||
if ( FT_New_Memory_Face( static_cast<FT_Library>( mLibrary ),
|
||||
reinterpret_cast<const FT_Byte*>( ptr ),
|
||||
static_cast<FT_Long>( sizeInBytes ),
|
||||
static_cast<FT_Long>( mFaceIndex ), &face ) != 0 ) {
|
||||
Log::error( "Failed to load font from memory (failed to create the font face)" );
|
||||
FT_Error err = FT_New_Memory_Face(
|
||||
static_cast<FT_Library>( mLibrary ), reinterpret_cast<const FT_Byte*>( ptr ),
|
||||
static_cast<FT_Long>( sizeInBytes ), static_cast<FT_Long>( mFaceIndex ), &face );
|
||||
if ( err != 0 ) {
|
||||
const char* err_str = FT_Error_String( err );
|
||||
Log::error( "Failed to load font from memory (failed to create the font face, face index "
|
||||
"%zu): %s (code %d)",
|
||||
mFaceIndex, err_str ? err_str : "Unknown error", err );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1071,20 +1076,9 @@ void FontTrueType::cleanup() {
|
||||
if ( FontManager::existsSingleton() && FontManager::instance()->getColorEmojiFont() == this )
|
||||
FontManager::instance()->setColorEmojiFont( nullptr );
|
||||
|
||||
if ( mFontBoldItalicCb != 0 && mFontBoldItalic != nullptr ) {
|
||||
mFontBoldItalic->popFontEventCallback( mFontBoldItalicCb );
|
||||
mFontBoldItalicCb = 0;
|
||||
}
|
||||
|
||||
if ( mFontBoldCb != 0 && mFontBold != nullptr ) {
|
||||
mFontBold->popFontEventCallback( mFontBoldCb );
|
||||
mFontBoldCb = 0;
|
||||
}
|
||||
|
||||
if ( mFontItalicCb != 0 && mFontItalic != nullptr ) {
|
||||
mFontItalic->popFontEventCallback( mFontItalicCb );
|
||||
mFontItalicCb = 0;
|
||||
}
|
||||
disconnectBoldItalicFont();
|
||||
disconnectBoldFont();
|
||||
disconnectItalicFont();
|
||||
|
||||
mCallbacks.clear();
|
||||
mNumCallBacks = 0;
|
||||
@@ -1772,6 +1766,7 @@ void FontTrueType::updateMonospaceState() const {
|
||||
void FontTrueType::setBoldFont( FontTrueType* fontBold ) {
|
||||
if ( fontBold == mFontBold )
|
||||
return;
|
||||
disconnectBoldFont();
|
||||
mFontBold = fontBold;
|
||||
if ( mFontBold != nullptr ) {
|
||||
mFontBoldCb = mFontBold->pushFontEventCallback( [this]( Uint32, Event event, Font* ) {
|
||||
@@ -1788,6 +1783,7 @@ void FontTrueType::setBoldFont( FontTrueType* fontBold ) {
|
||||
void FontTrueType::setItalicFont( FontTrueType* fontItalic ) {
|
||||
if ( fontItalic == mFontItalic )
|
||||
return;
|
||||
disconnectItalicFont();
|
||||
mFontItalic = fontItalic;
|
||||
if ( mFontItalic != nullptr ) {
|
||||
mFontItalicCb = mFontItalic->pushFontEventCallback( [this]( Uint32, Event event, Font* ) {
|
||||
@@ -1804,6 +1800,7 @@ void FontTrueType::setItalicFont( FontTrueType* fontItalic ) {
|
||||
void FontTrueType::setBoldItalicFont( FontTrueType* fontBoldItalic ) {
|
||||
if ( fontBoldItalic == mFontBoldItalic )
|
||||
return;
|
||||
disconnectBoldItalicFont();
|
||||
mFontBoldItalic = fontBoldItalic;
|
||||
if ( mFontBoldItalic != nullptr ) {
|
||||
mFontBoldItalicCb =
|
||||
@@ -1818,6 +1815,27 @@ void FontTrueType::setBoldItalicFont( FontTrueType* fontBoldItalic ) {
|
||||
updateMonospaceState();
|
||||
}
|
||||
|
||||
void FontTrueType::disconnectBoldFont() {
|
||||
if ( mFontBoldCb != 0 && mFontBold != nullptr )
|
||||
mFontBold->popFontEventCallback( mFontBoldCb );
|
||||
mFontBold = nullptr;
|
||||
mFontBoldCb = 0;
|
||||
}
|
||||
|
||||
void FontTrueType::disconnectItalicFont() {
|
||||
if ( mFontItalicCb != 0 && mFontItalic != nullptr )
|
||||
mFontItalic->popFontEventCallback( mFontItalicCb );
|
||||
mFontItalic = nullptr;
|
||||
mFontItalicCb = 0;
|
||||
}
|
||||
|
||||
void FontTrueType::disconnectBoldItalicFont() {
|
||||
if ( mFontBoldItalicCb != 0 && mFontBoldItalic != nullptr )
|
||||
mFontBoldItalic->popFontEventCallback( mFontBoldItalicCb );
|
||||
mFontBoldItalic = nullptr;
|
||||
mFontBoldItalicCb = 0;
|
||||
}
|
||||
|
||||
bool FontTrueType::hasSvgGlyphs() const {
|
||||
return mHasSvgGlyphs;
|
||||
}
|
||||
|
||||
@@ -1320,6 +1320,11 @@ void Image::copyImage( Graphics::Image* image, const Uint32& x, const Uint32& y
|
||||
}
|
||||
|
||||
void Image::resize( const Uint32& newWidth, const Uint32& newHeight, ResamplerFilter filter ) {
|
||||
if ( newWidth == 0 || newHeight == 0 ) {
|
||||
Log::warning( "Image::resize: Invalid resize %dx%d", newWidth, newHeight ) ;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( NULL != mPixels && ( mWidth != newWidth || mHeight != newHeight ) ) {
|
||||
unsigned char* resampled =
|
||||
resample_image( mPixels, mWidth, mHeight, mChannels, newWidth, newHeight, filter );
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <eepp/network/http.hpp>
|
||||
#include <eepp/network/http/httpstreamchunked.hpp>
|
||||
#include <eepp/network/ssl/sslsocket.hpp>
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <eepp/system/iostreamfile.hpp>
|
||||
#include <eepp/system/iostreaminflate.hpp>
|
||||
#include <eepp/system/iostreamstring.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
#include <eepp/system/sys.hpp>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
@@ -661,6 +663,11 @@ Uint64 Http::requestAsync( const Http::AsyncResponseCallback& cb, const URI& uri
|
||||
const Http::Request::FieldTable& headers, const std::string& body,
|
||||
const bool& validateCertificate, const URI& proxy,
|
||||
bool followRedirect ) {
|
||||
if ( Log::existsSingleton() && Log::instance()->getLogLevelThreshold() == LogLevel::Debug ) {
|
||||
Log::debug( "Http::requestAsync: %s \"%s\"", Request::methodToString( method ),
|
||||
uri.toString() );
|
||||
}
|
||||
|
||||
auto http = sGlobalHttpPool.get( uri, proxy );
|
||||
Request request( uri.getPathAndQuery(), method, body, validateCertificate, validateCertificate,
|
||||
true, true );
|
||||
@@ -978,8 +985,6 @@ Http::Response Http::downloadRequest( const Http::Request& request, IOStream& wr
|
||||
std::size_t currentTotalBytes = 0;
|
||||
std::size_t len = 0;
|
||||
std::size_t read = 0;
|
||||
char* eol = NULL; // end of line
|
||||
char* bol = NULL; // beginning of line
|
||||
char buffer[PACKET_BUFFER_SIZE + 1];
|
||||
bool isnheader = false;
|
||||
bool chunked = false;
|
||||
@@ -998,173 +1003,147 @@ Http::Response Http::downloadRequest( const Http::Request& request, IOStream& wr
|
||||
// If we didn't receive the header yet, we will try to find the end of the
|
||||
// header
|
||||
if ( !isnheader ) {
|
||||
// calculate combined length of unprocessed data and new data
|
||||
len += read;
|
||||
headerBuffer.append( readBuffer, read );
|
||||
|
||||
// NULL terminate buffer for string functions
|
||||
readBuffer[len] = '\0';
|
||||
std::size_t headerEnd = headerBuffer.find( "\r\n\r\n" );
|
||||
std::size_t headerDelimiterSize = 4;
|
||||
|
||||
// process each line in buffer looking for header break
|
||||
bol = readBuffer;
|
||||
if ( headerEnd == std::string::npos ) {
|
||||
headerEnd = headerBuffer.find( "\n\n" );
|
||||
headerDelimiterSize = 2;
|
||||
}
|
||||
|
||||
while ( !isnheader && ( eol = strchr( bol, '\n' ) ) != NULL ) {
|
||||
// update bol based upon the value of eol
|
||||
bol = eol + 1;
|
||||
if ( headerEnd != std::string::npos ) {
|
||||
isnheader = true;
|
||||
headerEnd += headerDelimiterSize;
|
||||
len = headerBuffer.size() - headerEnd;
|
||||
|
||||
// test if end of headers has been reached
|
||||
if ( 0 == strncmp( bol, "\r\n", 2 ) || 0 == strncmp( bol, "\n", 1 ) ) {
|
||||
// note that end of headers has been reached
|
||||
isnheader = true;
|
||||
std::string responseHead( headerBuffer, 0, headerEnd );
|
||||
|
||||
// update the value of bol to reflect the beginning of the line
|
||||
// immediately after the headers
|
||||
if ( bol[0] != '\n' )
|
||||
bol += 1;
|
||||
if ( !responseHead.empty() ) {
|
||||
// Build the Response object from the received data
|
||||
received.parse( responseHead );
|
||||
|
||||
bol += 1;
|
||||
// Check if the response is chunked
|
||||
chunked = received.getField( "transfer-encoding" ) == "chunked";
|
||||
|
||||
// calculate the amount of data remaining in the buffer
|
||||
len = read - ( bol - readBuffer );
|
||||
// Check if the content is compressed
|
||||
std::string encoding( received.getField( "content-encoding" ) );
|
||||
compressed =
|
||||
encoding == "gzip" || encoding == "deflate" || encoding == "br";
|
||||
|
||||
// Fill the header buffer
|
||||
headerBuffer.append( readBuffer, ( bol - readBuffer ) );
|
||||
if ( compressed ) {
|
||||
Compression::Mode compressionMode =
|
||||
"gzip" == encoding
|
||||
? Compression::MODE_GZIP
|
||||
: ( "br" == encoding ? Compression::MODE_BROTLI
|
||||
: Compression::MODE_DEFLATE );
|
||||
|
||||
if ( !headerBuffer.empty() ) {
|
||||
// Build the Response object from the received data
|
||||
received.parse( headerBuffer );
|
||||
inflateStream =
|
||||
IOStreamInflate::New( writeTo, compressionMode );
|
||||
}
|
||||
|
||||
// Check if the response is chunked
|
||||
chunked = received.getField( "transfer-encoding" ) == "chunked";
|
||||
if ( chunked ) {
|
||||
IOStream& writeToStream = compressed ? *inflateStream : writeTo;
|
||||
chunkedStream = eeNew( HttpStreamChunked, ( writeToStream ) );
|
||||
}
|
||||
|
||||
// Check if the content is compressed
|
||||
std::string encoding( received.getField( "content-encoding" ) );
|
||||
compressed = encoding == "gzip" || encoding == "deflate" ||
|
||||
encoding == "br";
|
||||
|
||||
if ( compressed ) {
|
||||
Compression::Mode compressionMode =
|
||||
"gzip" == encoding
|
||||
? Compression::MODE_GZIP
|
||||
: ( "br" == encoding ? Compression::MODE_BROTLI
|
||||
: Compression::MODE_DEFLATE );
|
||||
|
||||
inflateStream =
|
||||
IOStreamInflate::New( writeTo, compressionMode );
|
||||
}
|
||||
|
||||
if ( chunked ) {
|
||||
IOStream& writeToStream =
|
||||
compressed ? *inflateStream : writeTo;
|
||||
chunkedStream =
|
||||
eeNew( HttpStreamChunked, ( writeToStream ) );
|
||||
}
|
||||
|
||||
bufferStream = chunked
|
||||
? chunkedStream
|
||||
bufferStream = chunked ? chunkedStream
|
||||
: ( compressed ? inflateStream : &writeTo );
|
||||
|
||||
// Get the content length
|
||||
if ( !received.getField( "content-length" ).empty() ) {
|
||||
if ( !String::fromString(
|
||||
contentLength,
|
||||
received.getField( "content-length" ) ) )
|
||||
contentLength = 0;
|
||||
}
|
||||
// Get the content length
|
||||
if ( !received.getField( "content-length" ).empty() ) {
|
||||
if ( !String::fromString(
|
||||
contentLength,
|
||||
received.getField( "content-length" ) ) )
|
||||
contentLength = 0;
|
||||
}
|
||||
|
||||
if ( mConnection &&
|
||||
received.getField( "connection" ) == "closed" ) {
|
||||
mConnection->setConnected( false );
|
||||
mConnection->setTunneled( false );
|
||||
}
|
||||
if ( mConnection &&
|
||||
received.getField( "connection" ) == "closed" ) {
|
||||
mConnection->setConnected( false );
|
||||
mConnection->setTunneled( false );
|
||||
}
|
||||
|
||||
// If a redirection is requested, and requests follows
|
||||
// redirections, send a new request to the redirection location.
|
||||
if ( ( received.getStatus() == Response::MovedPermanently ||
|
||||
received.getStatus() == Response::MovedTemporarily ||
|
||||
received.getStatus() == Response::PermanentRedirect ||
|
||||
received.getStatus() == Response::TemporaryRedirect ) &&
|
||||
request.getFollowRedirect() ) {
|
||||
// If a redirection is requested, and requests follows
|
||||
// redirections, send a new request to the redirection location.
|
||||
if ( ( received.getStatus() == Response::MovedPermanently ||
|
||||
received.getStatus() == Response::MovedTemporarily ||
|
||||
received.getStatus() == Response::PermanentRedirect ||
|
||||
received.getStatus() == Response::TemporaryRedirect ) &&
|
||||
request.getFollowRedirect() ) {
|
||||
|
||||
// Only continue redirecting if less than 10 redirections
|
||||
// were done
|
||||
if ( request.mRedirectionCount <
|
||||
request.getMaxRedirects() ) {
|
||||
std::string location( received.getField( "location" ) );
|
||||
URI uri( location );
|
||||
// Only continue redirecting if less than 10 redirections
|
||||
// were done
|
||||
if ( request.mRedirectionCount < request.getMaxRedirects() ) {
|
||||
std::string location( received.getField( "location" ) );
|
||||
URI uri( location );
|
||||
|
||||
// Close the connection
|
||||
if ( mConnection && !mConnection->isKeepAlive() )
|
||||
mConnection->disconnect();
|
||||
// Close the connection
|
||||
if ( mConnection && !mConnection->isKeepAlive() )
|
||||
mConnection->disconnect();
|
||||
|
||||
eeSAFE_DELETE( chunkedStream );
|
||||
eeSAFE_DELETE( inflateStream );
|
||||
eeSAFE_DELETE( chunkedStream );
|
||||
eeSAFE_DELETE( inflateStream );
|
||||
|
||||
if ( !request.isCancelled() &&
|
||||
!sendProgress( *this, request, received,
|
||||
Request::Redirect, contentLength,
|
||||
currentTotalBytes ) ) {
|
||||
request.mCancel = true;
|
||||
if ( !request.isCancelled() &&
|
||||
!sendProgress( *this, request, received,
|
||||
Request::Redirect, contentLength,
|
||||
currentTotalBytes ) ) {
|
||||
request.mCancel = true;
|
||||
} else {
|
||||
Http::Request newRequest( request );
|
||||
newRequest.setUri( uri.getPathAndQuery() );
|
||||
newRequest.setMethod(
|
||||
Http::Request::getRedirectMethodFromStatus(
|
||||
request.getMethod(), received.getStatus() ) );
|
||||
|
||||
newRequest.setProgressCallback(
|
||||
request.getProgressCallback() );
|
||||
|
||||
if ( received.hasField( "set-cookie" ) ) {
|
||||
newRequest.setField(
|
||||
"Cookie", received.getField( "set-cookie" ) );
|
||||
}
|
||||
|
||||
request.mRedirectionCount++;
|
||||
newRequest.mRedirectionCount =
|
||||
request.mRedirectionCount;
|
||||
|
||||
// Same host, expects a path in the same domain
|
||||
if ( uri.getHost().empty() ||
|
||||
uri.getHost() == getHostName() ) {
|
||||
return downloadRequest( newRequest, writeTo,
|
||||
timeout );
|
||||
} else {
|
||||
Http::Request newRequest( request );
|
||||
newRequest.setUri( uri.getPathAndQuery() );
|
||||
newRequest.setMethod(
|
||||
Http::Request::getRedirectMethodFromStatus(
|
||||
request.getMethod(),
|
||||
received.getStatus() ) );
|
||||
|
||||
newRequest.setProgressCallback(
|
||||
request.getProgressCallback() );
|
||||
|
||||
if ( received.hasField( "set-cookie" ) ) {
|
||||
newRequest.setField(
|
||||
"Cookie",
|
||||
received.getField( "set-cookie" ) );
|
||||
}
|
||||
|
||||
request.mRedirectionCount++;
|
||||
newRequest.mRedirectionCount =
|
||||
request.mRedirectionCount;
|
||||
|
||||
// Same host, expects a path in the same domain
|
||||
if ( uri.getHost().empty() ||
|
||||
uri.getHost() == getHostName() ) {
|
||||
return downloadRequest( newRequest, writeTo,
|
||||
timeout );
|
||||
} else {
|
||||
// New host, we need to solve the host
|
||||
Http http( uri.getHost(), uri.getPort(),
|
||||
uri.getScheme() == "https" ? true
|
||||
: false );
|
||||
return http.downloadRequest( newRequest,
|
||||
writeTo, timeout );
|
||||
}
|
||||
// New host, we need to solve the host
|
||||
Http http( uri.getHost(), uri.getPort(),
|
||||
uri.getScheme() == "https" ? true
|
||||
: false );
|
||||
return http.downloadRequest( newRequest, writeTo,
|
||||
timeout );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !request.isCancelled() &&
|
||||
!sendProgress( *this, request, received,
|
||||
Request::HeaderReceived, contentLength,
|
||||
0 ) ) {
|
||||
request.mCancel = true;
|
||||
}
|
||||
|
||||
// Move the readBuffer to the starting point
|
||||
// of the file buffer
|
||||
if ( len > 0 ) {
|
||||
readBuffer = bol;
|
||||
read = len;
|
||||
} else {
|
||||
read = 0;
|
||||
}
|
||||
|
||||
headerBuffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isnheader ) {
|
||||
headerBuffer.append( readBuffer, ( bol - readBuffer ) );
|
||||
if ( !request.isCancelled() &&
|
||||
!sendProgress( *this, request, received,
|
||||
Request::HeaderReceived, contentLength, 0 ) ) {
|
||||
request.mCancel = true;
|
||||
}
|
||||
|
||||
// Move the response body bytes already read into the socket buffer.
|
||||
if ( len > 0 ) {
|
||||
std::memmove( buffer, headerBuffer.data() + headerEnd, len );
|
||||
readBuffer = buffer;
|
||||
read = len;
|
||||
} else {
|
||||
read = 0;
|
||||
}
|
||||
|
||||
headerBuffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning( \
|
||||
disable : 4127 ) // "conditional expression is constant" generated by the FD_SET macro
|
||||
#pragma warning( disable \
|
||||
: 4127 ) // "conditional expression is constant" generated by the FD_SET macro
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
@@ -129,6 +129,13 @@ Socket::Status TcpSocket::connect( const IpAddress& remoteAddress, unsigned shor
|
||||
|
||||
// Otherwise, wait until something happens to our socket (success, timeout or error)
|
||||
if ( status == Socket::NotReady ) {
|
||||
if ( getHandle() >= FD_SETSIZE ) {
|
||||
// The socket FD is too large for select().
|
||||
// You cannot safely use FD_SET.
|
||||
setBlocking( true );
|
||||
return Error;
|
||||
}
|
||||
|
||||
// Setup the selector
|
||||
fd_set selector;
|
||||
FD_ZERO( &selector );
|
||||
|
||||
@@ -484,6 +484,8 @@ Uint32 UIRichText::getFontSize() const {
|
||||
|
||||
UIRichText* UIRichText::setFontSize( const Uint32& characterSize ) {
|
||||
if ( mRichText.getFontStyleConfig().CharacterSize != characterSize ) {
|
||||
if ( characterSize == 0 )
|
||||
return this;
|
||||
mRichText.getFontStyleConfig().CharacterSize = characterSize;
|
||||
mRichText.invalidate();
|
||||
mLineHeightPxDirty = true;
|
||||
@@ -745,6 +747,12 @@ void UIRichText::loadFromXmlNode( const pugi::xml_node& node ) {
|
||||
} else {
|
||||
// Let parent logic load standard child widget
|
||||
UIWidget* uiwidget = UIWidgetCreator::createFromName( child.name() );
|
||||
|
||||
// For not known elements it should create an HTMLUnknown element, in practice
|
||||
// an span with a the tag name used is enough
|
||||
if ( uiwidget == nullptr )
|
||||
uiwidget = UITextSpan::NewWithTag( child.name() );
|
||||
|
||||
if ( uiwidget ) {
|
||||
uiwidget->setParent( this );
|
||||
uiwidget->loadFromXmlNode( child );
|
||||
|
||||
@@ -1190,9 +1190,11 @@ void UISceneNode::loadFontFaces( const StyleSheetStyleVector& styles, URI baseUR
|
||||
Base64::decode( data, decoded );
|
||||
FontTrueType* font = FontTrueType::New( familyName );
|
||||
if ( font->loadFromMemory( &decoded[0], decoded.size() ) ) {
|
||||
trySetFontFamily( fontFamily, fontStyle, font );
|
||||
mFontFaces.push_back( font );
|
||||
runOnMainThread( [this] { mRoot->reloadFontFamily(); } );
|
||||
runOnMainThread( [this, trySetFontFamily, fontFamily, fontStyle, font] {
|
||||
trySetFontFamily( fontFamily, fontStyle, font );
|
||||
mFontFaces.push_back( font );
|
||||
mRoot->reloadFontFamily();
|
||||
} );
|
||||
} else
|
||||
eeSAFE_DELETE( font );
|
||||
}
|
||||
@@ -1517,18 +1519,38 @@ Font* UISceneNode::getFontFromNamesList( std::string_view names, Uint32 fontStyl
|
||||
name = String::trim( name, ' ' );
|
||||
name = String::trim( name, '\'' );
|
||||
name = String::trim( name, '"' );
|
||||
|
||||
std::string fontFamily{ name };
|
||||
size_t size = fontFamily.size();
|
||||
if ( fontStyle )
|
||||
fontFamily += "#" + Text::styleFlagToString( fontStyle );
|
||||
|
||||
font = FontManager::instance()->getByName( fontFamily );
|
||||
|
||||
if ( fontStyle )
|
||||
fontFamily.resize( size );
|
||||
|
||||
if ( font == nullptr &&
|
||||
SystemFontResolver::genericFamilyFromName( fontFamily ) != GenericFamily::None ) {
|
||||
FontQuery query;
|
||||
query.family = fontFamily;
|
||||
query.italic = fontStyle & Text::Italic;
|
||||
query.weight = ( fontStyle & Text::Bold ) ? FontWeight::Bold : FontWeight::Normal;
|
||||
fontFamily = SystemFontResolver::instance()->resolve( query ).family;
|
||||
|
||||
if ( fontStyle )
|
||||
fontFamily += "#" + Text::styleFlagToString( fontStyle );
|
||||
|
||||
font = FontManager::instance()->getByName( fontFamily );
|
||||
}
|
||||
|
||||
return font != nullptr;
|
||||
},
|
||||
',' );
|
||||
|
||||
if ( !font && Graphics::SystemFontResolver::isEnabled() ) {
|
||||
Graphics::FontWeight weight =
|
||||
( fontStyle & Text::Bold ) ? Graphics::FontWeight::Bold : Graphics::FontWeight::Normal;
|
||||
Graphics::FontDesc desc = Graphics::SystemFontResolver::instance()->resolveFromNamesList(
|
||||
if ( font == nullptr && SystemFontResolver::isEnabled() ) {
|
||||
FontWeight weight = ( fontStyle & Text::Bold ) ? FontWeight::Bold : FontWeight::Normal;
|
||||
FontDesc desc = SystemFontResolver::instance()->resolveFromNamesList(
|
||||
std::string{ names }, weight, fontStyle & Text::Italic );
|
||||
if ( !desc.path.empty() ) {
|
||||
std::string family = desc.family;
|
||||
@@ -1559,7 +1581,7 @@ Font* UISceneNode::getFontFromNamesList( std::string_view names, Uint32 fontStyl
|
||||
}
|
||||
|
||||
Font* UISceneNode::reevaluateFontStyle( Font* currentFont, Uint32 fontStyle ) const {
|
||||
if ( !currentFont || !Graphics::SystemFontResolver::isEnabled() )
|
||||
if ( !currentFont || !SystemFontResolver::isEnabled() )
|
||||
return nullptr;
|
||||
|
||||
if ( currentFont->getType() != FontType::TTF )
|
||||
@@ -1579,7 +1601,7 @@ Font* UISceneNode::reevaluateFontStyle( Font* currentFont, Uint32 fontStyle ) co
|
||||
}
|
||||
|
||||
void UISceneNode::loadFontStyleVariants( Font* font, const std::string& family ) const {
|
||||
if ( !font || !Graphics::SystemFontResolver::isEnabled() )
|
||||
if ( !font || !SystemFontResolver::isEnabled() )
|
||||
return;
|
||||
if ( font->getType() != FontType::TTF )
|
||||
return;
|
||||
|
||||
@@ -231,6 +231,8 @@ Uint32 UITextSpan::getFontSize() const {
|
||||
|
||||
UITextSpan* UITextSpan::setFontSize( const Uint32& characterSize ) {
|
||||
if ( mRichText.getFontStyleConfig().CharacterSize != characterSize ) {
|
||||
if ( characterSize == 0 )
|
||||
return this;
|
||||
mRichText.getFontStyleConfig().CharacterSize = characterSize;
|
||||
mStyleState |= StyleStateFontSize;
|
||||
mRichText.invalidate();
|
||||
@@ -414,6 +416,10 @@ void UITextSpan::loadFromXmlNode( const pugi::xml_node& node ) {
|
||||
for ( pugi::xml_node child = node.first_child(); child; child = child.next_sibling() ) {
|
||||
if ( child.type() == pugi::node_element ) {
|
||||
UIWidget* widget = UIWidgetCreator::createFromName( child.name() );
|
||||
|
||||
if ( widget == nullptr )
|
||||
widget = UITextSpan::NewWithTag( child.name() );
|
||||
|
||||
if ( widget ) {
|
||||
widget->setParent( this );
|
||||
widget->loadFromXmlNode( child );
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
#include <iostream>
|
||||
|
||||
EE_MAIN_FUNC int main( int argc, char** argv ) {
|
||||
std::shared_ptr<ThreadPool> threadPool(
|
||||
ThreadPool::createShared( eemax<int>( 4, Sys::getCPUCount() ) ) );
|
||||
Http::setThreadPool( threadPool );
|
||||
SystemFontResolver::setEnabled( true );
|
||||
|
||||
args::ArgumentParser parser( "eepp HTML Example" );
|
||||
args::HelpFlag help( parser, "help", "Display this help menu", { 'h', "help" } );
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "utest.h"
|
||||
|
||||
#include <eepp/network/http.hpp>
|
||||
#include <eepp/network/cookiemanager.hpp>
|
||||
|
||||
using namespace EE;
|
||||
|
||||
@@ -34,6 +34,36 @@ using namespace EE::Graphics;
|
||||
using namespace EE::Window;
|
||||
using namespace EE::UI;
|
||||
|
||||
UTEST( FontRendering, relatedFontsDisconnectReplacedCallbacks ) {
|
||||
FontTrueType* font = FontTrueType::New( "RelatedFontsDisconnect-Regular" );
|
||||
FontTrueType* oldBold = FontTrueType::New( "RelatedFontsDisconnect-OldBold" );
|
||||
FontTrueType* newBold = FontTrueType::New( "RelatedFontsDisconnect-NewBold" );
|
||||
FontTrueType* oldItalic = FontTrueType::New( "RelatedFontsDisconnect-OldItalic" );
|
||||
FontTrueType* newItalic = FontTrueType::New( "RelatedFontsDisconnect-NewItalic" );
|
||||
FontTrueType* oldBoldItalic = FontTrueType::New( "RelatedFontsDisconnect-OldBoldItalic" );
|
||||
FontTrueType* newBoldItalic = FontTrueType::New( "RelatedFontsDisconnect-NewBoldItalic" );
|
||||
|
||||
font->setBoldFont( oldBold );
|
||||
font->setBoldFont( newBold );
|
||||
eeDelete( oldBold );
|
||||
EXPECT_EQ( newBold, font->getBoldFont() );
|
||||
|
||||
font->setItalicFont( oldItalic );
|
||||
font->setItalicFont( newItalic );
|
||||
eeDelete( oldItalic );
|
||||
EXPECT_EQ( newItalic, font->getItalicFont() );
|
||||
|
||||
font->setBoldItalicFont( oldBoldItalic );
|
||||
font->setBoldItalicFont( newBoldItalic );
|
||||
eeDelete( oldBoldItalic );
|
||||
EXPECT_EQ( newBoldItalic, font->getBoldItalicFont() );
|
||||
|
||||
eeDelete( font );
|
||||
eeDelete( newBold );
|
||||
eeDelete( newItalic );
|
||||
eeDelete( newBoldItalic );
|
||||
}
|
||||
|
||||
UTEST( FontRendering, fontsTest ) {
|
||||
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
||||
|
||||
|
||||
38
src/tests/unit_tests/http.cpp
Normal file
38
src/tests/unit_tests/http.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "utest.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include <eepp/network/http.hpp>
|
||||
#include <eepp/network/tcplistener.hpp>
|
||||
#include <eepp/network/tcpsocket.hpp>
|
||||
|
||||
using namespace EE;
|
||||
using namespace EE::Network;
|
||||
|
||||
UTEST( Http, responseHeaderLineLargerThanReceiveBuffer ) {
|
||||
TcpListener listener;
|
||||
ASSERT_EQ( listener.listen( Socket::AnyPort, IpAddress::LocalHost ), Socket::Done );
|
||||
|
||||
std::atomic<bool> serverOk{ false };
|
||||
std::thread server( [&listener, &serverOk] {
|
||||
TcpSocket client;
|
||||
if ( listener.accept( client ) != Socket::Done )
|
||||
return;
|
||||
|
||||
const std::string response = "HTTP/1.1 200 OK\r\nX-Long: " + std::string( 17000, 'a' ) +
|
||||
"\r\nContent-Length: 5\r\nConnection: close\r\n\r\nhello";
|
||||
serverOk = client.send( response.data(), response.size() ) == Socket::Done;
|
||||
client.disconnect();
|
||||
} );
|
||||
|
||||
Http http( "127.0.0.1", listener.getLocalPort() );
|
||||
Http::Response response = http.sendRequest( Http::Request( "/" ), Seconds( 5 ) );
|
||||
|
||||
server.join();
|
||||
listener.close();
|
||||
|
||||
EXPECT_TRUE( serverOk );
|
||||
EXPECT_EQ( response.getStatus(), Http::Response::Ok );
|
||||
EXPECT_TRUE( response.getBody() == "hello" );
|
||||
}
|
||||
@@ -131,6 +131,11 @@ UTEST( UIHTMLTable, complexLayout2 ) {
|
||||
|
||||
win->getInput()->update();
|
||||
SceneManager::instance()->update();
|
||||
SceneManager::instance()->update();
|
||||
|
||||
win->clear();
|
||||
SceneManager::instance()->draw();
|
||||
win->display();
|
||||
|
||||
win->clear();
|
||||
SceneManager::instance()->draw();
|
||||
|
||||
Reference in New Issue
Block a user