{
DALI_ASSERT_ALWAYS( adaptor );
-- // Use BitmapImage when SharedGlBuffer extension is unavailable
++ // Use BufferImage when SharedGlBuffer extension is unavailable
mBitmapBuffer = new NativeBitmapBuffer( adaptor, mImageWidth, mImageHeight, mPixelFormat );
mNativeImage = mBitmapBuffer;
}
STATES_G[$lastIdx]=1
elif [[ ${FILENAMES_G[$lastIdx]} == "-" && ${STATES_G[$lastIdx]} == 1 ]]
then
-- #BitmapImage already in memory and GPU mem. -> updated
++ #BufferImage already in memory and GPU mem. -> updated
SIZES_G[$lastIdx]=$SIZE
SIZE_DETAILS_G[$lastIdx]="$SIZE_DETAILS"
else
+++ /dev/null
--#ifndef __DALI_PLATFORM_DATA_CACHE_H__
--#define __DALI_PLATFORM_DATA_CACHE_H__
--
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--// EXTERNAL INCLUDES
--#include <string>
--#include <dali/public-api/common/vector-wrapper.h>
--
--namespace Dali
--{
--
--namespace Platform
--{
--
--/**
-- * Abstract interface for storing and reading data using a unique search key.
-- *
-- * | Key | Data |
-- * | Key | Data |
-- * | Key | Data |
-- *
-- * For example, the key could be a character code, the data a distance field.
-- *
-- * Only two operations are supported: Add and Find.
-- *
-- */
--class DataCache
--{
--public:
--
-- /**
-- * Read write mode.
-- */
-- enum ReadWriteMode
-- {
-- READ_ONLY, ///< The owner can only read data
-- READ_WRITE ///< The owner can read / write data
-- };
--
-- /**
-- * Compression mode
-- */
-- enum CompressionMode
-- {
-- COMPRESSION_OFF, ///< No data compression
-- RUN_LENGTH_ENCODING ///< RLE encoding
-- };
--
-- /**
-- * Data.
-- * A plain old data structure (POD).
-- * Used when searching and adding to the data cache.
-- */
-- struct Data
-- {
-- /**
-- * Constructor
-- */
-- Data()
-- :data( NULL ),
-- length( 0 ),
-- exists(false)
-- {}
--
-- /**
-- * Destructor
-- */
-- ~Data() {}
--
-- /**
-- * copy constructor
-- */
-- Data( const Data& rhs )
-- {
-- data = rhs.data;
-- length = rhs.length;
-- exists = rhs.exists;
-- }
--
-- /**
-- * Assignment operator
-- */
-- Data& operator=( const Data& rhs)
-- {
-- data = rhs.data;
-- length = rhs.length;
-- exists = rhs.exists;
-- return *this;
-- }
--
-- /**
-- * Set Data
-- * @param newData new data to set
-- * @param dataLength length of the data (in bytes)
-- */
-- void SetData( unsigned char* newData, unsigned int dataLength)
-- {
-- data = newData;
-- length = dataLength;
-- exists = true;
-- }
-- unsigned char* data; ///< pointer to binary data
-- unsigned int length:31; ///< length of the data in bytes
-- unsigned int exists:1; ///< whether the data exists in the cache
-- };
--
-- typedef unsigned int DataKey; ///< Data Key
-- typedef std::vector< DataKey> KeyVector; ///< Vector of keys
-- typedef std::vector< Data> DataVector; ///< Vector of data
--
-- /**
-- * Create a new data cache.
-- * @param[in] mode whether the owning object wants to read or read / write the data
-- * @param[in] compressionMode whether the data should be compressed
-- * @param[in] fileName used to prefix files for storing the data / key information
-- * @param[in] maxDataSize maximum size of the data
-- * @param[in] maxNumberEntries maximum number of entries in the cache, used to check for overflows
-- */
-- static DataCache* New( ReadWriteMode mode,
-- CompressionMode compressionMode,
-- const std::string& fileName,
-- unsigned int maxDataSize,
-- unsigned int maxNumberEntries );
--
-- /**
-- * Destructor.
-- */
-- virtual ~DataCache()
-- {
-- }
--
-- /**
-- * Given an array of keys, retrieve an array of data associated with it.
-- * The dataVector will be filled with Data objects. Each data object
-- * will have its data.exists flag set to true, if the data was found or
-- * false if it was not.
-- * @param[in] keyVector vector of keys to search for
-- * @param[out] dataVector vector of data objects
-- */
-- virtual void Find(const KeyVector& keyVector, DataVector& dataVector) = 0;
--
-- /**
-- * Adds an array of key/data to the cache.
-- * @param[in] keyVector vector of keys to add
-- * @param[in] dataVector vector of data objects to save
-- */
-- virtual void Add(const KeyVector& keyVector, const DataVector& dataVector) = 0;
--
--protected:
--
-- /**
-- * Constructor
-- */
-- DataCache()
-- {
-- }
--
--private:
--
-- // Undefined copy constructor.
-- DataCache( const DataCache& );
--
-- // Undefined assignment operator.
-- DataCache& operator=( const DataCache& );
--};
--
--} // namespace Platform
--
--} // namespace Dali
--
--#endif // __DALI_PLATFORM_DATA_CACHE_H__
+++ /dev/null
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--// CLASS HEADER
--#include "data-cache-impl.h"
--
--// EXTERNAL INCLUDES
--#include <boost/functional/hash.hpp>
--#include <boost/thread.hpp>
--#include <cstdio>
--
--// INTERNAL INCLUDES
--#include "data-cache-io.h"
--#include "data-compression.h"
--#include <dali/integration-api/debug.h>
--
--namespace Dali
--{
--
--namespace SlpPlatform
--{
--
--namespace
--{
--
--boost::mutex mFileCheckMutex; ///< used to ensure only one thread at a time is allowed to check a file for corruption
--std::vector< std::size_t /* hash value*/> fileCheckList; ///< List of files hashes that have been checked
--
--bool FileCheckedForCorruption( std::size_t hashValue )
--{
-- return std::find( fileCheckList.begin(), fileCheckList.end(), hashValue ) != fileCheckList.end();
--}
--
--void SetExistsFlag( Dali::Platform::DataCache::DataVector& dataVector, bool exists)
--{
-- for( unsigned int i = 0, size = dataVector.size(); i < size; ++i)
-- {
-- dataVector[i].exists = exists;
-- }
--}
--#ifdef DEBUG_ENABLED
--void CheckForDuplicateKeys(const Dali::Platform::DataCache::KeyVector& keyVector )
--{
-- std::map< Dali::Platform::DataCache::DataKey, bool> keyLookup;
-- for(unsigned int i = 0, size = keyVector.size(); i<size; ++i)
-- {
-- Dali::Platform::DataCache::DataKey key = keyVector[i];
-- DALI_ASSERT_ALWAYS( keyLookup.find( key ) == keyLookup.end() && "DataCache::Add() called with duplicate keys");
-- keyLookup[ key ] = 1;
-- }
--}
--#else
--void CheckForDuplicateKeys(const Dali::Platform::DataCache::KeyVector& keyVector )
--{
-- // don't check for duplicate keys in release mode
--}
--#endif
--
--} // unnamed namespace
--
--DataCache::DataCache( Dali::Platform::DataCache::ReadWriteMode mode,
-- Dali::Platform::DataCache::CompressionMode compressionMode,
-- const std::string& fileName,
-- unsigned int dataSize,
-- unsigned int maxNumberEntries )
--:mIndexFile( fileName +".index"),
-- mDataFile( fileName +".data"),
-- mNumberEntries( 0 ),
-- mMaxNumberEntries( maxNumberEntries ),
-- mMaxDataSize( dataSize ),
-- mEncodeBuffer( NULL ),
-- mDecodeBuffer( NULL ),
-- mEncodeBufferSize(0),
-- mMode( mode ),
-- mCompressionMode( compressionMode )
--{
-- mEncodeBufferSize = GetMaxEncodedDataSize();
-- mEncodeBuffer = new unsigned char [ mEncodeBufferSize ];
--
-- if( compressionMode != COMPRESSION_OFF )
-- {
-- mDecodeBuffer = new unsigned char[ mMaxDataSize ];
-- }
--
--
-- // check for corruption and repair if required
-- CorruptedFileCheck();
--}
--
--DataCache::~DataCache()
--{
-- delete []mDecodeBuffer;
-- delete []mEncodeBuffer;
--}
--
--void DataCache::Find( const KeyVector& keyVector, DataVector& dataVector )
--{
-- // create the data objects, and set the data.exists flag to false
-- dataVector.resize( keyVector.size() );
-- SetExistsFlag( dataVector, false );
--
-- // the aim is to avoid loading the index file, unless the key is not found in our memory lookup
-- bool indexFileLoaded( false );
--
-- // if the memory lookup is empty, this will try and load the index file
-- InitialiseLookup( indexFileLoaded );
--
-- if( mLookup.empty() )
-- {
-- // the index file has not been created
-- return;
-- }
--
-- // open the data file for read binary
-- FILE* dataFile = DataCacheIo::OpenFile( mDataFile.c_str(), DataCacheIo::DATA_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_ONLY );
-- if( NULL == dataFile )
-- {
-- DALI_LOG_ERROR("Failed to open data file '%s' for reading\n", mDataFile.c_str() );
-- return;
-- }
--
-- // read the data for each key, if it exists
-- ReadFromDataFile( dataFile, indexFileLoaded, keyVector, dataVector );
--
-- // close the data file
-- fclose( dataFile );
--}
--
--// Add()
--//
--// Stage 1.
--// - Lock the data file
--// - Read the latest index file to check for any updates (from other threads/processes)
--//
--// Stage 2.
--// - Insert data to the end of the file
--// - insert the new key / data offset to index file
--// - Increase the number of entries
--//
--// Stage 3.
--// - Close the index file
--// - Close and unlock the data file.
--//
--// The order ensures that:
--// We never write duplicate data.
--// Every entry in the index file, always has valid data.
--// The last chunk of data written to disk is the number of entries in the index file.
--// The write operations are atomic. If many threads are reading from the index file
--// while the write is in progress, depending on timing they will either read
--// n number of entries, or n+1 number of entries. In both cases the data will be valid.
--//
--// If two processes try to save at the same time, one is blocked due to the lock
--// on the data file.
--//
--// If the Process dies during this operation, the file is closed automatically
--// and the lock released
--//
--void DataCache::Add( const KeyVector& keyVector, const DataVector& dataVector )
--{
-- DALI_ASSERT_DEBUG( keyVector.size() == dataVector.size() && !keyVector.empty() );
--
-- CheckForDuplicateKeys( keyVector );
--
-- // copy the vector, so we can modify the exists flag
-- DataVector tempDataVector( dataVector );
-- SetExistsFlag( tempDataVector, false );
--
-- FILE* dataFile( NULL );
-- FILE* indexFile( NULL );
--
-- // open both data and index files, the dataFile will be locked..
-- // ..on failure both dataFile and indexFile will be NULL
-- OpenIndexAndDataForWriting( &dataFile, &indexFile );
--
-- if( dataFile != NULL && indexFile != NULL )
-- {
-- // update our lookup table with the one on disk
-- if( ReLoadIndexFile( indexFile ) )
-- {
-- // Ensure we don't write the same key/data twice if another process has already done it.
-- // if the key/data already exists, the data exists flag will be set to true
-- FindExistingData( keyVector, tempDataVector );
--
-- // write the data, and update the index
-- WriteDataAndUpdateIndex( keyVector, tempDataVector, dataFile, indexFile );
--
-- // close the index file
-- fclose( indexFile );
--
-- // closing the data file will release the lock
-- fclose( dataFile );
-- }
-- else // probable corruption detected
-- {
-- CloseAndReinitializeFiles( &indexFile, &dataFile );
-- }
-- }
--}
--
--void DataCache::CorruptedFileCheck( ) const
--{
-- // only allow one thread at a time to perform the corruption check
-- mFileCheckMutex.lock();
--
-- boost::hash<const std::string> hasher;
-- std::size_t hashValue = hasher( mDataFile );
--
-- // If the file has been checked for corruption already, do not check it again.
-- if( ! FileCheckedForCorruption( hashValue ))
-- {
-- // make sure the files are the correct version and haven't been corrupted
-- DataCacheIo::CheckAndRepairFiles( mIndexFile, mDataFile, mCompressionMode, mEncodeBufferSize, mMaxNumberEntries);
--
-- // add to the list of checked files
-- fileCheckList.push_back( hashValue );
-- }
--
-- mFileCheckMutex.unlock();
--}
--
--void DataCache::InitialiseLookup( bool &indexFileLoaded )
--{
-- // ensure the index file has been loaded at least once.
-- indexFileLoaded = false;
--
-- if( mLookup.empty() )
-- {
-- // if the memory lookup is empty, try loading the index from file
-- LoadIndexFile();
-- indexFileLoaded = true;
-- }
--}
--
--void DataCache::LoadIndexFile()
--{
-- FILE* indexFile = DataCacheIo::OpenFile( mIndexFile,
-- DataCacheIo::INDEX_FILE,
-- DataCacheIo::NO_LOCK,
-- DataCacheIo::READ_ONLY );
--
-- // the index file may not exist yet
-- if( !indexFile )
-- {
-- return;
-- }
--
-- // re-load it to check for new entries
-- if( ReLoadIndexFile( indexFile ) )
-- {
-- fclose( indexFile );
-- }
-- else
-- {
-- CloseAndReinitializeFiles( &indexFile, NULL );
-- }
--}
--
--bool DataCache::ReadFromDataFile( FILE* dataFile,
-- bool indexFileLoaded,
-- const KeyVector& keyVector,
-- DataVector& dataVector
-- )
--{
-- // for each key, try and find it in memory lookup.
-- // if a key is missing then see if the index file has been updated by another thread / process
--
-- for( unsigned int index = 0, vectorSize = keyVector.size(); index < vectorSize; ++index )
-- {
-- DataKey key = keyVector[index];
--
-- KeyLookup::const_iterator keyIter = mLookup.find( key);
--
-- // if a key isn't found in the lookup and we haven't tried loading the index file yet, do it now.
-- if( ( keyIter == mLookup.end() ) && ( !indexFileLoaded ) )
-- {
-- LoadIndexFile();
-- indexFileLoaded = true;
-- keyIter = mLookup.find( key );
-- }
--
-- // if we have found key, fill in the data
-- if( keyIter != mLookup.end() )
-- {
-- // key.second holds the offset in the data file of the binary data
-- unsigned int offset = (*keyIter).second;
-- Data& data( dataVector[ index] );
--
-- DALI_ASSERT_DEBUG( data.exists == false);
--
-- bool ok = ReadData( dataFile, offset , key, data);
-- if( !ok)
-- {
-- return false;
-- }
-- data.exists = true;
-- }
-- }
-- return true;
--}
--
--void DataCache::FindExistingData( const KeyVector& keyVector, DataVector& dataVector) const
--{
-- if( mLookup.empty() )
-- {
-- return;
-- }
-- // for each key, try and find it in memory lookup.
-- // at the same time check for duplicate keys in the key vector
-- for( unsigned int index = 0, vectorSize = keyVector.size(); index < vectorSize; ++index )
-- {
-- if( mLookup.find( keyVector[index] ) == mLookup.end() )
-- {
-- dataVector[index].exists = false;
-- }
-- else
-- {
-- dataVector[index].exists = true;
-- }
-- }
--}
--
--void DataCache::OpenIndexAndDataForWriting(FILE** dataFile, FILE** indexFile )
--{
-- // open and lock the data file
-- *dataFile = DataCacheIo::OpenFile( mDataFile, DataCacheIo::DATA_FILE, DataCacheIo::LOCK_FILE, DataCacheIo::READ_WRITE );
-- if( *dataFile == NULL )
-- {
-- DALI_LOG_ERROR( "Failed to open and lock %s\n", mDataFile.c_str() );
-- }
-- else
-- {
-- // open the index file, there is no need in locking it as well
-- // as the data file lock is used as a global lock
-- *indexFile = DataCacheIo::OpenFile( mIndexFile, DataCacheIo::INDEX_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_WRITE );
-- if( *indexFile == NULL )
-- {
-- DALI_LOG_ERROR( "Failed to open %s\n", mIndexFile.c_str() );
--
-- fclose( *dataFile );
-- *dataFile = NULL;
-- }
-- }
--}
--
--void DataCache::WriteDataAndUpdateIndex( const KeyVector& keyVector,
-- const DataVector& dataVector,
-- FILE* dataFile,
-- FILE* indexFile
-- )
--{
-- // seek to the end of both files for adding new data
-- DataCacheIo::PrepareForWritingData( dataFile, indexFile );
--
-- unsigned int newEntries( 0 );
--
-- for ( unsigned int index = 0, arraySize = keyVector.size(); index < arraySize; ++index )
-- {
-- const Data& data( dataVector[index] );
-- const DataKey& key( keyVector[index] );
--
-- // write the data, if the data doesn't already exist
-- if( data.exists == false )
-- {
-- newEntries++;
--
-- // write the data
-- unsigned int offset = WriteData( dataFile, key, data );
--
-- // update the index file with the new key / offset.
-- DataCacheIo::WriteKey( indexFile, key, offset );
--
-- // write to our memory lookup
-- mLookup[ key ] = offset;
--
-- }
-- }
-- if( newEntries )
-- {
-- mNumberEntries+= newEntries;
--
-- // assert if max entries is exceeded, the cache files will be deleted on restart
-- DALI_ASSERT_ALWAYS( mNumberEntries <= mMaxNumberEntries);
--
-- // write the number of entries
-- DataCacheIo::WriteNumberEntries( indexFile, mNumberEntries );
--
-- }
--}
--
--bool DataCache::ReadData( FILE* dataFile,
-- unsigned int offset,
-- DataCache::DataKey key,
-- DataCache::Data& data) const
--{
-- unsigned char *dataBuffer( mEncodeBuffer );
--
-- // load the data in to the encode buffer
-- bool ok = DataCacheIo::ReadData( dataFile, offset, key, data, mEncodeBuffer, mEncodeBufferSize );
-- if( !ok )
-- {
-- DALI_LOG_ERROR("data file corrupt \n");
-- return false;
-- }
--
-- if( mCompressionMode == RUN_LENGTH_ENCODING )
-- {
-- std::size_t bytesDecoded(0);
-- ok = DataCompression::DecodeRle( mEncodeBuffer, data.length, mDecodeBuffer, mMaxDataSize, bytesDecoded);
-- if( !ok )
-- {
-- DALI_LOG_ERROR("data file corrupt \n");
-- return false;
-- }
-- // set the dataBuffer to point to the decoded data
-- dataBuffer = mDecodeBuffer;
--
-- // set the data.length to be the decoded length
-- data.length = bytesDecoded;
-- }
--
-- // allocate and copy the data in the data structure
-- data.data = new unsigned char[ data.length ];
-- memcpy( data.data, dataBuffer, data.length );
--
-- return true;
--}
--
--unsigned int DataCache::WriteData( FILE *dataFile, DataKey key, const Data &data) const
--{
-- unsigned int offset;
--
-- // check data is not too large
-- DALI_ASSERT_DEBUG( data.length <= mMaxDataSize );
--
-- if( mCompressionMode == COMPRESSION_OFF )
-- {
-- // write the data
-- offset = DataCacheIo::WriteData( dataFile, key, data );
-- }
-- else
-- {
-- // compress, then write the data
-- std::size_t compressedLength( 0 );
-- DataCompression::EncodeRle( data.data, data.length, mEncodeBuffer, mEncodeBufferSize, compressedLength);
-- Data compressedData;
-- compressedData.SetData( mEncodeBuffer, compressedLength );
-- offset = DataCacheIo::WriteData( dataFile, key, compressedData );
-- }
-- return offset;
-- }
--
--bool DataCache::ReLoadIndexFile( FILE *indexFile )
--{
-- // First check if our memory cache is out of sync with what is in the file
-- // another process may have added some new entries
-- unsigned int numberEntries(0) ;
--
-- bool ok = DataCacheIo::ReadNumberEntries( indexFile, numberEntries);
-- if( !ok )
-- {
-- return false;
-- }
-- if( numberEntries == mNumberEntries )
-- {
-- // if there is no new entries return
-- return true;
-- }
--
-- if( numberEntries < mNumberEntries )
-- {
-- // this should not happen, but if it does delete the cache files and assert
-- DALI_LOG_ERROR("numberEntries too small \n");
-- return false;
-- }
-- ok = ReadNewEntries( indexFile, ( numberEntries - mNumberEntries) );
-- if( !ok )
-- {
-- return false;
-- }
-- return true;
--}
--
--bool DataCache::ReadNewEntries( FILE* indexFile, unsigned int newEntries)
--{
-- // instead of performing an I/O operation per entry, we read all new entries
-- // in a single read.
-- DataCacheIo::KeyMeta* keyMeta = new DataCacheIo::KeyMeta[ newEntries ];
--
-- // read newEntries worth of data from start index mNumberEntries.
-- bool ok = DataCacheIo::ReadEntries(indexFile, keyMeta, mNumberEntries, newEntries);
-- if( ok )
-- {
-- for( unsigned int i = 0; i< newEntries; ++i )
-- {
-- DataKey key( keyMeta[i].mKey );
-- unsigned int offset (keyMeta[i].mOffset );
--
-- // check the key hasn't been stored before
-- DALI_ASSERT_DEBUG( mLookup.end() == mLookup.find( key) );
--
-- // create a new key with the offset
-- mLookup[ key ] = offset;
-- mNumberEntries++;
-- }
-- }
-- else
-- {
-- DALI_LOG_ERROR("read new entries failed \n");
-- }
--
-- delete []keyMeta;
-- return ok;
--}
--
--//
--// If file corruption is detected while the thread is running
--// and after CorruptedFileCheck() has been performed,
--// then delete the files.
--// This should only occur if:
--// - 2 or more Dali Applications are running
--// - One of them is killed half way through a DataCache::Add operation,
--// corrupting the files.
--// - The other app then tries to use the corrupt files, and detects an error.
--// When either app restarts the cache will be recreated.
--//
--void DataCache::CloseAndReinitializeFiles( FILE** indexFile, FILE** dataFile ) const
--{
-- DALI_LOG_ERROR( "corrupt data file detected, re-created" );
--
-- // close existing files
-- if( indexFile && *indexFile )
-- {
-- fclose( *indexFile );
-- *indexFile = NULL;
-- }
--
-- if( dataFile && *dataFile )
-- {
-- fclose( *dataFile );
-- *dataFile = NULL;
-- }
--
-- // reopen files writable
-- FILE* newDataFile = DataCacheIo::OpenFile( mDataFile, DataCacheIo::DATA_FILE, DataCacheIo::LOCK_FILE, DataCacheIo::READ_WRITE );
-- if( newDataFile != NULL )
-- {
-- FILE* newIndexFile = DataCacheIo::OpenFile( mIndexFile, DataCacheIo::INDEX_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_WRITE );
-- if( newIndexFile != NULL )
-- {
-- // re-create the files with zero entries
-- DataCacheIo::ReCreateFiles( newIndexFile, newDataFile, mCompressionMode );
-- fclose( newIndexFile );
-- }
-- fclose( newDataFile );
-- }
--}
--
--unsigned int DataCache::GetMaxEncodedDataSize() const
--{
-- if( mCompressionMode == COMPRESSION_OFF )
-- {
-- return mMaxDataSize;
-- }
-- else
-- {
-- // RLE can double the data size in worst case scenario
-- return DataCompression::GetMaximumRleCompressedSize( mMaxDataSize );
-- }
--}
--
--} // namespace SlpPlatform
--
--} // namespace Dali
--
--// Implementation of Dali::Platform::DataCache::New()
--Dali::Platform::DataCache* Dali::Platform::DataCache::New(
-- Dali::Platform::DataCache::ReadWriteMode mode,
-- Dali::Platform::DataCache::CompressionMode compressionMode,
-- const std::string& fileName,
-- unsigned int maxDataSize,
-- unsigned int maxNumberEntries)
--{
-- return new Dali::SlpPlatform::DataCache( mode, compressionMode, fileName, maxDataSize, maxNumberEntries );
--}
+++ /dev/null
--#ifndef __DALI_SLP_PLATFORM_DATA_CACHE_H__
--#define __DALI_SLP_PLATFORM_DATA_CACHE_H__
--
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--// INTERNAL INCLUDES
--#include "../../interfaces/data-cache.h"
--#include <dali/public-api/common/map-wrapper.h>
--
--namespace Dali
--{
--
--namespace SlpPlatform
--{
--
--/**
-- * Class used for storing key, value data to the file system.
-- * Concrete implementation of the Platform::DataCache interface
-- * E.g. Unicode character code (Key), distance field binary data (Value).
-- *
-- *
-- * Internals: Uses two files.
-- * - Index file, which has Key values, and offsets to the data in the data file.
-- * __________________
-- * | FILE HEADER \
-- * |-------------------|
-- * | Key | Data Offset |
-- * | Key | Data Offset |
-- * | Key | Data Offset |
-- *
-- * - Data file, contains the data
-- * __________________________
-- * | FILE HEADER \
-- * | -------------------------|
-- * | Key | Data Length | Data |
-- * | Key | Data Length | Data |
-- * | Key | Data Length | Data |
-- *
-- * The Key is stored in the data file as well, to ensure the information held in the index file
-- * is correct.
-- *
-- * Multi-threading / multi-process notes
-- *
-- * - Any thread / process can read from the data-cache files without being blocked.
-- * - Only a single thread / process can write data at any time. This is achieved by
-- * using a file lock.
-- * - Reading from the data-cache while it is being written to is fine. See DataCache::Add()
-- * code comments for an explanation on how this works.
-- *
-- * Summary:
-- * DataCache::Find = never blocks
-- * DataCache::Add = will block, if another thread / process is also running DataCache::Add()
-- *
-- * File corruption
-- *
-- * This may occur if the power is cut or or if the process is killed during
-- * a DataCache::Add() operation.
-- * On class creation a check is made to ensure the files are valid.
-- * If corruption is found they are deleted and recreated empty.
-- *
-- * Performance notes:
-- * DataCache::Find() use std::map which has complexity of O( log n)
-- * Plus the addition of a fixed time reading/writing the data to file system.
-- * In simple terms, the time taken to Add or Find data in a data cache
-- * with 10,000 entries is almost identical to a data cache with 100 items.
-- *
-- */
--class DataCache : public Platform::DataCache
--{
--
--public:
--
-- /**
-- * Constructor
-- * @copydoc Dali::Platform::DataCache::DataCache()
-- */
-- DataCache( Dali::Platform::DataCache::ReadWriteMode mode,
-- Dali::Platform::DataCache::CompressionMode compressionMode,
-- const std::string& fileName,
-- unsigned int maxDataSize,
-- unsigned int maxNumberEntries);
--
-- /**
-- * Destructor
-- */
-- virtual ~DataCache();
--
-- /**
-- * @copydoc Dali::Platform::DataCache::Find()
-- */
-- virtual void Find( const KeyVector& keyVector, DataVector& valueArray );
--
-- /**
-- * @copydoc Dali::Platform::DataCache::Add()
-- */
-- virtual void Add(const KeyVector& keyVector, const DataVector& valueArray);
--
--private:
--
-- /**
-- * Check and re-create the data/index files if they are corrupt.
-- */
-- void CorruptedFileCheck() const;
--
-- /**
-- * Initialise the lookup.
-- * @param[out] indexFileLoaded set to true of the index file was loaded
-- */
-- void InitialiseLookup( bool &indexFileLoaded );
--
-- /**
-- * Load the index file if it exists
-- */
-- void LoadIndexFile();
--
-- /**
-- * Read data for each key.
-- * @param[in] dataFile data file
-- * @param[in] indexFileLoaded whether the index file has been loaded
-- * @param[in] keyVector vector of keys
-- * @param[out] dataVector vector of data objects
-- */
-- bool ReadFromDataFile( FILE* dataFile,
-- bool indexFileLoaded,
-- const KeyVector& keyVector,
-- DataVector& dataVector
-- );
--
-- /**
-- * Checks which keys / data exist in the data cache.
-- * Done just before writing to the data cache to avoid duplicate
-- * entries.
-- * @param[in] keyVector vector of keys
-- * @param[out] dataVector vector of data objects
-- */
-- void FindExistingData( const KeyVector& keyVector, DataVector& dataVector) const;
--
-- /**
-- * Open the index and data files for writing
-- * Asserts on failure.
-- * @param[out] dataFile data file
-- * @param[out] indexFile index file
-- */
-- void OpenIndexAndDataForWriting(FILE** dataFile, FILE** indexFile);
--
-- /**
-- * Writes the data to the data file and updates the index file.
-- * @param[in] keyVector vector of keys
-- * @param[in] dataVector vector of data objects
-- * @param[in] dataFile data file
-- * @param[in] indexFile index file
-- */
-- void WriteDataAndUpdateIndex( const KeyVector& keyVector,
-- const DataVector& dataVector,
-- FILE* dataFile,
-- FILE* indexFile );
-- /**
-- * Read the data from the data file.
-- * @param[in] dataFile data file
-- * @param[in[ offset the file offset where the data exists
-- * @param[in] key used to ensure the data is for the correct key
-- * @param[out] data assigned the data from the file
-- * @return true on success, false on failure (corruption)
-- */
-- bool ReadData( FILE* dataFile,
-- unsigned int offset,
-- DataKey key,
-- Data &data) const;
--
-- /**
-- * Write the data to the data file.
-- * @param[in] dataFile data file
-- * @param[in] key used to ensure the data is for the correct key
-- * @param[in] data assigned the data from the file
-- * @return the offset in the file where the data was written
-- */
-- unsigned int WriteData( FILE *dataFile, DataKey key, const Data &data) const;
--
-- /**
-- * Reload the index file to check for updates.
-- * @param[in] indexFile index file
-- * @return true on success, false on failure (corruption)
-- */
-- bool ReLoadIndexFile( FILE* indexFile );
--
-- /**
-- * Read new entries from the index file.
-- * @param[in] indexFile index file
-- * @param[in] newEntries number of new entries to read
-- * @return true on success, false on failure (corruption)
-- */
-- bool ReadNewEntries( FILE* indexFile, unsigned int newEntries);
--
-- /**
-- * Close existing files, then calls DataCacheIo::RecreateFiles to truncate and reinitialize the files
-- * @param[in] indexFile index file
-- * @param[in] dataFile data file
-- */
-- void CloseAndReinitializeFiles(FILE** indexFile , FILE** dataFile) const;
--
-- /**
-- * Return the maximum buffer size of encoded data.
-- * E.g. if maximum data size is 4 KB, and RLE compression is used
-- * the maximum encoded size is 8 KB in the worst case scenario.
-- * @return maximum size of encoded data.
-- */
-- unsigned int GetMaxEncodedDataSize() const;
--
-- typedef std::map< DataKey, unsigned int /* file offset */ > KeyLookup;
--
-- KeyLookup mLookup; ///< Lookup between key, and offset of the value in a table.
-- std::string mIndexFile; ///< index file name
-- std::string mDataFile; ///< cache file name
-- unsigned int mNumberEntries; ///< how many entries in our lookup (mLookup.size() can be O(n)
-- unsigned int mMaxNumberEntries; ///< Maximum number entries allowed
-- unsigned int mMaxDataSize; ///< size of the data
-- unsigned char* mEncodeBuffer; ///< encode buffer for compressed data
-- unsigned char* mDecodeBuffer; ///< decode buffer for un-compressed data
-- std::size_t mEncodeBufferSize; ///< Size of the encode buffer
--
-- Platform::DataCache::ReadWriteMode mMode; ///< read / write mode.
-- Platform::DataCache::CompressionMode mCompressionMode; ///< Compression mode
--
--};
--
--} // namespace SlpPlatform
--
--} // namespace Dali
--
--#endif // __DALI_SLP_PLATFORM_DATA_CACHE_H__
+++ /dev/null
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--// CLASS HEADER
--#include "data-cache-io.h"
--
--// INTERNAL INCLUDES
--#include <dali/integration-api/debug.h>
--
--// EXTERNAL INCLUDES
--#include <stdio.h>
--#include <string.h>
--#include <sys/file.h> // flock()
--#include <unistd.h> // ftruncate()
--#include <errno.h>
--
--
--namespace Dali
--{
--
--namespace SlpPlatform
--{
--
--namespace DataCacheIo
--{
--
--namespace // unnamed name space
--{
--
--#if defined(DEBUG_ENABLED)
--Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_DATA_CACHE_IO");
--#endif
--
--const std::size_t DESCRIPTION_SIZE( 16 ); ///< Description size
--const std::size_t VERSION_SIZE( sizeof(__DATE__ "-" __TIME__) ); ///< (date-time)
--const std::size_t COMPRESSION_MODE_SIZE( 10 ); ///< off | RLE
--const std::size_t NUMBER_ENTRIES_SIZE( sizeof(unsigned int) ); ///< number of entries in index file
--const std::size_t OFFSET_SIZE( sizeof(unsigned int) ); ///< size of the offset field
--
--const char INDEX_FILE_DESCRPITION[ DESCRIPTION_SIZE+1 ] = "Index File"; ///< String description added to the header
--const char DATA_FILE_DESCRPITION[ DESCRIPTION_SIZE+1 ] = "Data File"; ///< String description added to the header
--
--const char FILE_VERSION[ VERSION_SIZE+1 ] = __DATE__ "-" __TIME__; ///< Updates with each build
--
--typedef Dali::Platform::DataCache::DataKey DataKey;
--typedef Dali::Platform::DataCache::Data Data;
--typedef Dali::Platform::DataCache::CompressionMode CompressionMode;
--typedef unsigned int DataOffset;
--typedef unsigned int DataLength;
--
--/**
-- * File header, for both index and data files.
-- */
--struct FileHeader
--{
-- char description[ DESCRIPTION_SIZE+1 ];
-- char version[ VERSION_SIZE+1 ];
-- char compressionMode[ COMPRESSION_MODE_SIZE+1 ];
--};
--
--/**
-- * Data meta information
-- */
--struct DataMeta
--{
-- DataMeta() :mKey(0), mLength(0)
-- {}
-- DataMeta(DataKey key, DataLength length)
-- :mKey(key), mLength(length)
-- {}
-- DataKey mKey;
-- DataLength mLength;
--};
--
--const std::size_t FILE_HEADER_SIZE( sizeof (FileHeader )); ///< header size
--const std::size_t KEY_META_SIZE( sizeof (KeyMeta )); ///< key meta size
--const std::size_t DATA_META_SIZE( sizeof (DataMeta )); ///< Data meta size
--
--/**
-- * Helper to return the string for a compression mode.
-- */
--const char *GetCompressString( CompressionMode mode)
--{
-- return (mode == Dali::Platform::DataCache::COMPRESSION_OFF) ? "comp off" : "RLE on";
--}
--
--/**
-- * Helper to read a file header
-- */
--bool ReadHeader( FILE* file,
-- const char *fileDescription,
-- CompressionMode compressionMode)
--{
-- FileHeader header;
--
-- if( fseek( file, 0, SEEK_SET ) )
-- {
-- DALI_LOG_ERROR("Error seeking to start of file\n");
-- return false;
-- }
--
-- std::size_t read = fread( &header , FILE_HEADER_SIZE, 1, file );
-- if( read == 0 )
-- {
-- // This will happen if the file has just been created.
-- return false;
-- }
--
-- // make sure description, version and compression mode all match
-- if( ( strncmp( header.description, fileDescription, DESCRIPTION_SIZE ) == 0) &&
-- ( strncmp( header.version, FILE_VERSION, VERSION_SIZE ) == 0) &&
-- ( strncmp( header.compressionMode, GetCompressString( compressionMode ), COMPRESSION_MODE_SIZE )) == 0 )
-- {
-- return true;
-- }
-- // this will happen if the version changes
-- DALI_LOG_WARNING("Header miss-match %s\n",fileDescription);
-- return false;
--
--}
--
--/**
-- * Helper to write a file header
-- */
--void WriteHeader( FILE* file,
-- const char *fileDescription,
-- CompressionMode compressionMode)
--{
-- // Seek to beginning of file
-- rewind( file );
--
-- FileHeader header;
-- memset( &header, 0, FILE_HEADER_SIZE );
--
-- strncpy( header.description, fileDescription, DESCRIPTION_SIZE );
-- strncpy( header.version, FILE_VERSION, VERSION_SIZE );
-- strncpy( header.compressionMode, GetCompressString( compressionMode ), COMPRESSION_MODE_SIZE );
--
-- std::size_t NUMBER_OF_HEADERS( 1 );
-- std::size_t writeCount = fwrite( &header, FILE_HEADER_SIZE, NUMBER_OF_HEADERS, file );
-- if( writeCount != NUMBER_OF_HEADERS )
-- {
-- DALI_LOG_ERROR( "Error '%s' writing file header\n", strerror( errno ) );
-- }
--}
--
--/**
-- * Helper to write data meta information to the data file (key, length).
-- * Data file format is
-- * | KEY | DATA LENGTH | DATA |
-- */
--void WriteDataMeta( FILE* dataFile, DataKey key, const Data& data)
--{
-- DataMeta meta( key, data.length );
--
-- DALI_ASSERT_ALWAYS( data.length != 0 );
--
-- std::size_t NUMBER_OF_DATA_METAS( 1 );
-- // write the key and data length
-- std::size_t writeCount = fwrite( &meta, DATA_META_SIZE, NUMBER_OF_DATA_METAS, dataFile );
-- if( writeCount != NUMBER_OF_DATA_METAS )
-- {
-- DALI_LOG_ERROR( "Error '%s' writing data meta\n", strerror( errno ) );
-- }
--}
--
--/**
-- * Helper to read data meta information
-- */
--bool ReadDataMeta(FILE* dataFile, DataKey& key, Data& data)
--{
-- DataMeta meta;
--
-- // read the key and data length
-- std::size_t read = fread( &meta, DATA_META_SIZE, 1, dataFile );
-- if( read == 0 )
-- {
-- return false;
-- }
--
-- key = meta.mKey;
-- data.length = meta.mLength;
--
-- return true;
--}
--
--/**
-- * Helper to check a data section is valid
-- */
--bool CheckDataIsValid(FILE* dataFile,
-- unsigned int offset,
-- DataKey key,
-- Data& data,
-- unsigned int bufferSize,
-- bool checkDataExists)
--{
-- DataKey loadedKey(0);
--
-- // move to the file pointer to where the data is held
-- int ret = fseek( dataFile , offset, SEEK_SET);
-- if( ret != 0 )
-- {
-- // something has been corrupted.
-- DALI_LOG_ERROR("data offset is invalid (corrupt?)\n");
-- return false;
-- }
--
-- // read the key, and data size at the current file position to make sure it's valid
-- bool ok = ReadDataMeta( dataFile, loadedKey, data );
-- if( !ok )
-- {
-- DALI_LOG_ERROR("data meta corrupt\n");
-- return false;
-- }
--
-- // check the key matches
-- if( loadedKey != key )
-- {
-- DALI_LOG_ERROR("Key miss-match in data file\n");
-- return false;
-- }
--
-- // make sure the size is valid
-- if( data.length > bufferSize )
-- {
-- DALI_LOG_ERROR("Data size is corrupt in data file %d data size, buffer size %d \n",data.length, bufferSize);
-- return false;
-- }
--
-- if( checkDataExists )
-- {
-- // check if the file is big enough to support the data
-- ret = fseek( dataFile , data.length, SEEK_CUR);
-- if( ret != 0 )
-- {
-- // something has been corrupted.
-- DALI_LOG_ERROR("data field invalid or file truncated\n");
-- return false;
-- }
-- }
-- return true;
--}
--
--/**
-- * Helper to check the index file body
-- */
--bool CheckIndexFileBody( FILE* indexFile,
-- DataKey &lastKey,
-- DataOffset &lastOffset,
-- unsigned int& numberEntries,
-- unsigned int maxNummberEntries )
--{
--
-- bool ok = ReadNumberEntries( indexFile, numberEntries );
-- if( !ok )
-- {
-- return false;
-- }
-- if( numberEntries == 0 )
-- {
-- return true;
-- }
-- if( numberEntries >= maxNummberEntries )
-- {
-- DALI_LOG_ERROR("number entries > maxNummberEntries in index file, entries: %d \n", numberEntries);
-- return false;
-- }
--
-- // seek to offset where the last index is held
-- unsigned int lastKeyMetaOffset( FILE_HEADER_SIZE + NUMBER_ENTRIES_SIZE );
-- lastKeyMetaOffset+= (numberEntries - 1) * KEY_META_SIZE;
--
-- int ret = fseek( indexFile, lastKeyMetaOffset, SEEK_SET );
-- if( ret != 0 )
-- {
-- DALI_LOG_ERROR("index file corrupt, failed to seek to last index\n");
-- return false;
-- }
--
-- // read the key + offset
-- ok = ReadKey( indexFile, lastKey, lastOffset );
-- if( !ok )
-- {
-- return false;
-- }
--
-- if( fgetc( indexFile ) != EOF)
-- {
-- // data index is corrupt, it contains more entries than are recorded in numberEntries field
-- DALI_LOG_ERROR("index has more entries than recorded\n");
-- return false;
-- }
--
-- return true;
--
--}
--
--/**
-- * Helper to check the files are valid
-- */
--bool CheckFilesAreValid( FILE* indexFile,
-- FILE* dataFile,
-- Dali::Platform::DataCache::CompressionMode compressionMode,
-- unsigned int maxDataSize,
-- unsigned int maxNummberEntries)
--{
--
-- bool ok = ReadHeader( indexFile, INDEX_FILE_DESCRPITION, compressionMode );
-- if(!ok)
-- {
-- return false;
-- }
-- ok = ReadHeader( dataFile, DATA_FILE_DESCRPITION, compressionMode );
-- if(!ok)
-- {
-- return false;
-- }
--
-- DataKey key(0);
-- Data data;
-- DataOffset offset(0);
-- unsigned int numEntries(0);
--
-- // check the index file is ok, and find out the last entry in it
-- ok = CheckIndexFileBody( indexFile, key, offset, numEntries, maxNummberEntries );
-- if( !ok)
-- {
-- return false;
-- }
--
-- // if number entries = 0, then check the data file has no data after it's header
-- if( numEntries == 0)
-- {
-- if( fgetc( dataFile ) != EOF)
-- {
-- // data file is corrupt, it contains data thas has no entries
-- return false;
-- }
-- else
-- {
-- // no further checks needed
-- return true;
-- }
-- }
--
-- // check if the data is valid, this doesn't read the data, just checks the file
-- // has the correct length
-- ok = CheckDataIsValid( dataFile, offset, key, data , maxDataSize, true);
-- if( !ok )
-- {
-- return false;
-- }
-- // check we're at the end of the data file
-- if( fgetc( dataFile ) != EOF)
-- {
-- return false;
-- }
-- return true;
--}
--
--/**
-- * Helper to lock a file
-- */
--bool LockFile(FILE* file)
--{
-- // Place an exclusive lock. Only one process may hold an
-- // exclusive lock for a given file at a given time.
-- // It places an advisory locks only; given suitable permissions on a file,
-- // a process is free to ignore the use of flock() and perform I/O on the file.
-- int ret = flock( fileno(file), LOCK_EX);
-- if( 0 != ret )
-- {
-- DALI_LOG_ERROR("Error '%s' locking cache file\n", strerror( errno ) );
-- return false;
-- }
--
-- return true;
--}
--}; // unnamed namespace
--////////////////////////////////////////////////////////////////////////
--////////////////////////////////////////////////////////////////////////
--
--void CheckAndRepairFiles( const std::string& indexFileName,
-- const std::string& dataFileName,
-- Dali::Platform::DataCache::CompressionMode compressionMode,
-- unsigned int maxDataSize,
-- unsigned int maxNummberEntries )
--{
-- // It's possible if the power is lost or the has been process killed while writing to the index / data files
-- // they could be corrupt. The following quickly tests to make sure the headers
-- // and the last entry in the index / data file is valid.
--
-- FILE* dataFile = OpenFile( dataFileName, DATA_FILE, LOCK_FILE, READ_WRITE, CREATE_IF_MISSING );
-- if( dataFile != NULL )
-- {
-- FILE* indexFile = OpenFile( indexFileName, INDEX_FILE, NO_LOCK, READ_WRITE, CREATE_IF_MISSING );
-- if( indexFile != NULL )
-- {
-- if( ! CheckFilesAreValid( indexFile, dataFile, compressionMode, maxDataSize, maxNummberEntries) )
-- {
-- ReCreateFiles( indexFile, dataFile, compressionMode);
-- }
-- fclose( indexFile);
-- }
-- fclose( dataFile);
-- }
--}
--
--FILE* OpenFile(const std::string& fileName,
-- FileType fileType,
-- LockMode lockMode,
-- FileOpenMode fileMode,
-- FileCreationMode creationMode )
--{
-- // open and the file, for reading(r) binary (b) (+) update
-- const char* openMode( (fileMode == READ_WRITE) ? "r+b" : "rb" );
-- FILE* file = fopen( fileName.c_str(), openMode );
-- if( file == NULL )
-- {
-- if((fileMode == READ_WRITE) && (creationMode == CREATE_IF_MISSING) )
-- {
-- // Attempt to create a new file for reading / writing
-- DALI_LOG_INFO( gLogFilter , Debug::Concise, "Creating new file: %s\n",fileName.c_str());
-- file = fopen( fileName.c_str(), "w+b");
-- if( file == NULL )
-- {
-- DALI_LOG_ERROR( "Failed to create file %s, with error '%s'\n", fileName.c_str(), strerror( errno ) );
-- }
-- }
-- }
--
-- if( file != NULL ) // open file?
-- {
-- if( lockMode == LOCK_FILE ) // and file requires lock?
-- {
-- bool fileLockSucceeded = LockFile( file ); // lock file
-- if( ! fileLockSucceeded )
-- {
-- DALI_LOG_ERROR("Failed to lock file %s\n", fileName.c_str() );
-- fclose( file );
-- file = NULL;
-- }
-- }
-- }
--
-- return file;
--}
--
--void ReCreateFiles(FILE* indexFile, FILE* dataFile, CompressionMode compressionMode )
--{
-- int resultStatus(0);
--
-- // Truncate to zero and then write new headers.
--
-- // index file
-- resultStatus = ftruncate( fileno( indexFile ), 0);
-- if( resultStatus )
-- {
-- DALI_LOG_ERROR( "Error '%s' truncating index file\n", strerror( errno ) );
-- }
-- else
-- {
-- WriteHeader( indexFile, INDEX_FILE_DESCRPITION, compressionMode);
-- WriteNumberEntries( indexFile, 0 );
-- }
--
-- // data file
-- resultStatus = ftruncate( fileno( dataFile ), 0);
-- if( resultStatus )
-- {
-- DALI_LOG_ERROR( "Error '%s' truncating data file\n", strerror( errno ) );
-- }
-- else
-- {
-- WriteHeader( dataFile, DATA_FILE_DESCRPITION, compressionMode);
-- }
--}
--
--void PrepareForWritingData( FILE* dataFile, FILE* indexFile )
--{
-- if( fseek(dataFile, 0, SEEK_END) )
-- {
-- DALI_LOG_ERROR("Error seeking to start of dataFile\n");
-- }
--
-- if( fseek(indexFile, 0, SEEK_END) )
-- {
-- DALI_LOG_ERROR("Error seeking to start of indexFile\n");
-- }
--}
--
--unsigned int WriteData( FILE* dataFile, DataKey key, const Data& data )
--{
-- // get the current file offset
-- unsigned int offset( 0u );
-- long positionIndicator = ftell( dataFile );
-- if( positionIndicator > -1L )
-- {
-- offset = static_cast<unsigned int>(positionIndicator);
-- }
-- else
-- {
-- DALI_LOG_ERROR("Error finding the current file offset\n");
-- }
--
-- // write the key first and data size
-- WriteDataMeta( dataFile, key, data);
--
-- // write the data
-- fwrite( data.data, data.length, 1, dataFile );
--
-- return offset;
--}
--
--bool ReadData( FILE* dataFile,
-- unsigned int offset,
-- DataKey key,
-- Data& data,
-- unsigned char* dataBuffer,
-- unsigned int bufferSize)
--{
--
-- // read the data meta information first, ensure it's valid and will
-- // fit in to the dataBuffer
-- bool ok = CheckDataIsValid( dataFile, offset, key, data, bufferSize, false);
-- if( !ok )
-- {
-- // CheckDataIsValid will log an error
-- return false;
-- }
--
-- // read the actual data
-- std::size_t read = fread( dataBuffer , data.length, 1, dataFile );
-- if( read == 0 )
-- {
-- DALI_LOG_ERROR("Note enough data in data file (corrupt)\n");
-- return false;
-- }
-- return true;
--}
--
--bool ReadEntries(FILE *indexFile, KeyMeta* meta, unsigned int startIndex, unsigned int count)
--{
-- // seek past the header and existing entries to startIndex
-- unsigned int seekOffset = ( FILE_HEADER_SIZE + NUMBER_ENTRIES_SIZE )+ startIndex* KEY_META_SIZE;
--
-- int ret = fseek( indexFile , seekOffset , SEEK_SET);
-- if( ret != 0 )
-- {
-- DALI_LOG_ERROR("index file corrupt, fseek failed\n");
-- return false;
-- }
-- std::size_t readCount = fread( meta, KEY_META_SIZE, count, indexFile);
-- if( readCount != count )
-- {
-- DALI_LOG_ERROR("index file missing data\n");
-- return false;
-- }
-- return true;
--}
--
--bool ReadNumberEntries( FILE* indexFile, unsigned int &numEntries )
--{
-- int ret = fseek( indexFile , FILE_HEADER_SIZE, SEEK_SET);
-- if( ret != 0 )
-- {
-- DALI_LOG_ERROR("index file corrupt, fseek failed\n");
-- return false;
-- }
--
-- std::size_t read = fread( &numEntries, NUMBER_ENTRIES_SIZE , 1, indexFile);
-- if( read == 0)
-- {
-- DALI_LOG_ERROR("index file corrupt, fread failed\n");
-- return false;
-- }
-- return true;
--}
--
--void WriteNumberEntries( FILE* indexFile, unsigned int numEntries )
--{
-- // entries field is first bytes after header
-- if ( fseek( indexFile , FILE_HEADER_SIZE, SEEK_SET) )
-- {
-- DALI_LOG_ERROR("index file corrupt, fseek failed\n");
-- }
--
-- fwrite( &numEntries, NUMBER_ENTRIES_SIZE , 1, indexFile);
--}
--
--bool ReadKey( FILE* indexFile, DataKey &key, unsigned int& offset )
--{
-- KeyMeta meta;
--
-- std::size_t read = fread( &meta, KEY_META_SIZE, 1, indexFile );
-- if( read == 0 )
-- {
-- DALI_LOG_ERROR("index file corrupt, failed to read key meta\n");
-- return false;
-- }
-- key = meta.mKey;
-- offset = meta.mOffset;
-- return true;
--}
--
--void WriteKey(FILE* indexFile, DataKey key, unsigned int offset)
--{
-- KeyMeta meta( key, offset );
--
-- // write the key first
-- fwrite( &meta, KEY_META_SIZE, 1, indexFile );
--}
--
--std::size_t GetHeaderSize()
--{
-- return FILE_HEADER_SIZE;
--}
--} // namespace DataCacheIO
--
--} // namespace SlpPlatform
--
--} // namespace Dali
+++ /dev/null
--#ifndef __DALI_SLP_PLATFORM_DATA_CACHE_IO_H__
--#define __DALI_SLP_PLATFORM_DATA_CACHE_IO_H__
--
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--// INTERNAL INCLUDES
--#include "../../interfaces/data-cache.h"
--
--namespace Dali
--{
--namespace SlpPlatform
--{
--
--/**
-- * Input / Output file routines for the data-cache
-- * This file has no dependency on data-cache-impl.h, just the abstract interface data-cache.h
-- * For future work it would be possible to replace FILE* with a resource handle so that
-- * data-cache-impl would not have to know it is dealing with files.
-- *
-- */
--namespace DataCacheIo
--{
--
--/**
-- * Type of file
-- */
--enum FileType
--{
-- INDEX_FILE, ///< index file
-- DATA_FILE ///< data file
--};
--
--/**
-- * File lock mode
-- */
--enum LockMode
--{
-- LOCK_FILE, ///< lock the file
-- NO_LOCK ///< no lock
--};
--
--/**
-- * File open mode
-- */
--enum FileOpenMode
--{
-- READ_ONLY, ///< read only
-- READ_WRITE ///< read write
--};
--
--/**
-- * File creation mode
-- */
--enum FileCreationMode
--{
-- CREATE_IF_MISSING, ///< create the file if missing
-- DONT_CREATE_IF_MISSING ///< don't create the file if missing
--};
--
--
--/**
-- * Key meta information, holds key offset information for the index file.
-- * Contains plain old data (POD).
-- *
-- * | KEY | OFFSET |
-- */
--struct KeyMeta
--{
-- /**
-- * Constructor
-- */
-- KeyMeta():mKey(0),
-- mOffset(0)
-- {}
-- /**
-- * Constructor
-- */
-- KeyMeta( Dali::Platform::DataCache::DataKey key,
-- unsigned int offset)
-- :mKey(key), mOffset(offset)
-- {}
--
-- Dali::Platform::DataCache::DataKey mKey; ///< Key
-- unsigned int mOffset; ///< Offset
--
--private:
-- // Undefined copy constructor.
-- KeyMeta( const KeyMeta& );
--
-- // Undefined assignment operator.
-- KeyMeta& operator=( const KeyMeta&);
--};
--
--/**
-- * Check the index and data files and repair if required
-- * @param[in] indexFileName index filename
-- * @param[in] dataFileName data filename
-- * @param[in] compressionMode compression mode
-- * @param[in] maxDataSize maximum data size
-- * @param[in] maxNummberEntries maximum number of entries allowed
-- */
--void CheckAndRepairFiles( const std::string& indexFileName,
-- const std::string& dataFileName,
-- Dali::Platform::DataCache::CompressionMode compressionMode,
-- unsigned int maxDataSize,
-- unsigned int maxNummberEntries );
--
--/**
-- * Opens a file.
-- * @param[in] filename file name
-- * @param[in] fileType file type
-- * @param[in] lockMode whether to lock the file or not
-- * @param[in] fileMode whether to open the file for reading or read/writing.
-- * @param[in] creationMode whether to create the file if it's missing or not
-- * @return pointer to a file.
-- */
--FILE* OpenFile(const std::string& fileName,
-- FileType fileType,
-- LockMode lockMode,
-- FileOpenMode fileMode,
-- FileCreationMode creationMode = DONT_CREATE_IF_MISSING);
--
--/**
-- * Erases the contents of both index and data files and writes a new header.
-- * @param[in] indexFile index file
-- * @param[in] dataFile data file
-- * @param[in] compressionMode data compression mode
-- */
--void ReCreateFiles(FILE* indexFile, FILE* dataFile, Dali::Platform::DataCache::CompressionMode compressionMode);
--
--/**
-- * Prepares both index and data file to have data written to.
-- * Internally seeks to the end of both files.
-- * @param[in] indexFile index file
-- * @param[in] dataFile data file
-- */
--void PrepareForWritingData( FILE* dataFile, FILE* indexFile );
--
--
--/**
-- * Writes data to the data file.
-- * @param[in] dataFile data file
-- * @param[in] key the key to write
-- * @param[in] data the data to write
-- * @return the file offset of where the data was written to.
-- */
--unsigned int WriteData( FILE* dataFile,
-- Dali::Platform::DataCache::DataKey key,
-- const Dali::Platform::DataCache::Data& data );
--
--/**
-- * Reads data from the data file.
-- * The size of the data read is held in data.length.
-- * @param[in] dataFile data file
-- * @param[in] offset file offset
-- * @param[in] key the key value, used to ensure the correct data is read
-- * @param[out] data the data.length value is set to the data length.
-- * @param[in] dataBuffer the buffer to read the data into
-- * @param[in] bufferSize the size of the buffer in bytes
-- */
--bool ReadData( FILE* dataFile,
-- unsigned int offset,
-- Dali::Platform::DataCache::DataKey key,
-- Dali::Platform::DataCache::Data& data,
-- unsigned char* dataBuffer,
-- unsigned int bufferSize);
--
--/**
-- * Read the | KEY | OFFSET | entries from the index file.
-- * @param[in] indexFile the index file
-- * @param[out] meta pointer to an array of KeyMeta structures ( KEY | OFFSET ) structs
-- * @param[in] startIndex the index to start reading from
-- * @param[in] count the number of indexes to read
-- * @return true on success, false on failure
-- */
--bool ReadEntries(FILE *indexFile,KeyMeta* meta, unsigned int startIndex, unsigned int count);
--
--/**
-- * Read the number of entries from the index file
-- * @param[in] indexFile the index file
-- * @param[out] numEntries number of entries read
-- * @return true on success, false on failure
-- */
--bool ReadNumberEntries( FILE* indexFile, unsigned int &numEntries );
--
--/**
-- * Write the number of entries
-- * @param[in] indexFile the index file
-- * @param[in] numEntires number of entries
-- */
--void WriteNumberEntries( FILE* indexFile, unsigned int numEntries );
--
--/**
-- * Read a key from the index file
-- * @param[in] indexFile the index file
-- * @param[out] key the key
-- * @param[out] the offset
-- * @return true on success, false on failure
-- */
--bool ReadKey( FILE* indexFile, Dali::Platform::DataCache::DataKey& key, unsigned int& offset );
--
--/**
-- * Write a key to the index file
-- * @param[in] indexFile the index file
-- * @param[in] key the key
-- * @param[in] the offset
-- */
--void WriteKey(FILE* indexFile, Dali::Platform::DataCache::DataKey key, unsigned int offset );
--
--/**
-- * Get the header size
-- * @return the size of the file header
-- */
--std::size_t GetHeaderSize();
--
--} // namespace DataCacheIO
--
--} // namespace SlpPlatform
--
--} // namespace Dali
--
--#endif // __DALI_SLP_PLATFORM_DATA_CACHE_IO_H__
+++ /dev/null
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--// CLASS HEADER
--#include "data-cache-debug.h"
--
--#ifdef DATA_CACHE_DEBUG
--
--// INTERNAL INCLUDES
--#include "../data-cache-io.h"
--#include "../data-compression.h"
--#include <dali/integration-api/debug.h>
--#include <dali/public-api/common/set-wrapper.h>
--
--// EXTERNAL INCLUDES
--#include <boost/thread.hpp>
--
--namespace Dali
--{
--
--namespace SlpPlatform
--{
--
--namespace DataCacheIo
--{
--
--namespace
--{
--const char * const DALI_USER_FONT_CACHE_PATH( DALI_USER_FONT_CACHE_DIR );
--const std::string TEST_FILE("test-file");
--
--const unsigned int NUMBER_TEST_ITERATIONS(25000); ///< number of test iterations to perform per thread
--const bool RANDOM_DATA_SIZE(true); ///< whether to use random data sizes (up to DATA_SIZE)
--const unsigned int MAX_KEY_VALUE(200000); ////< number key index value
--const unsigned int DATA_SIZE(64); ///< maximum data size
--const unsigned int MAX_NUMBER_ENTRIES( 200000 ); ///< Maximum number of entries size
--const unsigned int ENTRIES_TO_READ_WRITE(1); ///< maximum number of entries to read/write in one API call
--const Platform::DataCache::CompressionMode COMPRESSION_MODE( Platform::DataCache::RUN_LENGTH_ENCODING); //or COMPRESSION_OFF );
--
--/**
-- * Fills the key vector with random keys between 0 and MAX_KEY_VALUE
-- */
--void FillVectorWithRandomKeys( Platform::DataCache::KeyVector& keyVector)
--{
-- // make sure if we are setup to write 20 key/data pairs in a single API call
-- // the we have at least 20 unique keys
-- DALI_ASSERT_ALWAYS( MAX_KEY_VALUE > ENTRIES_TO_READ_WRITE);
--
-- // create a set of unique keys, then insert them in to the key vector
-- typedef std::set< Platform::DataCache::DataKey > KeySet;
-- KeySet uniqueKeys;
-- while( uniqueKeys.size() != keyVector.size() )
-- {
-- uniqueKeys.insert( rand() % MAX_KEY_VALUE );
-- }
-- int i(0);
-- for( KeySet::const_iterator iter = uniqueKeys.begin(), endIter = uniqueKeys.end(); iter != endIter; ++iter )
-- {
-- keyVector[i] = (*iter);
-- i++;
-- }
--}
--
--/**
-- * Fill the data vector with random data
-- */
--void FillVectorWithRandomData( Platform::DataCache::DataVector& dataVector)
--{
-- for( unsigned int i = 0; i < dataVector.size(); i++ )
-- {
-- unsigned int length( DATA_SIZE );
-- if( RANDOM_DATA_SIZE )
-- {
-- length = 1 + rand() % DATA_SIZE;
-- }
-- unsigned char* data = new unsigned char[length];
-- dataVector[i].SetData( data, length );
-- }
--}
--
--/**
-- * delete the data vector, and check the exists flag is correct
-- */
--void DeleteData(Platform::DataCache::DataVector& dataVector )
--{
-- for( unsigned int i = 0; i < dataVector.size(); i++ )
-- {
-- Platform::DataCache::Data& data( dataVector[i] );
-- // check the exists flag
-- if (data.data && !data.exists)
-- {
-- DALI_ASSERT_ALWAYS(0 && "data exist flag wrong #1 ");
-- }
-- if (!data.data && data.exists)
-- {
-- DALI_ASSERT_ALWAYS(0 && "data exist flag wrong #2 ");
-- }
-- if (data.data)
-- {
-- delete []data.data;
-- }
-- }
--}
--
--/**
-- * read the number of entries, and get the entry list
-- */
--unsigned int CheckNumberEntries( FILE* indexFile, KeyMeta** keyMeta )
--{
-- unsigned int numberEntries;
--
-- bool ok = ReadNumberEntries( indexFile, numberEntries );
-- if( !ok )
-- {
-- // ReadEntries will log an error
-- DALI_ASSERT_ALWAYS(0);
-- }
-- // Check there is no data after the header, if there are no entries in the index file
-- if( numberEntries == 0 )
-- {
-- if( fgetc( indexFile ) != EOF)
-- {
-- // data index is corrupt, it contains more data than are recorded in numberEntries field
-- DALI_LOG_ERROR("index file has zero entries, but contains data after header\n");
-- DALI_ASSERT_ALWAYS(0);
-- }
-- return 0;
-- }
--
-- // allocate an array of ( key | offset ) structures
-- *keyMeta = new DataCacheIo::KeyMeta[ numberEntries ];
--
-- // read the index table in to memory
-- ok = ReadEntries(indexFile, *keyMeta, 0, numberEntries);
-- if( !ok )
-- {
-- // ReadEntries will log an error
-- DALI_ASSERT_ALWAYS(0);
-- }
-- // check there's no data at the end of the file
-- if( fgetc( indexFile ) != EOF)
-- {
-- // data index is corrupt, it contains more entries than are recorded in numberEntries field
-- DALI_LOG_ERROR("index has more entries than recorded\n");
-- DALI_ASSERT_ALWAYS(0);
-- }
-- return numberEntries;
--}
--
--unsigned int GetMaxDataSizeOnFile( unsigned int dataSize )
--{
-- if( COMPRESSION_MODE == Platform::DataCache::RUN_LENGTH_ENCODING )
-- {
-- return DataCompression::GetMaximumRleCompressedSize( dataSize );
-- }
-- return dataSize;
--}
--
--/**
-- * Checks every single entry in the data file.
-- * This is slow, it should not be performed unless debugging.
-- */
--void FullFileCheck( FILE* indexFile,
-- FILE* dataFile,
-- unsigned int maxDataSize)
--{
-- // Read entries from index file and make sure the file size is correct
-- DataCacheIo::KeyMeta* keyMeta(NULL);
-- unsigned int numberEntries = CheckNumberEntries( indexFile, &keyMeta );
-- unsigned int maxDataSizeOnFile = GetMaxDataSizeOnFile( maxDataSize );
--
-- // Allocate the file buffer for reading the data, and a decode buffer if the data is compressed
-- unsigned char* fileDataBuffer = new unsigned char[ maxDataSizeOnFile ];
-- unsigned char* decodeBuffer = new unsigned char[ maxDataSize ];
--
-- // For each entry, check the data is valid in the
-- unsigned int previousOffset = GetHeaderSize();
--
-- std::set< Dali::Platform::DataCache::DataKey > KeyLookup;
--
-- for(unsigned int i = 0; i < numberEntries; ++i )
-- {
-- Dali::Platform::DataCache::DataKey key( keyMeta[i].mKey );
-- Dali::Platform::DataCache::Data data;
--
-- // check for duplicate keys
-- if( KeyLookup.find(key) != KeyLookup.end() )
-- {
-- printf(" Duplicate Key Found %d \n",key);
-- DALI_ASSERT_ALWAYS(0 );
-- }
-- KeyLookup.insert(key);
--
-- unsigned int offset( keyMeta[i].mOffset);
--
-- // ensure the offset of each entry is correct
-- DALI_ASSERT_ALWAYS( previousOffset == offset);
--
-- bool ok = ReadData( dataFile, offset, key, data, fileDataBuffer, maxDataSizeOnFile );
-- if( !ok )
-- {
-- DALI_ASSERT_ALWAYS(0 && "DataCacheIO::ReadData failed");
-- }
--
-- unsigned int dataLengthOnFile = data.length;
--
-- if( COMPRESSION_MODE == Platform::DataCache::RUN_LENGTH_ENCODING )
-- {
-- // try and de-compress it
-- std::size_t decodedSize;
-- bool ok = DataCompression::DecodeRle( fileDataBuffer, data.length, decodeBuffer, maxDataSize, decodedSize);
-- DALI_ASSERT_ALWAYS( ok && " DataCompression::DecodeRle failed");
-- data.length = decodedSize;
-- }
--
-- // un-comment for list of key / data entries
-- // printf(" key = %d, length = %d \n",key,data.length);
-- previousOffset = offset + dataLengthOnFile + 8; /* 8 = key + length field */
-- }
-- delete []keyMeta;
-- delete []decodeBuffer;
-- delete []fileDataBuffer;
--}
--
--void ClearTestFiles( const std::string& indexFileName, const std::string& dataFileName )
--{
-- FILE* dataFile = DataCacheIo::OpenFile( dataFileName, DataCacheIo::DATA_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_WRITE, DataCacheIo::CREATE_IF_MISSING );
-- FILE* indexFile = DataCacheIo::OpenFile( indexFileName, DataCacheIo::INDEX_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_WRITE, DataCacheIo::CREATE_IF_MISSING);
--
-- ReCreateFiles( indexFile, dataFile, COMPRESSION_MODE);
--
-- fclose( dataFile );
-- fclose( indexFile );
--}
--
--} // unnamed name space
--
--void DataCacheStressTest(void)
--{
-- printf("thread started \n");
--
-- static unsigned int apiCalls(0);
-- std::string path(DALI_USER_FONT_CACHE_PATH);
-- std::string file = path + TEST_FILE ;
--
-- Platform::DataCache* cache = Platform::DataCache::New( Platform::DataCache::READ_WRITE,
-- COMPRESSION_MODE,
-- file,
-- DATA_SIZE,
-- MAX_NUMBER_ENTRIES);
--
--
-- for(unsigned int i = 0; i < NUMBER_TEST_ITERATIONS; ++i )
-- {
-- apiCalls+=2;
-- if( i%50 == 0)
-- {
-- printf("DataCache Add() & Find() calls: %d \r",apiCalls);
-- }
--
-- // Read a random array of key/data pairs
-- Platform::DataCache::KeyVector keyVector;
-- Platform::DataCache::DataVector dataVector;
--
-- unsigned int arraySize = ENTRIES_TO_READ_WRITE;
-- keyVector.resize( arraySize );
--
-- // read a random entry
-- FillVectorWithRandomKeys( keyVector );
-- cache->Find( keyVector, dataVector);
-- DeleteData( dataVector);
--
-- // Write a random entry
-- FillVectorWithRandomKeys( keyVector );
-- FillVectorWithRandomData( dataVector );
-- cache->Add( keyVector, dataVector );
-- DeleteData(dataVector);
-- }
-- delete cache;
--}
--
--void ThreadedStressTest()
--{
-- // only allow test to run once
-- static int done(false);
-- if( done )
-- {
-- return;
-- }
-- done = true;
--
-- std::string path(DALI_USER_FONT_CACHE_PATH);
-- std::string dataFileName = path + TEST_FILE + ".data";
-- std::string indexFileName = path + TEST_FILE + ".index";
--
-- // Make sure the data files are empty to start with
-- ClearTestFiles( indexFileName , dataFileName);
--
--
-- printf("____ DataCache Multi Thread Test Starting ____ \n");
--
-- boost::thread t1(DataCacheStressTest);
-- boost::thread t2(DataCacheStressTest);
-- boost::thread t3(DataCacheStressTest);
-- boost::thread t4(DataCacheStressTest);
-- boost::thread t5(DataCacheStressTest);
-- boost::thread t6(DataCacheStressTest);
-- boost::thread t7(DataCacheStressTest);
-- boost::thread t8(DataCacheStressTest);
--
-- t1.join();
-- t2.join();
-- t3.join();
-- t4.join();
-- t5.join();
-- t6.join();
-- t7.join();
-- t8.join();
--
-- // Check the data that was written is not corrupt
--
-- FILE* dataFile = OpenFile( dataFileName, DataCacheIo::DATA_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_ONLY );
-- FILE* indexFile = OpenFile( indexFileName, DataCacheIo::INDEX_FILE, DataCacheIo::NO_LOCK, DataCacheIo::READ_ONLY );
--
-- FullFileCheck( indexFile, dataFile, DATA_SIZE );
--
-- fclose( dataFile );
-- fclose( indexFile );
--
-- printf("____ DataCache Multi Thread Test PASSED ____ \n");
--}
--
--} // namespace DataCacheIO
--
--} // namespace SlpPlatform
--
--} // namespace Dali
--#endif // #ifdef DATA_CACHE_DEBUG
+++ /dev/null
--#ifndef __DALI_SLP_PLATFORM_DATA_CACHE_DEBUG_H__
--#define __DALI_SLP_PLATFORM_DATA_CACHE_DEBUG_H__
--
--/*
-- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
-- *
-- * Licensed under the Apache License, Version 2.0 (the "License");
-- * you may not use this file except in compliance with the License.
-- * You may obtain a copy of the License at
-- *
-- * http://www.apache.org/licenses/LICENSE-2.0
-- *
-- * Unless required by applicable law or agreed to in writing, software
-- * distributed under the License is distributed on an "AS IS" BASIS,
-- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- * See the License for the specific language governing permissions and
-- * limitations under the License.
-- *
-- */
--
--//#define DATA_CACHE_DEBUG // un-comment to enable
--#ifdef DATA_CACHE_DEBUG
--
--namespace Dali
--{
--namespace SlpPlatform
--{
--namespace DataCacheIo
--{
--
--/**
-- * Threading stress test.
-- * Launches a 8 of threads to read / write to the simultaneously to a single data cache.
-- * Each thread reads/writes a number of entries, using random keys and random data.
-- * When it has completed, a concise check of all data is made to detect any errors.
-- *
-- */
--void ThreadedStressTest();
--
--} // namespace DataCacheIO
--
--} // namespace SlpPlatform
--
--} // namespace Dali
--
--#endif // __DALI_SLP_PLATFORM_DATA_CACHE_DEBUG_H__
--#endif // #ifdef DATA_CACHE_DEBUG
$(slp_platform_abstraction_src_dir)/slp-platform-abstraction.cpp \
$(slp_platform_abstraction_src_dir)/slp-logging.cpp \
$(slp_platform_abstraction_src_dir)/slp-font-configuration-parser.cpp \
- $(slp_platform_abstraction_src_dir)/font-platform/font-controller-impl.cpp \
-- $(slp_platform_abstraction_src_dir)/data-cache/data-cache-io.cpp \
-- $(slp_platform_abstraction_src_dir)/data-cache/data-cache-impl.cpp \
-- $(slp_platform_abstraction_src_dir)/data-cache/tests/data-cache-debug.cpp \
-- $(slp_platform_abstraction_src_dir)/data-cache/data-compression.cpp \
- $(slp_platform_abstraction_src_dir)/data-cache/metrics-cache.cpp \
$(slp_platform_abstraction_src_dir)/dynamics/dynamics-factory.cpp \
\
- $(slp_platform_abstraction_src_dir)/resource-loader/loader-font.cpp \
$(slp_platform_abstraction_src_dir)/resource-loader/resource-loader.cpp \
$(slp_platform_abstraction_src_dir)/resource-loader/resource-requester-base.cpp \
$(slp_platform_abstraction_src_dir)/resource-loader/resource-bitmap-requester.cpp \
- $(slp_platform_abstraction_src_dir)/resource-loader/resource-model-requester.cpp \
$(slp_platform_abstraction_src_dir)/resource-loader/resource-shader-requester.cpp \
- $(slp_platform_abstraction_src_dir)/resource-loader/resource-text-requester.cpp \
\
$(slp_platform_abstraction_src_dir)/resource-loader/resource-thread-base.cpp \
$(slp_platform_abstraction_src_dir)/resource-loader/resource-thread-image.cpp \
- $(slp_platform_abstraction_src_dir)/resource-loader/resource-thread-model.cpp \
$(slp_platform_abstraction_src_dir)/resource-loader/resource-thread-shader.cpp \
- $(slp_platform_abstraction_src_dir)/resource-loader/resource-thread-text.cpp \
\
- $(slp_platform_abstraction_src_dir)/resource-loader/binary-model-builder.cpp \
\
$(slp_platform_abstraction_src_dir)/resource-loader/debug/resource-loader-debug.cpp \
\
#include <dali/public-api/common/scoped-pointer.h>
#include "resource-requester-base.h"
#include "resource-bitmap-requester.h"
- #include "resource-model-requester.h"
#include "resource-shader-requester.h"
-#include "resource-text-requester.h"
#include "debug/resource-loader-debug.h"
-#include "loader-font.h"
-#include "../interfaces/font-controller.h"
--#include "../interfaces/data-cache.h"
/**
ResourceLoaderImpl( ResourceLoader* loader )
{
- mFontController = Dali::Platform::FontController::New();
-
mRequestHandlers.insert(std::make_pair(ResourceBitmap, new ResourceBitmapRequester(*loader)));
mRequestHandlers.insert(std::make_pair(ResourceShader, new ResourceShaderRequester(*loader)));
- mRequestHandlers.insert(std::make_pair(ResourceModel, new ResourceModelRequester(*loader)));
- mRequestHandlers.insert(std::make_pair(ResourceText, new ResourceTextRequester(*loader)));
}
~ResourceLoaderImpl()
--- /dev/null
- BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text-abstraction/font-client-impl.h>
+
+// INTERNAL INCLUDES
+#include <singleton-service.h>
+#include <dali/internal/text-abstraction/font-client-plugin-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+FontClient::FontClient()
+: mPlugin( NULL ),
+ mDpiHorizontal( 0 ),
+ mDpiVertical( 0 )
+{
+}
+
+FontClient::~FontClient()
+{
+ delete mPlugin;
+}
+
+Dali::TextAbstraction::FontClient FontClient::Get()
+{
+ Dali::TextAbstraction::FontClient fontClientHandle;
+
+ Dali::SingletonService service( SingletonService::Get() );
+ if ( service )
+ {
+ // Check whether the singleton is already created
+ Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
+ if(handle)
+ {
+ // If so, downcast the handle
+ FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
+ fontClientHandle = Dali::TextAbstraction::FontClient( impl );
+ }
+ else // create and register the object
+ {
+ fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
+ service.Register( typeid( fontClientHandle ), fontClientHandle );
+ }
+ }
+
+ return fontClientHandle;
+}
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
+{
+ mDpiHorizontal = horizontalDpi;
+ mDpiVertical = verticalDpi;
+
+ // Allow DPI to be set without loading plugin
+ if( mPlugin )
+ {
+ mPlugin->SetDpi( horizontalDpi, verticalDpi );
+ }
+}
+
+void FontClient::SetDefaultFontFamily( const std::string& fontFamilyName,
+ const std::string& fontStyle )
+{
+ CreatePlugin();
+
+ mPlugin->SetDefaultFontFamily( fontFamilyName, fontStyle );
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+ CreatePlugin();
+
+ mPlugin->GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+ CreatePlugin();
+
+ mPlugin->GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+ CreatePlugin();
+
+ return mPlugin->GetPointSize( id );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+ CreatePlugin();
+
+ mPlugin->GetSystemFonts( systemFonts );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode, PointSize26Dot6 pointSize )
+{
+ CreatePlugin();
+
+ return mPlugin->FindDefaultFont( charcode, pointSize );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+ CreatePlugin();
+
+ return mPlugin->IsScalable( path );
+}
+
+bool FontClient::IsScalable( const FontFamily& fontFamily, const FontStyle& style )
+{
+ CreatePlugin();
+
+ return mPlugin->IsScalable( fontFamily, style );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+ CreatePlugin();
+
+ mPlugin->GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontFamily& fontFamily,
+ const FontStyle& style,
+ Dali::Vector< PointSize26Dot6 >& sizes )
+{
+ CreatePlugin();
+
+ mPlugin->GetFixedSizes( fontFamily, style, sizes );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+{
+ CreatePlugin();
+
+ return mPlugin->GetFontId( path, pointSize, faceIndex );
+}
+
+FontId FontClient::GetFontId( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex )
+{
+ CreatePlugin();
+
+ return mPlugin->GetFontId( fontFamily,
+ fontStyle,
+ pointSize,
+ faceIndex );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
+{
+ CreatePlugin();
+
+ return mPlugin->GetFontMetrics( fontId, metrics );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+ CreatePlugin();
+
+ return mPlugin->GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
+{
+ CreatePlugin();
+
+ return mPlugin->GetGlyphMetrics( array, size, horizontal );
+}
+
++BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+{
+ CreatePlugin();
+
+ return mPlugin->CreateBitmap( fontId, glyphIndex );
+}
+
+void FontClient::CreatePlugin()
+{
+ if( !mPlugin )
+ {
+ mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
+ }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
--- /dev/null
- BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/text-abstraction/font-client.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the FontClient
+ */
+class FontClient : public BaseObject
+{
+public:
+
+ /**
+ * Constructor
+ */
+ FontClient();
+
+ /**
+ * Destructor
+ */
+ ~FontClient();
+
+ /**
+ * @copydoc Dali::FontClient::Get()
+ */
+ static Dali::TextAbstraction::FontClient Get();
+
+ /**
+ * @copydoc Dali::FontClient::SetDpi()
+ */
+ void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+ /**
+ * @copydoc Dali::FontClient::SetDefaultFontFamily()
+ */
+ void SetDefaultFontFamily( const std::string& fontFamilyName,
+ const std::string& fontStyle );
+
+ /**
+ * @copydoc Dali::FontClient::GetDefaultFonts()
+ */
+ void GetDefaultFonts( FontList& defaultFonts );
+
+ /**
+ * @copydoc Dali::FontClient::GetSystemFonts()
+ */
+ void GetSystemFonts( FontList& systemFonts );
+
+ /**
+ * @copydoc Dali::FontClient::GetDescription()
+ */
+ void GetDescription( FontId id, FontDescription& fontDescription );
+
+ /**
+ * @copydoc Dali::FontClient::GetPointSize()
+ */
+ PointSize26Dot6 GetPointSize( FontId id );
+
+ /**
+ * @copydoc Dali::FontClient::FindDefaultFont()
+ */
+ FontId FindDefaultFont( Character charcode, PointSize26Dot6 pointSize );
+
+ /**
+ * @copydoc Dali::FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+ */
+ FontId GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex );
+
+ /**
+ * @copydoc Dali::FontClient::GetFontId(const FontFamily& fontFamily, const FontStyle& fontStyle, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+ */
+ FontId GetFontId( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex );
+
+ /**
+ * @copydoc Dali::FontClient::IsScalable(const FontPath& path )
+ */
+ bool IsScalable( const FontPath& path );
+
+ /**
+ * @copydoc Dali::FontClient::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
+ */
+ bool IsScalable( const FontFamily& fontFamily, const FontStyle& style );
+
+ /**
+ * @copydoc Dali::FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+ */
+ void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+ /**
+ * @copydoc Dali::FontClient::GetFixedSizes( const FontFamily& fontFamily, const FontStyle& fontStyle, Dali::Vector< PointSize26Dot6>& sizes )
+ */
+ void GetFixedSizes( const FontFamily& fontFamily,
+ const FontStyle& style,
+ Dali::Vector< PointSize26Dot6 >& sizes );
+
+ /**
+ * @copydoc Dali::FontClient::GetFontMetrics()
+ */
+ void GetFontMetrics( FontId fontId, FontMetrics& metrics );
+
+ /**
+ * @copydoc Dali::FontClient::GetGlyphIndex()
+ */
+ GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+ /**
+ * @copydoc Dali::FontClient::CreateMetrics()
+ */
+ bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal );
+
+ /**
+ * @copydoc Dali::FontClient::CreateBitmap()
+ */
++ BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+
+private:
+
+ /**
+ * Helper for lazy initialization.
+ */
+ void CreatePlugin();
+
+ // Undefined copy constructor.
+ FontClient( const FontClient& );
+
+ // Undefined assignment constructor.
+ FontClient& operator=( FontClient& );
+
+private:
+
+ struct Plugin;
+ Plugin* mPlugin;
+
+ // Allows DPI to be set without loading plugin
+ unsigned int mDpiHorizontal;
+ unsigned int mDpiVertical;
+
+}; // class FontClient
+
+} // namespace Internal
+
+inline static Internal::FontClient& GetImplementation(FontClient& fontClient)
+{
+ DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+ BaseObject& handle = fontClient.GetBaseObject();
+ return static_cast<Internal::FontClient&>(handle);
+}
+
+inline static const Internal::FontClient& GetImplementation(const FontClient& fontClient)
+{
+ DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+ const BaseObject& handle = fontClient.GetBaseObject();
+ return static_cast<const Internal::FontClient&>(handle);
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H__
--- /dev/null
- BitmapImage FontClient::Plugin::CreateBitmap( FontId fontId,
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text-abstraction/font-client-plugin-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/text-abstraction/glyph-info.h>
+#include <dali/integration-api/debug.h>
+
+// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
+
+/**
+ * Conversion from Fractional26.6 to float
+ */
+namespace
+{
+const float FROM_266 = 1.0f / 64.0f;
+
+const std::string FONT_FORMAT( "TrueType" );
+const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
+const std::string DEFAULT_FONT_STYLE( "Regular" );
+}
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+const bool FONT_FIXED_SIZE_BITMAP( true );
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ FontDescriptionId index )
+: fontFamily( fontFamily ),
+ fontStyle( fontStyle ),
+ index( index )
+{}
+
+FontClient::Plugin::FontIdCacheItem::FontIdCacheItem( FontDescriptionId validatedFontId,
+ PointSize26Dot6 pointSize,
+ FontId fontId )
+: validatedFontId( validatedFontId ),
+ pointSize( pointSize ),
+ fontId( fontId )
+{}
+
+FontClient::Plugin::CacheItem::CacheItem( FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 pointSize,
+ FaceIndex face,
+ const FontMetrics& metrics,
+ bool isFixedSizeBitmap )
+: mFreeTypeFace( ftFace ),
+ mPath( path ),
+ mPointSize( pointSize ),
+ mFaceIndex( face ),
+ mMetrics( metrics ),
+ mIsFixedSizeBitmap( isFixedSizeBitmap )
+{}
+
+FontClient::Plugin::Plugin( unsigned int horizontalDpi,
+ unsigned int verticalDpi )
+: mFreeTypeLibrary( NULL ),
+ mDpiHorizontal( horizontalDpi ),
+ mDpiVertical( verticalDpi ),
+ mSystemFonts(),
+ mDefaultFonts(),
+ mFontCache(),
+ mValidatedFontCache(),
+ mFontDescriptionCache( 1u ),
+ mFontIdCache()
+{
+ int error = FT_Init_FreeType( &mFreeTypeLibrary );
+ if( FT_Err_Ok != error )
+ {
+ DALI_LOG_ERROR( "FreeType Init error: %d\n", error );
+ }
+}
+
+FontClient::Plugin::~Plugin()
+{
+ FT_Done_FreeType( mFreeTypeLibrary );
+}
+
+void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
+ unsigned int verticalDpi )
+{
+ mDpiHorizontal = horizontalDpi;
+ mDpiVertical = verticalDpi;
+}
+
+void FontClient::Plugin::SetDefaultFontFamily( const FontFamily& fontFamilyName,
+ const FontStyle& fontStyle )
+{
+ mDefaultFonts.clear();
+
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamilyName,
+ fontStyle );
+
+ FcResult result = FcResultMatch;
+
+ // Match the pattern.
+ FcFontSet* fontSet = FcFontSort( NULL /* use default configure */,
+ fontFamilyPattern,
+ false /* don't trim */,
+ NULL,
+ &result );
+
+ if( NULL != fontSet )
+ {
+ // Reserve some space to avoid reallocations.
+ mDefaultFonts.reserve( fontSet->nfont );
+
+ for( int i = 0u; i < fontSet->nfont; ++i )
+ {
+ FcPattern* fontPattern = fontSet->fonts[i];
+
+ FontPath path;
+
+ // Skip fonts with no path
+ if( GetFcString( fontPattern, FC_FILE, path ) )
+ {
+ mDefaultFonts.push_back( FontDescription() );
+ FontDescription& fontDescription = mDefaultFonts.back();
+
+ fontDescription.path = path;
+
+ GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
+ GetFcString( fontPattern, FC_STYLE, fontDescription.style );
+ }
+ }
+
+ FcFontSetDestroy( fontSet );
+ }
+
+ FcPatternDestroy( fontFamilyPattern );
+}
+
+void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
+{
+ if( mDefaultFonts.empty() )
+ {
+ SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
+ DEFAULT_FONT_STYLE );
+ }
+
+ defaultFonts = mDefaultFonts;
+}
+
+void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
+{
+ if( mSystemFonts.empty() )
+ {
+ InitSystemFonts();
+ }
+
+ systemFonts = mSystemFonts;
+}
+
+void FontClient::Plugin::GetDescription( FontId id,
+ FontDescription& fontDescription ) const
+{
+ for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
+ endIt = mFontIdCache.end();
+ it != endIt;
+ ++it )
+ {
+ const FontIdCacheItem& item = *it;
+
+ if( item.fontId == id )
+ {
+ fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId );
+ return;
+ }
+ }
+
+ DALI_LOG_ERROR( "FontClient::Plugin::GetDescription. No description found for the font ID %d\n", id );
+}
+
+PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
+{
+ const FontId index = id - 1u;
+
+ if( id > 0u &&
+ index < mFontCache.size() )
+ {
+ return ( *( mFontCache.begin() + index ) ).mPointSize;
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FontClient::Plugin::GetPointSize. Invalid font ID %d\n", id );
+ }
+
+ return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+}
+
+FontId FontClient::Plugin::FindDefaultFont( Character charcode,
+ PointSize26Dot6 pointSize )
+{
+ // Create the list of default fonts if it has not been created.
+ if( mDefaultFonts.empty() )
+ {
+ SetDefaultFontFamily( DEFAULT_FONT_FAMILY_NAME,
+ DEFAULT_FONT_STYLE );
+ }
+
+ // Traverse the list of default fonts.
+ // Check for each default font if supports the character.
+
+ for( FontList::const_iterator it = mDefaultFonts.begin(),
+ endIt = mDefaultFonts.end();
+ it != endIt;
+ ++it )
+ {
+ const FontDescription& description = *it;
+
+ FcPattern* pattern = CreateFontFamilyPattern( description.family,
+ description.style );
+
+ FcResult result = FcResultMatch;
+ FcPattern* match = FcFontMatch( NULL /* use default configure */, pattern, &result );
+
+ FcCharSet* charSet = NULL;
+ FcPatternGetCharSet( match, FC_CHARSET, 0u, &charSet );
+
+ if( FcCharSetHasChar( charSet, charcode ) )
+ {
+ return GetFontId( description.family,
+ description.style,
+ pointSize,
+ 0u );
+ }
+ }
+
+ return 0u;
+}
+
+FontId FontClient::Plugin::GetFontId( const FontPath& path,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex,
+ bool cacheDescription )
+{
+ FontId id( 0 );
+
+ if( NULL != mFreeTypeLibrary )
+ {
+ FontId foundId(0);
+ if( FindFont( path, pointSize, faceIndex, foundId ) )
+ {
+ id = foundId;
+ }
+ else
+ {
+ id = CreateFont( path, pointSize, faceIndex, cacheDescription );
+ }
+ }
+
+ return id;
+}
+
+FontId FontClient::Plugin::GetFontId( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex )
+{
+ // This method uses three vectors which caches:
+ // * Pairs of non validated 'fontFamily, fontStyle' and an index to a vector with paths to font file names.
+ // * The path to font file names.
+ // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
+
+ // 1) Checks in the cache if the pair 'fontFamily, fontStyle' has been validated before.
+ // If it was it gets an index to the vector with paths to font file names. Otherwise,
+ // retrieves using font config a path to a font file name which matches with the pair
+ // 'fontFamily, fontStyle'. The path is stored in the chache.
+ //
+ // 2) Checks in the cache if the pair 'font point size, index to the vector with paths to
+ // fon file names' exists. If exists, it gets the font id. If it doesn't it calls
+ // the GetFontId() method with the path to the font file name and the point size to
+ // get the font id.
+
+ // The font id to be returned.
+ FontId fontId = 0u;
+
+ // Check first if the pair font family and style have been validated before.
+ FontDescriptionId validatedFontId = 0u;
+
+ if( !FindValidatedFont( fontFamily,
+ fontStyle,
+ validatedFontId ) )
+ {
+ // Use font config to validate the font family name and font style.
+ ValidateFont( fontFamily, fontStyle, validatedFontId );
+ }
+
+ // Check if exists a pair 'validatedFontId, pointSize' in the cache.
+ if( !FindFont( validatedFontId, pointSize, fontId ) )
+ {
+ // Retrieve the font file name path.
+ const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId );
+
+ // Retrieve the font id. Do not cache the description as it has been already cached.
+ fontId = GetFontId( description.path,
+ pointSize,
+ faceIndex,
+ false );
+
+ // Cache the pair 'validatedFontId, pointSize' to improve the following queries.
+ mFontIdCache.push_back( FontIdCacheItem( validatedFontId,
+ pointSize,
+ fontId ) );
+ }
+
+ return fontId;
+}
+
+void FontClient::Plugin::ValidateFont( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ FontDescriptionId& validatedFontId )
+{
+ // Create a font pattern.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
+ fontStyle );
+
+ FcResult result = FcResultMatch;
+
+ // match the pattern
+ FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+
+ if( match )
+ {
+ // Get the path to the font file name.
+ FontDescription description;
+ GetFcString( match, FC_FILE, description.path );
+ GetFcString( match, FC_FAMILY, description.family );
+ GetFcString( match, FC_STYLE, description.style );
+
+ // Set the index to the vector of paths to font file names.
+ validatedFontId = mFontDescriptionCache.size();
+
+ // Add the path to the cache.
+ mFontDescriptionCache.push_back( description );
+
+ // Cache the index and the pair font family name, font style.
+ FontDescriptionCacheItem item( fontFamily, fontStyle, validatedFontId );
+ mValidatedFontCache.push_back( item );
+
+ // destroyed the matched pattern
+ FcPatternDestroy( match );
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FontClient::Plugin::ValidateFont failed for font %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
+ }
+
+ // destroy the pattern
+ FcPatternDestroy( fontFamilyPattern );
+}
+
+
+
+void FontClient::Plugin::GetFontMetrics( FontId fontId,
+ FontMetrics& metrics )
+{
+ if( fontId > 0 &&
+ fontId-1 < mFontCache.size() )
+ {
+ metrics = mFontCache[fontId-1].mMetrics;
+ }
+ else
+ {
+ DALI_LOG_ERROR( "Invalid font ID %d\n", fontId );
+ }
+}
+
+GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
+ Character charcode )
+{
+ GlyphIndex index( 0 );
+
+ if( fontId > 0 &&
+ fontId-1 < mFontCache.size() )
+ {
+ FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+
+ index = FT_Get_Char_Index( ftFace, charcode );
+ }
+
+ return index;
+}
+
+bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
+ uint32_t size,
+ bool horizontal )
+{
+ bool success( true );
+
+ for( unsigned int i=0; i<size; ++i )
+ {
+ FontId fontId = array[i].fontId;
+
+ if( fontId > 0 &&
+ fontId-1 < mFontCache.size() )
+ {
+ FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+
+ // Check to see if we should be loading a Fixed Size bitmap?
+ if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
+ {
+ int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_COLOR );
+ if ( FT_Err_Ok == error )
+ {
+ // TODO passing height for metrics, should store width, height and advance
+
+ float height = mFontCache[ fontId -1 ].mMetrics.height;
+ array[i].width = height;
+ array[i].height = height;
+ array[i].advance = height;
+ array[i].xBearing = 0.0f;
+ array[i].yBearing = 0.0f;
+ return success;
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FreeType Bitmap Load_Glyph error %d\n", error );
+ return false;
+ }
+ }
+
+ int error = FT_Load_Glyph( ftFace, array[i].index, FT_LOAD_DEFAULT );
+
+ if( FT_Err_Ok == error )
+ {
+ array[i].width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
+ array[i].height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266 ;
+ if( horizontal )
+ {
+ array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
+ array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
+ array[i].advance = static_cast< float >( ftFace->glyph->metrics.horiAdvance ) * FROM_266;
+ }
+ else
+ {
+ array[i].xBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
+ array[i].yBearing = static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
+ array[i].advance = static_cast< float >( ftFace->glyph->metrics.vertAdvance ) * FROM_266;
+ }
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else
+ {
+ success = false;
+ }
+ }
+
+ return success;
+}
+
- BitmapImage bitmap;
++BufferImage FontClient::Plugin::CreateBitmap( FontId fontId,
+ GlyphIndex glyphIndex )
+{
- void FontClient::Plugin::ConvertBitmap( BitmapImage& destBitmap,
++ BufferImage bitmap;
+
+ if( fontId > 0 &&
+ fontId-1 < mFontCache.size() )
+ {
+ FT_Face ftFace = mFontCache[fontId-1].mFreeTypeFace;
+
+ FT_Error error;
+
+ // Check to see if this is fixed size bitmap
+ if ( mFontCache[fontId-1].mIsFixedSizeBitmap )
+ {
+ error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
+ }
+ else
+ {
+ error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_DEFAULT );
+ }
+ if( FT_Err_Ok == error )
+ {
+ FT_Glyph glyph;
+ error = FT_Get_Glyph( ftFace->glyph, &glyph );
+
+ // Convert to bitmap if necessary
+ if ( FT_Err_Ok == error )
+ {
+ if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
+ {
+ error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
+ if ( FT_Err_Ok == error )
+ {
+ FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
+ ConvertBitmap( bitmap, bitmapGlyph->bitmap );
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FT_Get_Glyph Failed with error: %d\n", error );
+ }
+ }
+ else
+ {
+ ConvertBitmap( bitmap, ftFace->glyph->bitmap );
+ }
+
+ // Created FT_Glyph object must be released with FT_Done_Glyph
+ FT_Done_Glyph( glyph );
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FT_Load_Glyph Failed with error: %d\n", error );
+ }
+ }
+
+ return bitmap;
+}
+
+void FontClient::Plugin::InitSystemFonts()
+{
+ FcFontSet* fontSet = GetFcFontSet();
+
+ if( fontSet )
+ {
+ // Reserve some space to avoid reallocations.
+ mSystemFonts.reserve( fontSet->nfont );
+
+ for( int i = 0u; i < fontSet->nfont; ++i )
+ {
+ FcPattern* fontPattern = fontSet->fonts[i];
+
+ FontPath path;
+
+ // Skip fonts with no path
+ if( GetFcString( fontPattern, FC_FILE, path ) )
+ {
+ mSystemFonts.push_back( FontDescription() );
+ FontDescription& fontDescription = mSystemFonts.back();
+
+ fontDescription.path = path;
+
+ GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
+ GetFcString( fontPattern, FC_STYLE, fontDescription.style );
+ }
+ }
+
+ FcFontSetDestroy( fontSet );
+ }
+}
+
+FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontFamily& fontFamily,
+ const FontStyle& fontStyle )
+{
+ // create the cached font family lookup pattern
+ // a pattern holds a set of names, each name refers to a property of the font
+ FcPattern* fontFamilyPattern = FcPatternCreate();
+
+ // add a property to the pattern for the font family
+ FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontFamily.c_str() ) );
+
+ // add a property to the pattern for the font family
+ FcPatternAddString( fontFamilyPattern, FC_STYLE, reinterpret_cast<const FcChar8*>( fontStyle.c_str() ) );
+
+ // Add a property of the pattern, to say we want to match TrueType fonts
+ FcPatternAddString( fontFamilyPattern , FC_FONTFORMAT, reinterpret_cast<const FcChar8*>( FONT_FORMAT.c_str() ) );
+
+ // modify the config, with the mFontFamilyPatterm
+ FcConfigSubstitute( NULL /* use default configure */, fontFamilyPattern, FcMatchPattern );
+
+ // provide default values for unspecified properties in the font pattern
+ // e.g. patterns without a specified style or weight are set to Medium
+ FcDefaultSubstitute( fontFamilyPattern );
+
+ return fontFamilyPattern;
+}
+
+_FcFontSet* FontClient::Plugin::GetFcFontSet() const
+{
+ // create a new pattern.
+ // a pattern holds a set of names, each name refers to a property of the font
+ FcPattern* pattern = FcPatternCreate();
+
+ // create an object set used to define which properties are to be returned in the patterns from FcFontList.
+ FcObjectSet* objectSet = FcObjectSetCreate();
+
+ // build an object set from a list of property names
+ FcObjectSetAdd( objectSet, FC_FILE );
+ FcObjectSetAdd( objectSet, FC_FAMILY );
+ FcObjectSetAdd( objectSet, FC_STYLE );
+
+ // get a list of fonts
+ // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
+ FcFontSet* fontset = FcFontList( NULL /* the default configuration is checked to be up to date, and used */, pattern, objectSet );
+
+ // clear up the object set
+ if( objectSet )
+ {
+ FcObjectSetDestroy( objectSet );
+ }
+ // clear up the pattern
+ if( pattern )
+ {
+ FcPatternDestroy( pattern );
+ }
+
+ return fontset;
+}
+
+bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
+ const char* const n,
+ std::string& string )
+{
+ FcChar8* file = NULL;
+ const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
+
+ if( FcResultMatch == retVal )
+ {
+ // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
+ string.assign( reinterpret_cast<const char*>( file ) );
+
+ return true;
+ }
+
+ return false;
+}
+
+FontId FontClient::Plugin::CreateFont( const FontPath& path,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex,
+ bool cacheDescription )
+{
+ FontId id( 0 );
+
+ // Create & cache new font face
+ FT_Face ftFace;
+ int error = FT_New_Face( mFreeTypeLibrary,
+ path.c_str(),
+ 0,
+ &ftFace );
+
+ if( FT_Err_Ok == error )
+ {
+ // Check to see if the font contains fixed sizes?
+ if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
+ {
+ // Ensure this size is available
+ for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+ {
+ if ( pointSize == ftFace->available_sizes[ i ].size )
+ {
+ // Tell Freetype to use this size
+ error = FT_Select_Size( ftFace, i );
+ if ( FT_Err_Ok != error )
+ {
+ DALI_LOG_ERROR( "FreeType Select_Size error: %d\n", error );
+ }
+ else
+ {
+ // Indicate that the font is a fixed sized bitmap
+ FontMetrics metrics( 0.0f,
+ 0.0f,
+ static_cast< float >( ftFace->available_sizes[ i ].height ) );
+
+ mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics, FONT_FIXED_SIZE_BITMAP ) );
+ id = mFontCache.size();
+
+ if( cacheDescription )
+ {
+ FontDescription description;
+ description.path = path;
+ description.family = FontFamily( ftFace->family_name );
+ description.style = FontStyle( ftFace->style_name );
+
+ mFontDescriptionCache.push_back( description );
+ }
+ return id;
+ }
+ }
+ }
+
+ // Can't find this size
+ std::stringstream sizes;
+ for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+ {
+ if ( i )
+ {
+ sizes << ", ";
+ }
+ sizes << ftFace->available_sizes[ i ].size;
+ }
+ DALI_LOG_ERROR( "FreeType Font: %s, does not contain Bitmaps of size: %d. Available sizes are: %s\n",
+ path.c_str(), pointSize, sizes.str().c_str() );
+ }
+ else
+ {
+ error = FT_Set_Char_Size( ftFace,
+ 0,
+ pointSize,
+ mDpiHorizontal,
+ mDpiVertical );
+
+ if( FT_Err_Ok == error )
+ {
+
+ FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
+
+ FontMetrics metrics( static_cast< float >( ftMetrics.ascender ) * FROM_266,
+ static_cast< float >( ftMetrics.descender ) * FROM_266,
+ static_cast< float >( ftMetrics.height ) * FROM_266 );
+
+ mFontCache.push_back( CacheItem( ftFace, path, pointSize, faceIndex, metrics ) );
+ id = mFontCache.size();
+
+ if( cacheDescription )
+ {
+ FontDescription description;
+ description.path = path;
+ description.family = FontFamily( ftFace->family_name );
+ description.style = FontStyle( ftFace->style_name );
+
+ mFontDescriptionCache.push_back( description );
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FreeType Set_Char_Size error: %d for pointSize %d\n", error, pointSize );
+ }
+ }
+ }
+ else
+ {
+ DALI_LOG_ERROR( "FreeType New_Face error: %d for %s\n", error, path.c_str() );
+ }
+
+ return id;
+}
+
- destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
++void FontClient::Plugin::ConvertBitmap( BufferImage& destBitmap,
+ FT_Bitmap srcBitmap )
+{
+ if( srcBitmap.width*srcBitmap.rows > 0 )
+ {
+ switch( srcBitmap.pixel_mode )
+ {
+ case FT_PIXEL_MODE_GRAY:
+ {
+ if( srcBitmap.pitch == static_cast< int >( srcBitmap.width ) )
+ {
- destBitmap = BitmapImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
++ destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::L8 );
+
+ PixelBuffer* destBuffer = destBitmap.GetBuffer();
+ memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows );
+ }
+ break;
+ }
+
+ case FT_PIXEL_MODE_BGRA:
+ {
+ if ( srcBitmap.pitch == static_cast< int >( srcBitmap.width << 2 ) )
+ {
++ destBitmap = BufferImage::New( srcBitmap.width, srcBitmap.rows, Pixel::BGRA8888 );
+
+ PixelBuffer* destBuffer = destBitmap.GetBuffer();
+ memcpy( destBuffer, srcBitmap.buffer, srcBitmap.width*srcBitmap.rows*4 );
+ }
+ break;
+ }
+ default:
+ {
+ DALI_LOG_ERROR( "FontClient Unable to create Bitmap of this PixelType\n" );
+ break;
+ }
+ }
+ }
+}
+
+bool FontClient::Plugin::FindFont( const FontPath& path,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex,
+ FontId& fontId ) const
+{
+ fontId = 0u;
+ for( std::vector<CacheItem>::const_iterator it = mFontCache.begin(),
+ endIt = mFontCache.end();
+ it != endIt;
+ ++it, ++fontId )
+ {
+ const CacheItem& cacheItem = *it;
+
+ if( cacheItem.mPointSize == pointSize &&
+ cacheItem.mFaceIndex == faceIndex &&
+ cacheItem.mPath == path )
+ {
+ ++fontId;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool FontClient::Plugin::FindValidatedFont( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ FontDescriptionId& validatedFontId )
+{
+ validatedFontId = 0u;
+
+ for( std::vector<FontDescriptionCacheItem>::const_iterator it = mValidatedFontCache.begin(),
+ endIt = mValidatedFontCache.end();
+ it != endIt;
+ ++it )
+ {
+ const FontDescriptionCacheItem& item = *it;
+
+ if( ( fontFamily == item.fontFamily ) &&
+ ( fontStyle == item.fontStyle ) )
+ {
+ validatedFontId = item.index;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
+ PointSize26Dot6 pointSize,
+ FontId& fontId )
+{
+ fontId = 0u;
+
+ for( std::vector<FontIdCacheItem>::const_iterator it = mFontIdCache.begin(),
+ endIt = mFontIdCache.end();
+ it != endIt;
+ ++it )
+ {
+ const FontIdCacheItem& item = *it;
+
+ if( ( validatedFontId == item.validatedFontId ) &&
+ ( pointSize == item.pointSize ) )
+ {
+ fontId = item.fontId;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool FontClient::Plugin::IsScalable( const FontPath& path )
+{
+ FT_Face ftFace;
+ int error = FT_New_Face( mFreeTypeLibrary,
+ path.c_str(),
+ 0,
+ &ftFace );
+ if( FT_Err_Ok != error )
+ {
+ DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
+ }
+ return ( ftFace->num_fixed_sizes == 0 );
+}
+
+bool FontClient::Plugin::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
+{
+ // Create a font pattern.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
+ fontStyle );
+
+ FcResult result = FcResultMatch;
+
+ // match the pattern
+ FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+
+ if( match )
+ {
+ // Get the path to the font file name.
+ FontPath path;
+ GetFcString( match, FC_FILE, path );
+ return IsScalable( path );
+ }
+ DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
+ return true;
+}
+
+void FontClient::Plugin::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6 >& sizes )
+{
+ // Empty the caller container
+ sizes.Clear();
+
+ FT_Face ftFace;
+ int error = FT_New_Face( mFreeTypeLibrary,
+ path.c_str(),
+ 0,
+ &ftFace );
+ if( FT_Err_Ok != error )
+ {
+ DALI_LOG_ERROR( "FreeType Cannot check font: %s\n", path.c_str() );
+ }
+
+ // Fetch the number of fixed sizes available
+ if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
+ {
+ for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+ {
+ sizes.PushBack( ftFace->available_sizes[ i ].size );
+ }
+ }
+}
+
+void FontClient::Plugin::GetFixedSizes( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ Dali::Vector< PointSize26Dot6 >& sizes )
+{
+ // Create a font pattern.
+ FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontFamily,
+ fontStyle );
+
+ FcResult result = FcResultMatch;
+
+ // match the pattern
+ FcPattern* match = FcFontMatch( NULL /* use default configure */, fontFamilyPattern, &result );
+
+ if( match )
+ {
+ // Get the path to the font file name.
+ FontPath path;
+ GetFcString( match, FC_FILE, path );
+ return GetFixedSizes( path, sizes );
+ }
+ DALI_LOG_ERROR( "FreeType Cannot check font: %s %s\n", fontFamily.c_str(), fontStyle.c_str() );
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
--- /dev/null
- BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+#ifndef __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H__
+#define __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/text-abstraction/font-metrics.h>
+#include <dali/internal/text-abstraction/font-client-impl.h>
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+
+// forward declarations of font config types.
+struct _FcFontSet;
+struct _FcPattern;
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ *@brief Type used for indices addressing the vector with front descriptions of validated pairs 'font family name, font style'.
+ */
+typedef uint32_t FontDescriptionId;
+
+/**
+ * @brief FontClient implementation.
+ */
+struct FontClient::Plugin
+{
+ /**
+ * @brief Caches an index to the vector of font descriptions for a given 'font family name, font style'.
+ */
+ struct FontDescriptionCacheItem
+ {
+ FontDescriptionCacheItem( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ FontDescriptionId index );
+
+ FontFamily fontFamily; ///< The font family name.
+ FontStyle fontStyle; ///< The font style.
+ FontDescriptionId index; ///< Index to the vector of font descriptions.
+ };
+
+ /**
+ * @brief Caches the font id of the pair font point size and the index to the vector of font descriptions of validated fonts.
+ */
+ struct FontIdCacheItem
+ {
+ FontIdCacheItem( FontDescriptionId validatedFontId,
+ PointSize26Dot6 pointSize,
+ FontId fontId );
+
+ FontDescriptionId validatedFontId; ///< Index to the vector with font descriptions.
+ PointSize26Dot6 pointSize; ///< The font point size.
+ FontId fontId; ///< The font id.
+ };
+
+ /**
+ * @brief Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+ */
+ struct CacheItem
+ {
+ CacheItem( FT_Face ftFace,
+ const FontPath& path,
+ PointSize26Dot6 pointSize,
+ FaceIndex face,
+ const FontMetrics& metrics,
+ bool isFixedSizeBitmap = false );
+
+ FT_Face mFreeTypeFace; ///< The FreeType face.
+ FontPath mPath; ///< The path to the font file name.
+ PointSize26Dot6 mPointSize; ///< The font point size.
+ FaceIndex mFaceIndex; ///< The face index.
+ FontMetrics mMetrics; ///< The font metrics.
+ bool mIsFixedSizeBitmap; ///< Font is fixed size bitmap.
+ };
+
+ /**
+ * Constructor.
+ *
+ * Initializes the FreeType library.
+ * Initializes the dpi values.
+ *
+ * @param[in] horizontalDpi The horizontal dpi.
+ * @param[in] verticalDpi The vertical dpi.
+ */
+ Plugin( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+ /**
+ * Default destructor.
+ *
+ * Frees any allocated resource.
+ */
+ ~Plugin();
+
+ /**
+ * @copydoc Dali::FontClient::SetDpi()
+ */
+ void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+ /**
+ * @copydoc Dali::FontClient::SetDefaultFontFamily()
+ */
+ void SetDefaultFontFamily( const FontFamily& fontFamilyName,
+ const FontStyle& fontStyle );
+
+ /**
+ * @copydoc Dali::FontClient::GetDefaultFonts()
+ */
+ void GetDefaultFonts( FontList& defaultFonts );
+
+ /**
+ * @copydoc Dali::FontClient::GetSystemFonts()
+ */
+ void GetSystemFonts( FontList& systemFonts );
+
+ /**
+ * @copydoc Dali::FontClient::GetDescription()
+ */
+ void GetDescription( FontId id, FontDescription& fontDescription ) const;
+
+ /**
+ * @copydoc Dali::FontClient::GetPointSize()
+ */
+ PointSize26Dot6 GetPointSize( FontId id );
+
+ /**
+ * @copydoc Dali::FontClient::FindDefaultFont()
+ */
+ FontId FindDefaultFont( Character charcode, PointSize26Dot6 pointSize );
+
+ /**
+ * @see Dali::FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+ *
+ * @param[in] cacheDescription Whether to cache the font description.
+ */
+ FontId GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, bool cacheDescription = true );
+
+ /**
+ * @copydoc Dali::FontClient::GetFontId(const FontFamily& fontFamily, const FontStyle& fontStyle, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+ */
+ FontId GetFontId( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex );
+
+ /**
+ * @copydoc Dali::FontClient::IsScalable(const FontPath& path )
+ */
+ bool IsScalable( const FontPath& path );
+
+ /**
+ * @copydoc Dali::FontClient::IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle )
+ */
+ bool IsScalable( const FontFamily& fontFamily, const FontStyle& fontStyle );
+
+ /**
+ * @copydoc Dali::FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+ */
+ void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+ /**
+ * @copydoc Dali::FontClient::GetFixedSizes( const FontFamily& fontFamily, const FontStyle& fontStyle, Dali::Vector< PointSize26Dot6>& sizes )
+ */
+ void GetFixedSizes( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ Dali::Vector< PointSize26Dot6 >& sizes );
+
+ /**
+ * @copydoc Dali::FontClient::GetFontMetrics()
+ */
+ void GetFontMetrics( FontId fontId, FontMetrics& metrics );
+
+ /**
+ * @copydoc Dali::FontClient::GetGlyphIndex()
+ */
+ GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+ /**
+ * @copydoc Dali::FontClient::CreateMetrics()
+ */
+ bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal );
+
+ /**
+ * @copydoc Dali::FontClient::CreateBitmap()
+ */
- void ConvertBitmap( BitmapImage& destBitmap, FT_Bitmap srcBitmap );
++ BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+
+private:
+
+ /**
+ * Caches the fonts present in the platform.
+ *
+ * Calls GetFcFontSet() to retrieve the fonts.
+ */
+ void InitSystemFonts();
+
+ /**
+ * @brief Creates a font family pattern used to match fonts.
+ *
+ * @param[in] fontFamily The font family name.
+ * @param[in] fontStyle The font style.
+ *
+ * @return The pattern.
+ */
+ _FcPattern* CreateFontFamilyPattern( const FontFamily& fontFamily,
+ const FontStyle& fontStyle );
+
+ /**
+ * Retrieves the fonts present in the platform.
+ *
+ * @return A font fonfig data structure with the platform's fonts.
+ */
+ _FcFontSet* GetFcFontSet() const;
+
+ /**
+ * Retrieves a font config object's value from a pattern.
+ *
+ * @param[in] pattern The font config pattern.
+ * @param[in] n The object.
+ * @param[out] string The object's value.
+ *
+ * @return @e true if the operation is successful.
+ */
+ bool GetFcString( const _FcPattern* const pattern, const char* const n, std::string& string );
+
+ /**
+ * @brief Creates a font.
+ *
+ * @param[in] path The path to the font file name.
+ * @param[in] pointSize The font point size.
+ * @param[in] faceIndex A face index.
+ * @param[in] cacheDescription Whether to cache the font description.
+ *
+ * @return The font id.
+ */
+ FontId CreateFont( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, bool cacheDescription );
+
+ /**
+ * @brief Creates a fixed size font
+ *
+ * @param[in] path The path to the font file name.
+ * @param[in] pointSize The font point size( must be an available size ).
+ * @param[in] faceIndex A face index.
+ * @param[in] cacheDescription Whether to cache the font description.
+ *
+ * @return The font id.
+ */
+ FontId CreateFixedSizeFont( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, bool cacheDescription );
+
+ /**
+ *
+ * @param[in] destBitmap
+ * @param[in] srcBitmap
+ */
++ void ConvertBitmap( BufferImage& destBitmap, FT_Bitmap srcBitmap );
+
+ /**
+ * @brief Finds in the cache if there is a triplet with the path to the font file name, the font point size and the face index.
+ * If there is one , if writes the font id in the param @p fontId.
+ *
+ * @param[in] path Path to the font file name.
+ * @param[in] pointSize The font point size.
+ * @param[in] faceIndex The face index.
+ * @param[out] fontId The font id.
+ *
+ * @return @e true if there triplet is found.
+ */
+ bool FindFont( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex, FontId& fontId ) const;
+
+ /**
+ * @brief Finds in the cahce a pair 'font family, font style'.
+ * If there is one, it writes the index to the vector with font descriptions in the param @p validatedFontId.
+ *
+ * @param[in] fontFamily The font family name.
+ * @param[in] fontStyle The font style.
+ * @param[out] validatedFontId The index to the vector with font descriptions.
+ *
+ * @return @e true if the pair is found.
+ */
+ bool FindValidatedFont( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ FontDescriptionId& validatedFontId );
+
+ /**
+ * @brief Finds in the cache a pair 'validated font id and font point size'.
+ * If there is one it writes the font id in the param @p fontId.
+ *
+ * @param[in] validatedFontId Index to the vector with font descriptions.
+ * @param[in] pointSize The font point size.
+ * @param[out] fontId The font id.
+ *
+ * @return @e true if the pair is found.
+ */
+ bool FindFont( FontDescriptionId validatedFontId,
+ PointSize26Dot6 pointSize,
+ FontId& fontId );
+
+ /**
+ * @brief Validate a font family and style
+ *
+ * @param[in] fontFamily Font Family to validate
+ * @param[in] fontStyle Font Style to validate
+ * @param[out] validatedFontId Result of validation
+ */
+ void ValidateFont( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ FontDescriptionId& validatedFontId );
+
+ FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+
+ unsigned int mDpiHorizontal; ///< Horizontal dpi.
+ unsigned int mDpiVertical; ///< Vertical dpi.
+
+ FontList mSystemFonts; ///< Cached system fonts.
+ FontList mDefaultFonts; ///< Cached default fonts.
+
+ std::vector<CacheItem> mFontCache; ///< Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+ std::vector<FontDescriptionCacheItem> mValidatedFontCache; ///< Caches indices to the vector of font descriptions for a given 'font family name, font style'.
+ FontList mFontDescriptionCache; ///< Caches font descriptions for the validated font family name and font style pairs.
+ std::vector<FontIdCacheItem> mFontIdCache; ///< Caches font ids for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
+};
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H__
--- /dev/null
- BitmapImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text-abstraction/font-client-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE = 768u; // 12*64
+
+FontClient FontClient::Get()
+{
+ return Internal::FontClient::Get();
+}
+
+FontClient::FontClient()
+{
+}
+
+FontClient::~FontClient()
+{
+}
+
+FontClient::FontClient( const FontClient& handle )
+: BaseHandle( handle )
+{
+}
+
+FontClient& FontClient::operator=( const FontClient& handle )
+{
+ BaseHandle::operator=( handle );
+ return *this;
+}
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi )
+{
+ GetImplementation(*this).SetDpi( horizontalDpi, verticalDpi );
+}
+
+void FontClient::SetDefaultFontFamily( const std::string& fontFamilyName,
+ const std::string& fontStyle )
+{
+ GetImplementation(*this).SetDefaultFontFamily( fontFamilyName, fontStyle );
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+ GetImplementation(*this).GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+ GetImplementation(*this).GetSystemFonts( systemFonts );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+ GetImplementation(*this).GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+ return GetImplementation(*this).GetPointSize( id );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode, PointSize26Dot6 pointSize )
+{
+ return GetImplementation(*this).FindDefaultFont( charcode, pointSize );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+{
+ return GetImplementation(*this).GetFontId( path, pointSize, faceIndex );
+}
+
+FontId FontClient::GetFontId( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ PointSize26Dot6 pointSize,
+ FaceIndex faceIndex )
+{
+ return GetImplementation(*this).GetFontId( fontFamily,
+ fontStyle,
+ pointSize,
+ faceIndex );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
+{
+ GetImplementation(*this).GetFontMetrics( fontId, metrics );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+ return GetImplementation(*this).GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal )
+{
+ return GetImplementation(*this).GetGlyphMetrics( array, size, horizontal );
+}
+
++BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+{
+ return GetImplementation(*this).CreateBitmap( fontId, glyphIndex );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+ return GetImplementation(*this).IsScalable( path );;
+}
+
+bool FontClient::IsScalable( const FontFamily& fontFamily, const FontStyle& style )
+{
+ return GetImplementation(*this).IsScalable( fontFamily, style );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+ GetImplementation(*this).GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontFamily& fontFamily,
+ const FontStyle& style,
+ Dali::Vector< PointSize26Dot6 >& sizes )
+{
+ GetImplementation(*this).GetFixedSizes( fontFamily, style, sizes );
+}
+
+FontClient::FontClient( Internal::FontClient* internal )
+: BaseHandle( internal )
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
--- /dev/null
- #include <dali/public-api/images/bitmap-image.h>
+#ifndef __DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H__
+#define __DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H__
+
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
- * @return A valid BitmapImage, or an empty handle if the glyph could not be rendered.
++#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/text-abstraction/font-list.h>
+#include <dali/public-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+struct FontMetrics;
+struct GlyphInfo;
+
+namespace Internal DALI_INTERNAL
+{
+class FontClient;
+}
+
+/**
+ * @brief FontClient provides access to font information and resources.
+ *
+ * <h3>Querying the System Fonts</h3>
+ *
+ * A "system font" is described by a "path" to a font file on the native filesystem, along with a "family" and "style".
+ * For example on the Ubuntu system a "Regular" style font from the "Ubuntu Mono" family can be accessed from "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf".
+ *
+ * <h3>Accessing Fonts</h3>
+ *
+ * A "font" is created from the system for a specific point size in 26.6 fractional points. A "FontId" is used to identify each font.
+ * For example two different fonts with point sizes 10 & 12 can be created from the "Ubuntu Mono" family:
+ * @code
+ * FontClient fontClient = FontClient::Get();
+ * FontId ubuntuMonoTen = fontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 10*64 );
+ * FontId ubuntuMonoTwelve = fontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 12*64 );
+ * @endcode
+ * Glyph metrics and bitmap resources can then be retrieved using the FontId.
+ */
+class DALI_IMPORT_API FontClient : public BaseHandle
+{
+public:
+ static const PointSize26Dot6 DEFAULT_POINT_SIZE; ///< The default point size.
+
+public:
+
+ /**
+ * @brief Retrieve a handle to the FontClient instance.
+ *
+ * @return A handle to the FontClient
+ */
+ static FontClient Get();
+
+ /**
+ * @brief Create an uninitialized TextAbstraction handle.
+ */
+ FontClient();
+
+ /**
+ * @brief Destructor
+ *
+ * This is non-virtual since derived Handle types must not contain data or virtual methods.
+ */
+ ~FontClient();
+
+ /**
+ * @brief This copy constructor is required for (smart) pointer semantics.
+ *
+ * @param[in] handle A reference to the copied handle.
+ */
+ FontClient( const FontClient& handle );
+
+ /**
+ * @brief This assignment operator is required for (smart) pointer semantics.
+ *
+ * @param [in] handle A reference to the copied handle.
+ * @return A reference to this.
+ */
+ FontClient& operator=( const FontClient& handle );
+
+ ////////////////////////////////////////
+ // Font management and validation.
+ ////////////////////////////////////////
+
+ /**
+ * @brief Set the DPI of the target window.
+ *
+ * @note Multiple windows are not currently supported.
+ * @param[in] horizontalDpi The horizontal resolution in DPI.
+ * @param[in] verticalDpi The vertical resolution in DPI.
+ */
+ void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+ /**
+ * Set the default font family and its style that should be used by the font client.
+ *
+ * @param[in] fontFamilyName The default name of the font's family.
+ * @param[in] fontStyle The default font's style.
+ */
+ void SetDefaultFontFamily( const std::string& fontFamilyName,
+ const std::string& fontStyle );
+
+ /**
+ * @brief Retrieve the list of default fonts supported by the system.
+ *
+ * @param[out] defaultFonts A list of default font paths, family & style strings.
+ */
+ void GetDefaultFonts( FontList& defaultFonts );
+
+ /**
+ * @brief Retrieve the list of fonts supported by the system.
+ *
+ * @param[out] systemFonts A list of font paths, family & style strings.
+ */
+ void GetSystemFonts( FontList& systemFonts );
+
+ /**
+ * @brief Retrieves the font description of a given font @p id.
+ *
+ * @param[in] id The font id.
+ * @param[out] fontDescription The path, family & style describing the font.
+ */
+ void GetDescription( FontId id, FontDescription& fontDescription );
+
+ /**
+ * @brief Retrieves the font point size of a given font @p id.
+ *
+ * @param[in] id The font id.
+ *
+ * @return The point size in 26.6 fractional points.
+ */
+ PointSize26Dot6 GetPointSize( FontId id );
+
+ /**
+ * @brief Find an appropriate font for displaying a UTF-32 character.
+ *
+ * This is useful when localised strings are provided for multiple languages
+ * i.e. when a single default font does not work for all languages.
+ * @param[in] charcode The character for which a font is needed.
+ * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+ * @return A valid font ID, or zero if the font does not exist.
+ */
+ FontId FindDefaultFont( Character charcode,
+ PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE );
+
+ /**
+ * @brief Retrieve the unique identifier for a font.
+ *
+ * @param[in] path The path to a font file.
+ * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+ * @param[in] faceIndex The index of the font face (optional).
+ * @return A valid font ID, or zero if the font does not exist.
+ */
+ FontId GetFontId( const FontPath& path, PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE, FaceIndex faceIndex = 0 );
+
+ /**
+ * @brief Retrieve the unique identifier for a font.
+ *
+ * @param[in] fontFamily The font family name.
+ * @param[in] fontStyle The font style.
+ * @param[in] pointSize The point size in 26.6 fractional points; the default point size is 12*64.
+ * @param[in] faceIndex The index of the font face (optional).
+ * @return A valid font ID, or zero if the font does not exist.
+ */
+ FontId GetFontId( const FontFamily& fontFamily,
+ const FontStyle& fontStyle,
+ PointSize26Dot6 pointSize = DEFAULT_POINT_SIZE,
+ FaceIndex faceIndex = 0 );
+
+ /**
+ * @brief Check to see if a font is scalable.
+ *
+ * @param[in] path The path to a font file.
+ * @return true if scalable.
+ */
+ bool IsScalable( const FontPath& path );
+
+ /**
+ * @brief Check to see if a font is scalable.
+ *
+ * @param[in] fontFamily The font family name.
+ * @param[in] style The font style.
+ * @return true if scalable
+ */
+ bool IsScalable( const FontFamily& fontFamily, const FontStyle& style );
+
+ /**
+ * @brief Get a list of sizes available for a fixed size font.
+ *
+ * @param[in] path The path to a font file.
+ * @param[out] sizes A list of the available sizes, if no sizes available will return empty.
+ */
+ void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+ /**
+ * @brief Get a list of sizes available for a fixed size font.
+ *
+ * @param[in] fontFamily The font family name.
+ * @param[in] style The font style.
+ * @param[out] sizes A list of the available sizes, if no sizes available will return empty.
+ */
+ void GetFixedSizes( const FontFamily& fontFamily,
+ const FontStyle& style,
+ Dali::Vector< PointSize26Dot6 >& sizes );
+
+ ////////////////////////////////////////
+ // Font metrics, glyphs and bitmaps.
+ ////////////////////////////////////////
+
+ /**
+ * @brief Query the metrics for a font.
+ *
+ * @param[in] fontId The ID of the font for the required glyph.
+ * @param[out] metrics The font metrics.
+ */
+ void GetFontMetrics( FontId fontId, FontMetrics& metrics );
+
+ /**
+ * @brief Retrieve the glyph index for a UTF-32 character code.
+ *
+ * @param[in] fontId The ID of the font for the required glyph.
+ * @param[in] charcode The UTF-32 character code.
+ * @return The glyph index, or zero if the character code is undefined.
+ */
+ GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+ /**
+ * @brief Retrieve the metrics for a series of glyphs.
+ *
+ * @param[in,out] array An array of glyph-info structures with initialized FontId & GlyphIndex values.
+ * On return, the remaining metrics values will be initialized e.g. glyph size & bearing values.
+ * @param[in] size The size of the array.
+ * @param[in] horizontal True for horizontal layouts (set to false for vertical layouting).
+ * @return True if all of the requested metrics were found.
+ */
+ bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal = true );
+
+ /**
+ * @brief Render a bitmap representation of a glyph.
+ *
+ * @param[in] fontId The ID of the font.
+ * @param[in] glyphIndex The index of a glyph within the specified font.
- BitmapImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
++ * @return A valid BufferImage, or an empty handle if the glyph could not be rendered.
+ */
++ BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex );
+
+public: // Not intended for application developers
+ /**
+ * @brief This constructor is used by FontClient::Get().
+ *
+ * @param[in] fontClient A pointer to the internal fontClient object.
+ */
+ explicit DALI_INTERNAL FontClient( Internal::FontClient* fontClient );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // __DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H__