// // Copyright (c) 2008-2014 the Urho3D project. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // #include "Precompiled.h" #include "Context.h" #include "Deserializer.h" #include "FileSystem.h" #include "Font.h" #include "FontFaceBitMap.h" #include "FontFaceFreeType.h" #include "Graphics.h" #include "Profiler.h" #include "DebugNew.h" namespace Urho3D { static const int MIN_POINT_SIZE = 1; static const int MAX_POINT_SIZE = 96; Font::Font(Context* context) : Resource(context), fontDataSize_(0), fontType_(FONT_NONE) { } Font::~Font() { // To ensure FreeType deallocates properly, first clear all faces, then release the raw font data ReleaseFaces(); fontData_.Reset(); } void Font::RegisterObject(Context* context) { context->RegisterFactory(); } bool Font::Load(Deserializer& source) { PROFILE(LoadFont); // In headless mode, do not actually load, just return success Graphics* graphics = GetSubsystem(); if (!graphics) return true; fontType_ = FONT_NONE; faces_.Clear(); fontDataSize_ = source.GetSize(); if (fontDataSize_) { fontData_ = new unsigned char[fontDataSize_]; if (source.Read(&fontData_[0], fontDataSize_) != fontDataSize_) return false; } else { fontData_.Reset(); return false; } String ext = GetExtension(GetName()); if (ext == ".ttf" || ext == ".otf" || ext == ".woff") fontType_ = FONT_FREETYPE; else if (ext == ".xml" || ext == ".fnt") fontType_ = FONT_BITMAP; SetMemoryUse(fontDataSize_); return true; } bool Font::SaveXML(Serializer& dest, int pointSize, bool usedGlyphs) { FontFace* fontFace = GetFace(pointSize); if (!fontFace) return false; PROFILE(FontSaveXML); SharedPtr packedFontFace(new FontFaceBitMap(this)); if (!packedFontFace->Load(fontFace, usedGlyphs)) return false; return packedFontFace->Save(dest, pointSize); } FontFace* Font::GetFace(int pointSize) { // In headless mode, always return null Graphics* graphics = GetSubsystem(); if (!graphics) return 0; // For bitmap font type, always return the same font face provided by the font's bitmap file regardless of the actual requested point size if (fontType_ == FONT_BITMAP) pointSize = 0; else pointSize = Clamp(pointSize, MIN_POINT_SIZE, MAX_POINT_SIZE); HashMap >::Iterator i = faces_.Find(pointSize); if (i != faces_.End()) { if (!i->second_->IsDataLost()) return i->second_; else { // Erase and reload face if texture data lost (OpenGL mode only) faces_.Erase(i); } } PROFILE(GetFontFace); switch (fontType_) { case FONT_FREETYPE: return GetFaceFreeType(pointSize); case FONT_BITMAP: return GetFaceBitmap(pointSize); default: return 0; } } void Font::ReleaseFaces() { faces_.Clear(); } FontFace* Font::GetFaceFreeType(int pointSize) { SharedPtr newFace(new FontFaceFreeType(this)); if (!newFace->Load(&fontData_[0], fontDataSize_, pointSize)) return 0; faces_[pointSize] = newFace; return newFace; } FontFace* Font::GetFaceBitmap(int pointSize) { SharedPtr newFace(new FontFaceBitMap(this)); if (!newFace->Load(&fontData_[0], fontDataSize_, pointSize)) return 0; faces_[pointSize] = newFace; return newFace; } }