Back to index

nux  3.0.0
TextLoader.cpp
Go to the documentation of this file.
00001 // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
00002 /*
00003  * Copyright (C) 2012 Canonical Ltd
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 3 as
00007  * published by the Free Software Foundation.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  *
00017  * Authored by: Jason Smith <jason.smith@canonical.com>
00018  */
00019 
00020 #include "TextLoader.h"
00021 #include "NuxGraphics/CairoGraphics.h"
00022 
00023 #include <cairo/cairo.h>
00024 #include <pango/pango.h>
00025 #include <pango/pangocairo.h>
00026 
00027 namespace nux {
00028 
00029 struct TextLoader::Impl
00030 {
00031   Impl(TextLoader* parent);
00032   ~Impl();
00033 
00034   void RasterizeText(void* cairo_context, Color color);
00035   Size ComputeTextSize();
00036   std::string GetPangoFontName();
00037 
00038   TextLoader* parent_;
00039   float padding_x_;
00040   float padding_y_;
00041 };
00042 
00043 TextLoader::Impl::Impl(TextLoader* parent)
00044   : parent_(parent)
00045   , padding_x_(0)
00046   , padding_y_(0)
00047 {
00048 
00049 }
00050 
00051 TextLoader::Impl::~Impl()
00052 {
00053 
00054 }
00055 
00056 std::string TextLoader::Impl::GetPangoFontName()
00057 {
00058   std::ostringstream os;
00059   os << parent_->font_name() << " " << parent_->font_size();
00060   return std::string(os.str());
00061 }
00062 
00063 Size TextLoader::Impl::ComputeTextSize()
00064 {
00065   cairo_surface_t*      pango_surface = NULL;
00066   cairo_t*              cairo_ctx     = NULL;
00067   PangoLayout*          pango_layout  = NULL;
00068   PangoFontDescription* font_desc     = NULL;
00069   PangoContext*         pango_ctx     = NULL;
00070   PangoRectangle        ink_rect      = {0, 0, 0, 0};
00071   PangoRectangle        logical_rect  = {0, 0, 0, 0};
00072   int                   dpi           = 96;
00073 
00074   std::string pango_font_name = GetPangoFontName();
00075 
00076   // Create Cairo surface.
00077   pango_surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1);
00078   
00079   // Create Cairo context.
00080   cairo_ctx = cairo_create(pango_surface);
00081   
00082   // Create layout.
00083   pango_layout = pango_cairo_create_layout(cairo_ctx);
00084   {
00085     pango_layout_set_wrap     (pango_layout, PANGO_WRAP_WORD_CHAR);
00086     pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END);
00087     pango_layout_set_markup   (pango_layout, parent_->text().c_str(), -1);
00088     pango_layout_set_height   (pango_layout, -parent_->lines());
00089 
00090     // Sets the width to which the lines of the PangoLayout should wrap or ellipsized. The default value is -1: no width set.
00091     pango_layout_set_width(pango_layout, parent_->width * PANGO_SCALE);
00092   }
00093 
00094   // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]"
00095   font_desc = pango_font_description_from_string(pango_font_name.c_str());
00096   {
00097     pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL);
00098     pango_layout_set_font_description(pango_layout, font_desc);
00099   }
00100 
00101   // Get Pango context
00102   pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed
00103 
00104   // Set font options
00105   CairoFontOptions font_options;
00106   {
00107     cairo_font_options_set_antialias      (font_options, CAIRO_ANTIALIAS_DEFAULT);
00108     cairo_font_options_set_subpixel_order(font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT);
00109     cairo_font_options_set_hint_style     (font_options, CAIRO_HINT_STYLE_DEFAULT);
00110     cairo_font_options_set_hint_metrics   (font_options, CAIRO_HINT_METRICS_ON);
00111     cairo_set_font_options(cairo_ctx, font_options);
00112 
00113     pango_cairo_context_set_font_options(pango_ctx, font_options);
00114   }
00115 
00116   // use some default DPI-value
00117   pango_cairo_context_set_resolution(pango_ctx, dpi);
00118 
00119   pango_layout_context_changed(pango_layout);
00120   pango_layout_get_extents(pango_layout, &ink_rect, &logical_rect);
00121 
00122   int text_width = std::ceil((float)logical_rect.width / PANGO_SCALE);
00123   int text_height = std::ceil((float)logical_rect.height / PANGO_SCALE);
00124 
00125   padding_x_ = text_width - logical_rect.width / PANGO_SCALE;
00126   padding_y_ = text_height - logical_rect.height / PANGO_SCALE;
00127 
00128   text_width = std::min<int>(text_width, parent_->width());
00129 
00130   // clean up
00131   pango_font_description_free(font_desc);
00132   g_object_unref(pango_layout);
00133   cairo_destroy(cairo_ctx);
00134   cairo_surface_destroy(pango_surface);
00135 
00136   return Size(text_width, text_height);
00137 }
00138 
00139 void TextLoader::Impl::RasterizeText(void* cairo_context, Color color)
00140 {
00141   cairo_t* cairo_ctx = (cairo_t*) cairo_context;
00142 
00143   PangoLayout*          pango_layout  = NULL;
00144   PangoFontDescription* font_desc     = NULL;
00145   PangoContext*         pango_ctx     = NULL;
00146   int                   dpi            = 96;
00147 
00148   // Create layout.
00149   pango_layout = pango_cairo_create_layout(cairo_ctx);
00150   {
00151     pango_layout_set_wrap     (pango_layout, PANGO_WRAP_WORD_CHAR);
00152     pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END);
00153     pango_layout_set_alignment(pango_layout, (PangoAlignment)parent_->alignment());
00154     pango_layout_set_markup   (pango_layout, parent_->text().c_str(), -1);
00155     pango_layout_set_height   (pango_layout, -parent_->lines());
00156 
00157     // Sets the width to which the lines of the PangoLayout should wrap or ellipsized. The default value is -1: no width set.
00158     pango_layout_set_width(pango_layout, parent_->width * PANGO_SCALE);
00159   }
00160 
00161   // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]"
00162   font_desc = pango_font_description_from_string(GetPangoFontName().c_str());
00163   {
00164     pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL);
00165     pango_layout_set_font_description(pango_layout, font_desc);
00166   }
00167 
00168   // Get Pango context
00169   pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed
00170 
00171   // Set font options
00172   CairoFontOptions font_options;
00173   {
00174     cairo_font_options_set_antialias      (font_options, CAIRO_ANTIALIAS_DEFAULT);
00175     cairo_font_options_set_subpixel_order (font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT);
00176     cairo_font_options_set_hint_style     (font_options, CAIRO_HINT_STYLE_DEFAULT);
00177     cairo_font_options_set_hint_metrics   (font_options, CAIRO_HINT_METRICS_ON);
00178     cairo_set_font_options(cairo_ctx, font_options);
00179 
00180     pango_cairo_context_set_font_options(pango_ctx, font_options);
00181   }
00182 
00183   pango_cairo_context_set_resolution(pango_ctx, dpi);
00184 
00185   cairo_set_source_rgba(cairo_ctx, 1.0, 1.0, 1.0, 1.0);
00186 
00187   pango_layout_context_changed(pango_layout);
00188 
00189   cairo_move_to(cairo_ctx, padding_x_, padding_y_);
00190   pango_cairo_show_layout(cairo_ctx, pango_layout);
00191 
00192   // clean up
00193   pango_font_description_free(font_desc);
00194   g_object_unref(pango_layout);
00195 }
00196 
00197 TextLoader::TextLoader()
00198   : alignment(TextAlignment::ALIGN_CENTER)
00199   , font_name("Ubuntu")
00200   , font_size(10)
00201   , width(-1)
00202   , minimum_width(0)
00203   , lines(1)
00204   , pimpl(new TextLoader::Impl(this))
00205 {
00206 
00207 }
00208 
00209 TextLoader::~TextLoader()
00210 {
00211   delete pimpl;
00212 }
00213 
00214 ObjectPtr<BaseTexture> TextLoader::CreateTexture()
00215 {
00216   ObjectPtr<BaseTexture> result;
00217   Size sz = pimpl->ComputeTextSize();
00218 
00219   if (sz.width == 0 || sz.height == 0)
00220     return result;
00221 
00222   CairoGraphics* cairo_graphics = new CairoGraphics(CAIRO_FORMAT_ARGB32, std::max<int>(sz.width, minimum_width()), sz.height);
00223   cairo_t* cairo_ctx = cairo_graphics->GetContext();
00224   cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_CLEAR);
00225   cairo_paint(cairo_ctx);
00226   cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_OVER);
00227 
00228   pimpl->RasterizeText(cairo_ctx, color);
00229 
00230   NBitmapData* bitmap = cairo_graphics->GetBitmap();
00231 
00232   // NTexture2D is the high level representation of an image that is backed by
00233   // an actual opengl texture.
00234 
00235   BaseTexture* rasterized_text_texture = NULL;
00236 
00237   rasterized_text_texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture();
00238   rasterized_text_texture->Update(bitmap);
00239 
00240   result = rasterized_text_texture;
00241   rasterized_text_texture->UnReference(); // get rid of our ref so the owner is the only one who gets it
00242   rasterized_text_texture = NULL;
00243 
00244   delete bitmap;
00245   cairo_destroy(cairo_ctx);
00246   delete cairo_graphics;
00247   cairo_graphics = NULL;
00248 
00249   return result;
00250 }
00251 
00252 }