/*
This file is part of Magnum .
Copyright © 2010 , 2011 , 2012 , 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019 ,
2020 , 2021 , 2022 , 2023 Vladimír Vondruš < mosra @ centrum . cz >
Permission is hereby granted , free of charge , to any person obtaining a
copy of this software and associated documentation files ( the " Software " ) ,
to deal in the Software without restriction , including without limitation
the rights to use , copy , modify , merge , publish , distribute , sublicense ,
and / or sell copies of the Software , and to permit persons to whom the
Software is furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE .
*/
# include <sstream>
# include <tuple>
# include <Corrade/Containers/ArrayViewStl.h> /**< @todo drop once std::vector is gone */
# include <Corrade/Containers/StringStl.h> /**< @todo drop once Debug is stream-free */
# include <Corrade/TestSuite/Tester.h>
# include <Corrade/TestSuite/Compare/Container.h>
# include <Corrade/TestSuite/Compare/String.h>
# include <Corrade/Utility/DebugStl.h> /**< @todo drop once Debug is stream-free */
# include "Magnum/Image.h"
# include "Magnum/ImageView.h"
# include "Magnum/PixelFormat.h"
# include "Magnum/Text/AbstractGlyphCache.h"
namespace Magnum { namespace Text { namespace Test { namespace {
struct AbstractGlyphCacheTest : TestSuite : : Tester {
explicit AbstractGlyphCacheTest ( ) ;
void initialize ( ) ;
void access ( ) ;
void reserve ( ) ;
void reserveIncremental ( ) ;
void reserveTooSmall ( ) ;
void setImage ( ) ;
void setImageOutOfRange ( ) ;
void image ( ) ;
void imageNotSupported ( ) ;
void imageNotImplemented ( ) ;
} ;
AbstractGlyphCacheTest : : AbstractGlyphCacheTest ( ) {
addTests ( { & AbstractGlyphCacheTest : : initialize ,
& AbstractGlyphCacheTest : : access ,
& AbstractGlyphCacheTest : : reserve ,
& AbstractGlyphCacheTest : : reserveIncremental ,
& AbstractGlyphCacheTest : : reserveTooSmall ,
& AbstractGlyphCacheTest : : setImage ,
& AbstractGlyphCacheTest : : setImageOutOfRange ,
& AbstractGlyphCacheTest : : image ,
& AbstractGlyphCacheTest : : imageNotSupported ,
& AbstractGlyphCacheTest : : imageNotImplemented } ) ;
}
struct DummyGlyphCache : AbstractGlyphCache {
using AbstractGlyphCache : : AbstractGlyphCache ;
GlyphCacheFeatures doFeatures ( ) const override { return { } ; }
void doSetImage ( const Vector2i & , const ImageView2D & ) override { }
} ;
void AbstractGlyphCacheTest : : initialize ( ) {
DummyGlyphCache cache { { 1024 , 2048 } } ;
CORRADE_COMPARE ( cache . textureSize ( ) , ( Vector2i { 1024 , 2048 } ) ) ;
}
void AbstractGlyphCacheTest : : access ( ) {
DummyGlyphCache cache { Vector2i ( 236 ) } ;
Vector2i position ;
Range2Di rectangle ;
/* Default "Not Found" glyph */
CORRADE_COMPARE ( cache . glyphCount ( ) , 1 ) ;
std : : tie ( position , rectangle ) = cache [ 0 ] ;
CORRADE_COMPARE ( position , Vector2i ( 0 , 0 ) ) ;
CORRADE_COMPARE ( rectangle , Range2Di ( { 0 , 0 } , { 0 , 0 } ) ) ;
/* Overwrite the "Not Found" glyph */
cache . insert ( 0 , { 3 , 5 } , { { 10 , 10 } , { 23 , 45 } } ) ;
CORRADE_COMPARE ( cache . glyphCount ( ) , 1 ) ;
std : : tie ( position , rectangle ) = cache [ 0 ] ;
CORRADE_COMPARE ( position , Vector2i ( 3 , 5 ) ) ;
CORRADE_COMPARE ( rectangle , Range2Di ( { 10 , 10 } , { 23 , 45 } ) ) ;
/* Querying available glyph */
cache . insert ( 25 , { 3 , 4 } , { { 15 , 30 } , { 45 , 35 } } ) ;
CORRADE_COMPARE ( cache . glyphCount ( ) , 2 ) ;
std : : tie ( position , rectangle ) = cache [ 25 ] ;
CORRADE_COMPARE ( position , Vector2i ( 3 , 4 ) ) ;
CORRADE_COMPARE ( rectangle , Range2Di ( { 15 , 30 } , { 45 , 35 } ) ) ;
/* Querying not available glyph falls back to "Not Found" */
std : : tie ( position , rectangle ) = cache [ 42 ] ;
CORRADE_COMPARE ( position , Vector2i ( 3 , 5 ) ) ;
CORRADE_COMPARE ( rectangle , Range2Di ( { 10 , 10 } , { 23 , 45 } ) ) ;
}
void AbstractGlyphCacheTest : : reserve ( ) {
DummyGlyphCache cache { { 29 , 20 } , { 1 , 2 } } ;
std : : vector < Range2Di > out = cache . reserve ( { { 5 , 3 } , { 12 , 6 } , { 10 , 5 } } ) ;
CORRADE_COMPARE_AS ( Containers : : arrayView ( out ) , Containers : : arrayView < Range2Di > ( {
Range2Di : : fromSize ( { 1 , 2 } , { 5 , 3 } ) ,
Range2Di : : fromSize ( { 15 , 2 } , { 12 , 6 } ) ,
Range2Di : : fromSize ( { 1 , 12 } , { 10 , 5 } ) ,
} ) , TestSuite : : Compare : : Container ) ;
}
void AbstractGlyphCacheTest : : reserveIncremental ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
DummyGlyphCache cache { { 25 , 12 } } ;
/* insert() is what triggers the assert, not reserve() alone */
cache . insert ( 0 , { 3 , 5 } , { { 10 , 10 } , { 23 , 45 } } ) ;
std : : ostringstream out ;
Error redirectError { & out } ;
cache . reserve ( { { 12 , 6 } } ) ;
CORRADE_COMPARE ( out . str ( ) , " Text::AbstractGlyphCache::reserve(): reserving space in non-empty cache is not yet implemented \n " ) ;
}
void AbstractGlyphCacheTest : : reserveTooSmall ( ) {
DummyGlyphCache cache { { 20 , 12 } } ;
std : : ostringstream out ;
Error redirectError { & out } ;
CORRADE_VERIFY ( cache . reserve ( { { 5 , 3 } , { 12 , 6 } , { 10 , 5 } } ) . empty ( ) ) ;
CORRADE_COMPARE ( out . str ( ) , " TextureTools::atlas(): requested atlas size Vector(20, 12) is too small to fit 3 Vector(12, 6) textures. Generated atlas will be empty. \n " ) ;
}
void AbstractGlyphCacheTest : : setImage ( ) {
struct : AbstractGlyphCache {
using AbstractGlyphCache : : AbstractGlyphCache ;
GlyphCacheFeatures doFeatures ( ) const override { return { } ; }
void doSetImage ( const Vector2i & offset , const ImageView2D & image ) override {
imageOffset = offset ;
imageSize = image . size ( ) ;
}
Vector2i imageOffset , imageSize ;
} cache { { 100 , 200 } } ;
cache . setImage ( { 80 , 175 } , ImageView2D { PixelFormat : : R8Unorm , { 20 , 25 } } ) ;
CORRADE_COMPARE ( cache . imageOffset , ( Vector2i { 80 , 175 } ) ) ;
CORRADE_COMPARE ( cache . imageSize , ( Vector2i { 20 , 25 } ) ) ;
}
void AbstractGlyphCacheTest : : setImageOutOfRange ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
DummyGlyphCache cache { { 100 , 200 } } ;
/* This is fine */
cache . setImage ( { 80 , 175 } , ImageView2D { PixelFormat : : R8Unorm , { 20 , 25 } } ) ;
std : : ostringstream out ;
Error redirectError { & out } ;
cache . setImage ( { 81 , 175 } , ImageView2D { PixelFormat : : R8Unorm , { 20 , 25 } } ) ;
cache . setImage ( { 80 , 176 } , ImageView2D { PixelFormat : : R8Unorm , { 20 , 25 } } ) ;
cache . setImage ( { - 1 , 175 } , ImageView2D { PixelFormat : : R8Unorm , { 20 , 25 } } ) ;
cache . setImage ( { 80 , - 1 } , ImageView2D { PixelFormat : : R8Unorm , { 20 , 25 } } ) ;
CORRADE_COMPARE_AS ( out . str ( ) ,
" Text::AbstractGlyphCache::setImage(): Range({81, 175}, {101, 200}) out of range for texture size Vector(100, 200) \n "
" Text::AbstractGlyphCache::setImage(): Range({80, 176}, {100, 201}) out of range for texture size Vector(100, 200) \n "
" Text::AbstractGlyphCache::setImage(): Range({-1, 175}, {19, 200}) out of range for texture size Vector(100, 200) \n "
" Text::AbstractGlyphCache::setImage(): Range({80, -1}, {100, 24}) out of range for texture size Vector(100, 200) \n " ,
TestSuite : : Compare : : String ) ;
}
void AbstractGlyphCacheTest : : image ( ) {
struct : AbstractGlyphCache {
using AbstractGlyphCache : : AbstractGlyphCache ;
GlyphCacheFeatures doFeatures ( ) const override { return GlyphCacheFeature : : ImageDownload ; }
void doSetImage ( const Vector2i & , const ImageView2D & ) override { }
Image2D doImage ( ) override { return Image2D { PixelFormat : : RG8Unorm } ; }
} cache { { 200 , 300 } } ;
Image2D image = cache . image ( ) ;
CORRADE_COMPARE ( image . format ( ) , PixelFormat : : RG8Unorm ) ;
}
void AbstractGlyphCacheTest : : imageNotSupported ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
struct : AbstractGlyphCache {
using AbstractGlyphCache : : AbstractGlyphCache ;
GlyphCacheFeatures doFeatures ( ) const override { return { } ; }
void doSetImage ( const Vector2i & , const ImageView2D & ) override { }
} cache { { 200 , 300 } } ;
std : : ostringstream out ;
Error redirectError { & out } ;
cache . image ( ) ;
CORRADE_COMPARE ( out . str ( ) , " Text::AbstractGlyphCache::image(): feature not supported \n " ) ;
}
void AbstractGlyphCacheTest : : imageNotImplemented ( ) {
CORRADE_SKIP_IF_NO_ASSERT ( ) ;
struct : AbstractGlyphCache {
using AbstractGlyphCache : : AbstractGlyphCache ;
GlyphCacheFeatures doFeatures ( ) const override { return GlyphCacheFeature : : ImageDownload ; }
void doSetImage ( const Vector2i & , const ImageView2D & ) override { }
} cache { { 200 , 300 } } ;
std : : ostringstream out ;
Error redirectError { & out } ;
cache . image ( ) ;
CORRADE_COMPARE ( out . str ( ) , " Text::AbstractGlyphCache::image(): feature advertised but not implemented \n " ) ;
}
} } } }
CORRADE_TEST_MAIN ( Magnum : : Text : : Test : : AbstractGlyphCacheTest )