2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/event/text/atlas/glyph-atlas-manager.h>
22 #include <dali/internal/event/text/atlas/atlas-ranking.h>
23 #include <dali/internal/event/text/atlas/atlas-size.h>
24 #include <dali/internal/event/text/atlas/debug/atlas-debug.h>
25 #include <dali/integration-api/resource-declarations.h>
34 GlyphAtlasManager::GlyphAtlasManager( const FontLookupInterface& fontLookup )
35 : mGlyphResourceManager( fontLookup ),
36 mAtlasesChanged(false)
40 GlyphAtlasManager::~GlyphAtlasManager()
42 // Atlases automatically get destroyed.
45 TextVertexBuffer* GlyphAtlasManager::TextRequired( const Integration::TextArray& text ,
46 const TextFormat& format,
47 FontMetricsInterface& metrics )
50 FontId fontId = metrics.GetFontId();
52 AtlasRanking bestRank( text.Count() );
54 // find the atlas which is best suited to displaying the text string
55 GlyphAtlas* atlas = FindAtlas( text, format, fontId, bestRank);
57 DALI_ASSERT_DEBUG( atlas && "Find atlas should always return a valid atlas." );
59 // if the atlas is full, create a new larger one
60 if( bestRank.GetSpaceStatus() == AtlasRanking::FULL_CAN_BE_RESIZED )
62 atlas = CreateLargerAtlas( atlas );
65 // assign the text to it
66 return atlas->AssignText( text, format, fontId, metrics );
69 void GlyphAtlasManager::TextNotRequired( const Integration::TextArray& text,
70 const TextFormat& format,
72 unsigned int textureId )
74 GlyphAtlas& atlas = GetAtlas( textureId );
76 atlas.TextNoLongerUsed( text, format, fontId );
80 bool GlyphAtlasManager::IsTextLoaded( const Integration::TextArray& text,
81 const TextFormat& format,
83 unsigned int textureId ) const
86 GlyphAtlas& atlas = GetAtlas( textureId );
88 return atlas.IsTextLoaded( text, format, fontId );
91 void GlyphAtlasManager::AddTextObserver( TextObserver& observer)
93 mGlyphResourceManager.AddTextObserver( observer );
96 void GlyphAtlasManager::RemoveTextObserver( TextObserver& observer)
98 mGlyphResourceManager.RemoveTextObserver( observer );
101 void GlyphAtlasManager::AddTextureObserver( GlyphTextureObserver& observer)
103 DALI_ASSERT_DEBUG( std::find(mTextureObservers.Begin(), mTextureObservers.End(), &observer) == mTextureObservers.End() && "Observer already exists" );
104 mTextureObservers.PushBack(&observer);
107 void GlyphAtlasManager::RemoveTextureObserver( GlyphTextureObserver& observer)
109 TextureObserverList::Iterator iter = std::find(mTextureObservers.Begin(), mTextureObservers.End(), &observer);
111 DALI_ASSERT_DEBUG( iter != mTextureObservers.End() && "Observer missing" );
112 mTextureObservers.Erase(iter);
115 void GlyphAtlasManager::SendTextRequests()
117 if( mAtlasesChanged )
119 NotifyAtlasObservers();
120 mAtlasesChanged = false;
123 // this is called at the end of an event cycle.
124 // Each atlas builds up a list of text load requests
125 // We grab the requests here and pass them on to glyph-resource-manager
126 for( std::size_t i = 0, atlasCount = mAtlasList.Size() ; i < atlasCount ; ++i )
128 GlyphAtlas& atlas( *mAtlasList[i] );
130 if( atlas.HasPendingRequests() )
132 const GlyphRequestList& requestList( atlas.GetRequestList() );
134 mGlyphResourceManager.AddRequests( requestList, atlas, atlas.GetTextureId() );
136 atlas.ClearRequestLists();
141 GlyphLoadObserver& GlyphAtlasManager::GetLoadObserver()
143 return mGlyphResourceManager;
146 GlyphAtlas* GlyphAtlasManager::CreateAtlas( unsigned int size )
148 GlyphAtlas* atlas = GlyphAtlas::New( size );
155 GlyphAtlas* GlyphAtlasManager::FindAtlas( const Integration::TextArray& text,
156 const TextFormat& format,
158 AtlasRanking &bestRank )
160 // if the text is underlined, add the underline character to the text string
161 Integration::TextArray searchText( text );
162 if( format.IsUnderLined() )
164 searchText.PushBack( format.GetUnderLineCharacter() );
167 if( mAtlasList.Count() == 0 )
169 // make sure the initial atlas size holds the requested text.
170 unsigned int size = GlyphAtlasSize::GetInitialSize( searchText.Count() );
172 return CreateAtlas( size );
175 // go through each atlas finding the best match
176 GlyphAtlas* bestMatch( NULL );
178 for( std::size_t i = 0, atlasCount = mAtlasList.Size() ; i < atlasCount ; ++i )
180 GlyphAtlas& atlas( *mAtlasList[i] );
182 AtlasRanking rank = atlas.GetRanking( searchText , fontId );
184 if( bestRank.HigherRanked( rank ) == false)
190 if( rank.AllCharactersMatched() )
192 // break if an atlas is found which has all the glyphs loaded
199 void GlyphAtlasManager::AddAtlas( GlyphAtlas* atlas)
201 // create a texture for the atlas.
202 unsigned int textureID = mGlyphResourceManager.CreateTexture( atlas->GetSize() );
204 // assign the texture id
205 atlas->SetTextureId( textureID );
207 mAtlasList.PushBack( atlas );
209 // resource manager will inform the atlas when glyphs are loaded or uploaded to a texture
210 mGlyphResourceManager.AddObserver( *atlas );
213 void GlyphAtlasManager::RemoveAtlas( GlyphAtlas* atlas )
215 for( std::size_t i = 0; i< mAtlasList.Size(); ++i )
217 if( mAtlasList[i] == atlas)
219 // remove it from the resource manager observer list
220 mGlyphResourceManager.RemoveObserver( *atlas );
222 // remove the item from the list & delete it
223 mAtlasList.Erase( mAtlasList.Begin()+i );
227 DALI_ASSERT_DEBUG( 0 && "atlas not found");
230 GlyphAtlas& GlyphAtlasManager::GetAtlas( unsigned int textureId ) const
232 for( std::size_t i = 0, atlasCount = mAtlasList.Size() ; i < atlasCount ; ++i )
234 GlyphAtlas& atlas( *mAtlasList[i] );
236 if( atlas.GetTextureId() == textureId )
241 // check if the texture id is for an old atlas that has been replaced by this atlas
242 if( atlas.HasReplacedTexture( textureId ) )
247 DALI_ASSERT_ALWAYS( 0 && "Atlas not found");
250 GlyphAtlas* GlyphAtlasManager::CreateLargerAtlas( GlyphAtlas* atlas )
252 if( atlas->GetSize() == GlyphAtlasSize::GetMaxSize() )
254 // @todo implement atlas splitting
255 DALI_ASSERT_ALWAYS(0 && "Atlas reached max size");
258 // Create a new bigger atlas
259 unsigned int biggerSize = GlyphAtlasSize::GetNextSize( atlas->GetSize() );
261 GlyphAtlas* newAtlas = GlyphAtlas::New( biggerSize );
263 // clone the contents of the old atlas
264 newAtlas->CloneContents( atlas );
266 // remove the old atlas
267 RemoveAtlas( atlas );
270 AddAtlas( newAtlas );
272 mAtlasesChanged = true;
277 void GlyphAtlasManager::NotifyAtlasObservers()
279 DALI_LOG_INFO(gTextAtlasLogFilter, Debug::General, "GlyphAtlasManager::NotifyAtlasObservers()\n");
281 for( std::size_t i = 0, atlasCount = mAtlasList.Size() ; i < atlasCount ; ++i )
283 GlyphAtlas& atlas( *mAtlasList[i] );
285 Integration::ResourceId newTexture;
286 TextureIdList oldTextures;
287 atlas.GetNewTextureId( oldTextures, newTexture );
289 // copy this list so, the observers can remove themselves during the call back
290 TextureObserverList observerList( mTextureObservers );
292 TextureObserverList::Iterator iter( observerList.Begin() );
293 TextureObserverList::ConstIterator endIter( observerList.End() );
294 for( ; iter != endIter; ++iter )
296 GlyphTextureObserver* observer((*iter));
297 observer->TextureResized( oldTextures, newTexture );
302 } // namespace Internal