Back to index

nux  3.0.0
StaticText.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright 2012 Inalogic® Inc.
00003  *
00004  * This program is free software: you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License, as
00006  * published by the  Free Software Foundation; either version 2.1 or 3.0
00007  * of the License.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranties of
00011  * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
00012  * PURPOSE.  See the applicable version of the GNU Lesser General Public
00013  * License for more details.
00014  *
00015  * You should have received a copy of both the GNU Lesser General Public
00016  * License along with this program. If not, see <http://www.gnu.org/licenses/>
00017  *
00018  * Authored by: Jay Taoko <jaytaoko@inalogic.com>
00019  *
00020  */
00021 
00022 #include "Nux.h"
00023 #include "Layout.h"
00024 #include "HLayout.h"
00025 #include "VLayout.h"
00026 #include "Validator.h"
00027 
00028 #include "cairo/cairo.h"
00029 #include "pango/pango.h"
00030 #include "pango/pangocairo.h"
00031 #include "NuxGraphics/CairoGraphics.h"
00032 #include "NuxGraphics/GraphicsDisplay.h"
00033 
00034 #include "StaticText.h"
00035 
00036 #if defined(NUX_OS_WINDOWS)
00037   #include "D2DTextRenderer.h"
00038 #endif
00039 
00040 namespace nux
00041 {
00042   // DIP = Device Independent Pixel unit
00043   // 1 DIP = 1/96 inch.
00044   // 1 inch = 72 points.
00045   float ConvertPointSizeToDIP(float points)
00046   {
00047     return points;
00048     //return (points/72.0f)*96.0f;
00049   }
00050 
00051   NUX_IMPLEMENT_OBJECT_TYPE(StaticText);
00052 
00053   StaticText::StaticText(const std::string& text, NUX_FILE_LINE_DECL)
00054   : View(NUX_FILE_LINE_PARAM)
00055   , text_width_(0)
00056   , text_height_(0)
00057   {
00058     padding_x_ = 0;
00059     padding_y_ = 0;
00060     update_text_rendering_ = true;
00061     text_alignment_ = ALIGN_CENTER;
00062 
00063 #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE)
00064     layout_left_ = 0;
00065     layout_top_ = 0;
00066     
00067     GetGraphicsDisplay()->GetDirect2DFactory()->GetDesktopDpi(&dpi_scale_x, &dpi_scale_y);
00068     dpi_scale_x /= 96.0f;
00069     dpi_scale_y /= 96.0f;
00070 
00071     // 1 DIP = (1/96) inch;  1 inch = 96 DIP
00072     // PixelToDIP = (pixels/dpi)*96.0f
00073 
00074     font_size_ = 12;
00075     font_name_ = "Tahoma";
00076 
00077 #elif defined(NUX_STATIC_TEXT_USE_CAIRO)
00078     cairo_graphics_ = NULL;
00079     font_size_ = 10;
00080     font_name_ = "Ubuntu";
00081     std::ostringstream os;
00082     os << font_name_ << " " << font_size_;
00083     pango_font_name_ = std::string(os.str());
00084 
00085     dpy_ = 96.0f;
00086 #endif
00087 
00088     size_match_text_ = true;
00089     text_color_ = color::White;
00090     clip_to_width_ = 0;
00091 
00092     SetMinimumSize(1, 1);
00093     SetText(text);
00094   }
00095 
00096   StaticText::~StaticText()
00097   {
00098 #if defined(NUX_STATIC_TEXT_USE_CAIRO)
00099     if (cairo_graphics_ != 0)
00100       delete(cairo_graphics_);
00101 #endif
00102 
00103     if (dw_texture_.IsValid())
00104       dw_texture_.Release();
00105   }
00106 
00107   void StaticText::ApplyMinWidth()
00108   {
00109     Size sz = GetTextSizeNoClip();
00110 
00111     if ((sz.width <= GetMaximumWidth()) && (sz.width >= GetMinimumWidth()))
00112     {
00113       SetBaseWidth(sz.width);
00114     }
00115     else if (sz.width >= GetMaximumWidth())
00116     {
00117       View::ApplyMaxWidth();
00118     }
00119     else
00120     {
00121       View::ApplyMinWidth();
00122     }
00123   }
00124 
00125   long StaticText::ComputeContentSize()
00126   {
00127     int pre_layout_width = GetBaseWidth();
00128     int pre_layout_height = GetBaseHeight();
00129 
00130     Size sz = GetTextSizeNoClip();
00131 
00132     // The height of the StaticText is the height of the text itself.
00133     SetBaseHeight(sz.height);
00134 
00135      if ((sz.width >= GetMinimumWidth()) && (sz.width <= GetMaximumWidth()))
00136      {
00137        // The text size is within the bounds of the view.
00138        SetBaseWidth(sz.width);
00139      }
00140      else if (sz.width > GetMaximumWidth())
00141      {
00142        // The text is bigger than the available size.
00143        ApplyMaxWidth();
00144      }
00145      else if (sz.width < GetMinimumWidth())
00146      {
00147        // The text size is smaller than the minimum width of the view.
00148        View::ApplyMinWidth();
00149      }
00150 
00151     // Get the width size of this area.
00152     int width = GetBaseWidth();
00153     int height = GetBaseHeight();
00154 
00155     if (sz.width > width)
00156     {
00157       // The text is too large to fit.
00158       // There will be ellipsis at the end of the text.
00159       SetClipping(width);
00160     }
00161     else
00162     {
00163       // The text fits inside the view.
00164       SetClipping(0);
00165     }
00166 
00167     long result = 0;
00168     if (pre_layout_width < width)
00169       result |= eLargerWidth;
00170     else if (pre_layout_width > width)
00171       result |= eSmallerWidth;
00172     else
00173       result |= eCompliantWidth;
00174 
00175     if (pre_layout_height < height)
00176       result |= eLargerHeight;
00177     else if (pre_layout_height > height)
00178       result |= eSmallerHeight;
00179     else
00180       result |= eCompliantHeight;
00181 
00182     return result;
00183 
00184   }
00185 
00186   void StaticText::SetSizeMatchText(bool size_match_text)
00187   {
00188     size_match_text_ = size_match_text;
00189   }
00190 
00191   bool StaticText::GetSizeMatchText() const
00192   {
00193     return size_match_text_;
00194   }
00195 
00196    void StaticText::SetClipping(int clipping)
00197    {
00198      if (clip_to_width_ == clipping)
00199        return;
00200  
00201      clip_to_width_ = clipping;
00202  
00203      if (clip_to_width_ < 0)
00204        clip_to_width_ = 0;
00205  
00206      ComputeTextSize();
00207      update_text_rendering_ = true;
00208    }
00209  
00210    int StaticText::GetClipping() const
00211    {
00212      return clip_to_width_;
00213    }
00214 
00215   void StaticText::Draw(GraphicsEngine& graphics_engine, bool forceDraw)
00216   {
00217     if (update_text_rendering_)
00218     {
00219       UpdateTextRendering();
00220     }
00221 
00222     // Draw background texture here.
00223 
00224     if (!dw_texture_.IsValid())
00225       return;
00226 
00227     Geometry base = GetGeometry();
00228     graphics_engine.PushClippingRectangle(base);
00229 
00230     nux::GetPainter().PaintBackground(graphics_engine, base);
00231 
00232     // Get the current blend states. They will be restored later.
00233     unsigned int alpha = 0, src = 0, dest = 0;
00234     graphics_engine.GetRenderStates().GetBlend(alpha, src, dest);
00235 
00236     graphics_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
00237 
00238     TexCoordXForm texxform;
00239     texxform.SetWrap(TEXWRAP_CLAMP, TEXWRAP_CLAMP);
00240     texxform.SetTexCoordType(TexCoordXForm::OFFSET_COORD);
00241 
00242     // Compute and y coordinate centered on the view
00243     int y = base.y + (base.height - dw_texture_->GetHeight()) / 2;
00244 
00245     int x = base.x;
00246     
00247     //Special case: In the horizontal direction, if the width of the text is smaller than the 
00248     // width of the view, then center the text horizontally.
00249     if (dw_texture_->GetWidth() < base.width)
00250     {
00251       if (text_alignment_ == ALIGN_CENTER)
00252       {
00253         x = base.x + (base.width - dw_texture_->GetWidth()) / 2;
00254       }
00255       else if (text_alignment_ == ALIGN_LEFT)
00256       {
00257         x = base.x;
00258       }
00259       else if (text_alignment_ == ALIGN_RIGHT)
00260       {
00261         x = base.x + base.width - dw_texture_->GetWidth();
00262       }
00263     }
00264 
00265     graphics_engine.QRP_1Tex(x,
00266       y,
00267       dw_texture_->GetWidth(),
00268       dw_texture_->GetHeight(),
00269       dw_texture_,
00270       texxform,
00271       text_color_);
00272 
00273     graphics_engine.GetRenderStates().SetBlend(alpha, src, dest);
00274     graphics_engine.PopClippingRectangle();
00275   }
00276 
00277   void StaticText::SetFontSize(int font_size)
00278   {
00279     if (font_size <= 0)
00280       return;
00281       
00282 #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE)
00283     font_size_ = font_size;
00284 #elif defined(NUX_STATIC_TEXT_USE_CAIRO)
00285     font_size_ = font_size;
00286     std::ostringstream os;
00287     os << font_name_ << " " << font_size_;
00288     pango_font_name_ = std::string(os.str());
00289 #endif
00290 
00291     // reset cache
00292     no_clip_size_.width = 0;
00293     no_clip_size_.height = 0;
00294     // Changing the font can cause the StaticView to resize itself.
00295     Size sz = GetTextSizeNoClip();
00296     // Calling SetBaseSize will trigger a layout request of this view and all of its parents.
00297     SetBaseSize(sz.width, sz.height);
00298   }
00299 
00300   void StaticText::SetTextPointSize(int font_size)
00301   {
00302     SetFontSize(font_size);
00303   }
00304 
00305   int StaticText::GetFontSize() const
00306   {
00307     return font_size_;
00308   }
00309 
00310   int StaticText::GetTextPointSize() const
00311   {
00312     return GetFontSize();
00313   }
00314 
00315   void StaticText::SetText(const std::string& text)
00316   {
00317     if (text_ == text)
00318       return;
00319 
00320     text_ = text;
00321 
00322     // reset cache
00323     no_clip_size_.width = 0;
00324     no_clip_size_.height = 0;
00325 
00326     // Changing the font can cause the StaticView to resize itself.
00327     Size sz = GetTextSizeNoClip();
00328     // Calling SetBaseSize will trigger a layout request of this view and all of its parents.
00329     SetBaseSize(sz.width, sz.height);
00330 
00331     update_text_rendering_ = true;
00332     text_changed.emit(this);
00333     QueueDraw();
00334   }
00335 
00336   std::string StaticText::GetText() const
00337   {
00338     return text_;
00339   }
00340 
00341   void StaticText::SetTextColor(const Color& text_color)
00342   {
00343     text_color_ = text_color;
00344   }
00345 
00346   Color StaticText::GetTextColor() const
00347   {
00348     return text_color_;
00349   }
00350 
00351   void StaticText::SetFontName(const std::string& font_name)
00352   {
00353     if (font_name_ == font_name)
00354       return;
00355 
00356     font_name_ = font_name;
00357 
00358 #if defined(NUX_OS_LINUX)
00359     std::ostringstream os;
00360     os << font_name_ << " " << font_size_;
00361     pango_font_name_ = std::string(os.str());
00362 #endif
00363     
00364     // reset cache
00365     no_clip_size_.width = 0;
00366     no_clip_size_.height = 0;
00367 
00368     // Changing the font can cause the StaticView to resize itself.
00369     Size sz = GetTextSizeNoClip();
00370     // Calling SetBaseSize will trigger a layout request of this view and all of its parents.
00371     SetBaseSize(sz.width, sz.height);
00372     QueueDraw();
00373   }
00374 
00375   std::string StaticText::GetFontName() const
00376   {
00377     return font_name_;
00378   }
00379 
00380   void StaticText::GetTextLayoutSize(int& width, int& height) const
00381   {
00382     if (text_ == "")
00383     {
00384       width = 0;
00385       height = 0;
00386       return;
00387     }
00388 
00389     width = text_width_;
00390     height = text_height_;
00391   }
00392 
00393   Size StaticText::GetTextLayoutSize() const
00394   {
00395     Size sz;
00396     GetTextLayoutSize(sz.width, sz.height);
00397     return sz;
00398   }
00399 
00400   void StaticText::SetTextAlignment(TextAlignment alignment)
00401   {
00402     text_alignment_ = alignment;
00403   }
00404 
00405   StaticText::TextAlignment StaticText::GetTextAlignment() const
00406   {
00407     return text_alignment_;
00408   }
00409   
00410   ObjectPtr<nux::IOpenGLBaseTexture> StaticText::GetTextTexture()
00411   {
00412     if (update_text_rendering_)
00413     {
00414       // If the text rendering needs to be updated, do it here.
00415       UpdateTextRendering();
00416     }
00417 
00418     return dw_texture_;
00419   }
00420 
00421   Size StaticText::GetTextSizeNoClip()
00422   {
00423     if (no_clip_size_.width == 0)
00424       no_clip_size_ = ComputeTextSize(false, false);
00425     return no_clip_size_;
00426   }
00427 
00428 #if defined(NUX_STATIC_TEXT_USE_DIRECT_WRITE)
00429   Size StaticText::ComputeTextSize(bool assign, bool with_clipping)
00430   {
00431     HRESULT hr;
00432     IDWriteFactory* pDWriteFactory = GetGraphicsDisplay()->GetDirectWriteFactory();
00433 
00434     ID2D1RenderTarget* pRT = NULL;
00435     IDWriteTextFormat* pTextFormat = NULL;
00436 
00437     hr = pDWriteFactory->CreateTextFormat(
00438         ANSICHAR_TO_UNICHAR(font_name_.c_str()),                  // Font family name.
00439         NULL,                       // Font collection(NULL sets it to use the system font collection).
00440         DWRITE_FONT_WEIGHT_REGULAR,
00441         DWRITE_FONT_STYLE_NORMAL,
00442         DWRITE_FONT_STRETCH_NORMAL,
00443         ConvertPointSizeToDIP(font_size_),
00444         L"en-us",
00445         &pTextFormat);
00446 
00447     // Center align(horizontally) the text.
00448     if (SUCCEEDED(hr))
00449     {
00450       hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
00451     }
00452 
00453     if (SUCCEEDED(hr))
00454     {
00455       hr = pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
00456     }
00457 
00458     if (SUCCEEDED(hr))
00459     {
00460       hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
00461     }
00462 
00463     IDWriteTextLayout* pTextLayout_;
00464     hr = pDWriteFactory->CreateTextLayout(
00465       TCHAR_TO_UNICHAR(text_.c_str()),      // The string to be laid out and formatted.
00466       text_.length(),                       // The length of the string.
00467       pTextFormat,                         // The text format to apply to the string(contains font information, etc).
00468       1,                                    // The width of the layout box.
00469       1,                                    // The height of the layout box.
00470       &pTextLayout_                         // The IDWriteTextLayout interface pointer.
00471       );
00472 
00473     DWRITE_TEXT_METRICS metrics;
00474     pTextLayout_->GetMetrics(&metrics);
00475 
00476     int text_width = std::ceil(metrics.widthIncludingTrailingWhitespace * dpi_scale_x);
00477     int text_height = std::ceil(metrics.height * dpi_scale_y);
00478 
00479     if (assign)
00480     {
00481       text_width_ = text_width;
00482       text_height_ = text_height;
00483 
00484       padding_x_ = text_width_ - metrics.widthIncludingTrailingWhitespace * dpi_scale_x;
00485       padding_y_ = text_height_ - metrics.height * dpi_scale_y;
00486 
00487       if (with_clipping && (clip_to_width_ > 0))
00488       {
00489         text_width_ = text_width_ <= clip_to_width_ ? text_width_ : clip_to_width_;
00490       }
00491 
00492       text_width = text_width_;
00493       text_height = text_height_;
00494     }
00495 
00496     layout_top_ = metrics.top * dpi_scale_x;
00497     layout_left_ = metrics.left * dpi_scale_y;
00498 
00499     if (pTextLayout_)
00500     {
00501       pTextLayout_->Release();
00502       pTextLayout_ = NULL;
00503     }
00504 
00505     if (pTextFormat)
00506     {
00507       pTextFormat->Release();
00508       pTextFormat = NULL;
00509     }
00510 
00511     return Size(text_width, text_height);
00512   }
00513 
00514   void StaticText::RasterizeText(Color color)
00515   {
00516     if ((text_width_ <=0) || (text_height_ <= 0))
00517     {
00518       dw_texture_.Release();
00519       return;
00520     }
00521 
00522     HRESULT hr;
00523 
00524     ID2D1Factory* pD2DFactory = GetGraphicsDisplay()->GetDirect2DFactory();
00525     IDWriteFactory* pDWriteFactory = GetGraphicsDisplay()->GetDirectWriteFactory();
00526     IWICImagingFactory* pWICFactory = GetGraphicsDisplay()->GetWICFactory();
00527 
00528     ID2D1RenderTarget* pRT = NULL;
00529     IDWriteTextFormat* pTextFormat = NULL;
00530 
00531     hr = pDWriteFactory->CreateTextFormat(
00532       ANSICHAR_TO_UNICHAR(font_name_.c_str()),                  // Font family name.
00533       NULL,                       // Font collection(NULL sets it to use the system font collection).
00534       DWRITE_FONT_WEIGHT_REGULAR,
00535       DWRITE_FONT_STYLE_NORMAL,
00536       DWRITE_FONT_STRETCH_NORMAL,
00537       ConvertPointSizeToDIP(font_size_),
00538       L"en-us",
00539       &pTextFormat);
00540 
00541 
00542     // Center align(horizontally) the text.
00543     if (SUCCEEDED(hr))
00544     {
00545       hr = pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
00546     }
00547 
00548     if (SUCCEEDED(hr))
00549     {
00550       hr = pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
00551     }
00552 
00553     if (SUCCEEDED(hr))
00554     {
00555       hr = pTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
00556     }
00557 
00558     IDWriteTextLayout* pTextLayout_ = NULL;
00559 
00560     hr = pDWriteFactory->CreateTextLayout(
00561       TCHAR_TO_UNICHAR(text_.c_str()),      // The string to be laid out and formatted.
00562       text_.length(),                       // The length of the string.
00563       pTextFormat,                         // The text format to apply to the string(contains font information, etc).
00564       text_width_ / dpi_scale_x,                                    // The width of the layout box.
00565       text_height_ / dpi_scale_y,                                    // The height of the layout box.
00566       &pTextLayout_                         // The IDWriteTextLayout interface pointer.
00567       );
00568 
00569     IDWriteInlineObject* inlineObject = NULL;
00570     if (SUCCEEDED(hr))
00571     {
00572       pDWriteFactory->CreateEllipsisTrimmingSign(
00573         pTextLayout_,
00574         &inlineObject);
00575     }
00576     DWRITE_TRIMMING trimming = {DWRITE_TRIMMING_GRANULARITY_CHARACTER, 0, 0};
00577     hr = pTextLayout_->SetTrimming(&trimming, inlineObject);
00578 
00579     IWICBitmap* pWICBitmap = NULL;
00580     if (SUCCEEDED(hr))
00581     {
00582       hr = pWICFactory->CreateBitmap(
00583         text_width_ / dpi_scale_x,
00584         text_height_ / dpi_scale_y,
00585         GUID_WICPixelFormat32bppPBGRA,
00586         WICBitmapCacheOnLoad,
00587         &pWICBitmap);
00588     }
00589 
00590     // Set the render target type to D2D1_RENDER_TARGET_TYPE_DEFAULT to use software rendering.
00591     if (SUCCEEDED(hr))
00592     {
00593       D2D1_RENDER_TARGET_PROPERTIES renderTargetProperties;
00594      
00595       renderTargetProperties.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
00596       renderTargetProperties.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
00597       renderTargetProperties.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
00598       renderTargetProperties.dpiX = 0.0;
00599       renderTargetProperties.dpiY = 0.0;
00600       renderTargetProperties.usage = D2D1_RENDER_TARGET_USAGE_NONE;
00601       renderTargetProperties.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;
00602      
00603       hr = pD2DFactory->CreateWicBitmapRenderTarget(
00604         pWICBitmap,
00605         renderTargetProperties, //D2D1::RenderTargetProperties(),
00606         &pRT);
00607     }
00608 
00609     ID2D1SolidColorBrush* pBrush;
00610     hr = pRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF(color.red, color.green, color.blue, color.alpha)), &pBrush);
00611 
00612     // Create the text renderer
00613     CustomTextRenderer* pTextRenderer_ = new (std::nothrow) CustomTextRenderer(
00614       pD2DFactory,
00615       pRT,
00616       pBrush,
00617       NULL);
00618 
00619     D2D1_POINT_2F origin = D2D1::Point2F(static_cast<FLOAT>(padding_x_ / dpi_scale_x), static_cast<FLOAT>(padding_y_ / dpi_scale_y));
00620 
00621     if (0)
00622     {
00623       if (SUCCEEDED(hr))
00624       {
00625         pRT->BeginDraw();
00626 
00627         pRT->SetTransform(D2D1::IdentityMatrix());
00628 
00629         pRT->Clear(D2D1::ColorF(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)));
00630 
00631         // Call the DrawText method of this class.
00632         hr = pTextLayout_->Draw(
00633           NULL,
00634           pTextRenderer_,  // Custom text renderer.
00635           origin.x,
00636           origin.y
00637           );
00638 
00639         hr = pRT->EndDraw();
00640       }
00641     }
00642     else
00643     {
00644       if (SUCCEEDED(hr))
00645       {
00646         pRT->BeginDraw();
00647 
00648         pRT->SetTransform(D2D1::IdentityMatrix());
00649 
00650         pRT->Clear(D2D1::ColorF(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)));
00651 
00652         // Call the DrawText method of this class.
00653         pRT->DrawTextLayout(
00654           origin,
00655           pTextLayout_,
00656           pBrush);
00657 
00658         hr = pRT->EndDraw();
00659       }
00660     }
00661 
00662     {
00663       unsigned int width, height;
00664       pWICBitmap->GetSize(&width, &height);
00665 
00666       dw_texture_ = nux::GetGraphicsDisplay()->GetGpuDevice()->CreateTexture(width, height, 1, nux::BITFMT_B8G8R8A8, NUX_TRACKER_LOCATION);
00667 
00668       nux::SURFACE_LOCKED_RECT lock_rect;
00669       dw_texture_->LockRect(0, &lock_rect, NULL);
00670 
00671       pWICBitmap->CopyPixels(NULL, lock_rect.Pitch, 4*width*height, (BYTE*) lock_rect.pBits);
00672 
00673       dw_texture_->UnlockRect(0);
00674 
00675     }
00676 
00677     if (pTextRenderer_)
00678       delete pTextRenderer_;
00679 
00680     if (pBrush)
00681     {
00682       pBrush->Release();
00683       pBrush = NULL;
00684     }
00685 
00686 
00687     if (pRT)
00688     {
00689       pRT->Release();
00690       pRT = NULL;
00691     }
00692 
00693     if (pWICBitmap)
00694     {
00695       pWICBitmap->Release();
00696       pWICBitmap = NULL;
00697     }
00698 
00699     if (pTextLayout_)
00700     {
00701       pTextLayout_->Release();
00702       pTextLayout_ = NULL;
00703     }
00704 
00705     if (pTextFormat)
00706     {
00707       pTextFormat->Release();
00708       pTextFormat = NULL;
00709     }
00710   }
00711 
00712    void StaticText::UpdateTextRendering()
00713    {
00714      Size sz = ComputeTextSize();
00715 
00716      if (sz.width == 0 || sz.height == 0)
00717      {
00718        // Nothing to render
00719        if (dw_texture_.IsValid())
00720        {
00721          dw_texture_.Release();
00722        }
00723        return;
00724      }
00725 
00726      RasterizeText(color::White);
00727      update_text_rendering_ = false;
00728    }
00729 #elif defined(NUX_STATIC_TEXT_USE_CAIRO)
00730   Size StaticText::ComputeTextSize(bool assign, bool with_clipping)
00731   {
00732     cairo_surface_t*      pango_surface = NULL;
00733     cairo_t*              cairo_ctx     = NULL;
00734     PangoLayout*          pango_layout  = NULL;
00735     PangoFontDescription* font_desc     = NULL;
00736     PangoContext*         pango_ctx     = NULL;
00737     PangoRectangle        ink_rect      = {0, 0, 0, 0};
00738     PangoRectangle        logical_rect  = {0, 0, 0, 0};
00739     int                   dpi           = 96;
00740 
00741     // Create Cairo surface.
00742     pango_surface = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1);
00743     
00744     // Create Cairo context.
00745     cairo_ctx = cairo_create(pango_surface);
00746     
00747     // Create layout.
00748     pango_layout = pango_cairo_create_layout(cairo_ctx);
00749     {
00750       pango_layout_set_wrap     (pango_layout, PANGO_WRAP_WORD_CHAR);
00751       pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END);
00752       pango_layout_set_markup   (pango_layout, text_.c_str(), -1);
00753     }
00754 
00755     // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]"
00756     font_desc = pango_font_description_from_string(pango_font_name_.c_str());
00757     {
00758       pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL);
00759       pango_layout_set_font_description(pango_layout, font_desc);
00760     }
00761 
00762     // Get Pango context
00763     pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed
00764 
00765     // Set font options
00766     CairoFontOptions font_options;
00767     {
00768       cairo_font_options_set_antialias      (font_options, CAIRO_ANTIALIAS_DEFAULT);
00769       cairo_font_options_set_subpixel_order(font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT);
00770       cairo_font_options_set_hint_style     (font_options, CAIRO_HINT_STYLE_DEFAULT);
00771       cairo_font_options_set_hint_metrics   (font_options, CAIRO_HINT_METRICS_ON);
00772       cairo_set_font_options(cairo_ctx, font_options);
00773 
00774       pango_cairo_context_set_font_options(pango_ctx, font_options);
00775     }
00776 
00777     // use some default DPI-value
00778     pango_cairo_context_set_resolution(pango_ctx, dpi);
00779 
00780     pango_layout_context_changed(pango_layout);
00781     pango_layout_get_extents(pango_layout, &ink_rect, &logical_rect);
00782 
00783     int text_width = std::ceil((float)logical_rect.width / PANGO_SCALE);
00784     int text_height = std::ceil((float)logical_rect.height / PANGO_SCALE);
00785 
00786     if (assign)
00787     {
00788       text_width_ = text_width;
00789       text_height_ = text_height;
00790 
00791       padding_x_ = text_width_ - logical_rect.width / PANGO_SCALE;
00792       padding_y_ = text_height_ - logical_rect.height / PANGO_SCALE;
00793 
00794       if (with_clipping && (clip_to_width_ > 0))
00795       {
00796         text_width_ = text_width_ <= clip_to_width_ ? text_width_ : clip_to_width_;
00797       }
00798 
00799       text_width = text_width_;
00800       text_height = text_height_;
00801     }
00802 
00803     // clean up
00804     pango_font_description_free(font_desc);
00805     g_object_unref(pango_layout);
00806     cairo_destroy(cairo_ctx);
00807     cairo_surface_destroy(pango_surface);
00808 
00809     return Size(text_width, text_height);
00810   }
00811 
00812   void StaticText::RasterizeText(void* cairo_context, Color color)
00813   {
00814     cairo_t* cairo_ctx = (cairo_t*) cairo_context;
00815 
00816     PangoLayout*          pango_layout  = NULL;
00817     PangoFontDescription* font_desc     = NULL;
00818     PangoContext*         pango_ctx     = NULL;
00819     int                   dpi            = 96;
00820 
00821     // Create layout.
00822     pango_layout = pango_cairo_create_layout(cairo_ctx);
00823     {
00824       pango_layout_set_wrap     (pango_layout, PANGO_WRAP_WORD_CHAR);
00825       pango_layout_set_ellipsize(pango_layout, PANGO_ELLIPSIZE_END);
00826       pango_layout_set_markup   (pango_layout, text_.c_str(), -1);
00827 
00828       // Sets the width to which the lines of the PangoLayout should wrap or ellipsized. The default value is -1: no width set.
00829       pango_layout_set_width(pango_layout, (clip_to_width_ ? clip_to_width_ : text_width_) * PANGO_SCALE);
00830     }
00831 
00832     // Create font description: "[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]"
00833     font_desc = pango_font_description_from_string(pango_font_name_.c_str());
00834     {
00835       pango_font_description_set_weight(font_desc, PANGO_WEIGHT_NORMAL);
00836       pango_layout_set_font_description(pango_layout, font_desc);
00837     }
00838 
00839     // Get Pango context
00840     pango_ctx = pango_layout_get_context(pango_layout); // is not ref'ed
00841 
00842     // Set font options
00843     CairoFontOptions font_options;
00844     {
00845       cairo_font_options_set_antialias      (font_options, CAIRO_ANTIALIAS_DEFAULT);
00846       cairo_font_options_set_subpixel_order (font_options, CAIRO_SUBPIXEL_ORDER_DEFAULT);
00847       cairo_font_options_set_hint_style     (font_options, CAIRO_HINT_STYLE_DEFAULT);
00848       cairo_font_options_set_hint_metrics   (font_options, CAIRO_HINT_METRICS_ON);
00849       cairo_set_font_options(cairo_ctx, font_options);
00850 
00851       pango_cairo_context_set_font_options(pango_ctx, font_options);
00852     }
00853 
00854     pango_cairo_context_set_resolution(pango_ctx, dpi);
00855 
00856     cairo_set_source_rgba(cairo_ctx, 1.0, 1.0, 1.0, 1.0);
00857 
00858     pango_layout_context_changed(pango_layout);
00859 
00860     cairo_move_to(cairo_ctx, padding_x_, padding_y_);
00861     pango_cairo_show_layout(cairo_ctx, pango_layout);
00862 
00863     // clean up
00864     pango_font_description_free(font_desc);
00865     g_object_unref(pango_layout);
00866   }
00867 
00868   void StaticText::UpdateTextRendering()
00869   {
00870     Size sz = ComputeTextSize();
00871 
00872     if (sz.width == 0 || sz.height == 0)
00873     {
00874       // Nothing to render
00875       if (dw_texture_.IsValid())
00876       {
00877         dw_texture_.Release();
00878       }
00879       return;
00880     }
00881 
00882     cairo_graphics_ = new CairoGraphics(CAIRO_FORMAT_ARGB32, sz.width, sz.height);
00883     cairo_t* cairo_ctx = cairo_graphics_->GetContext();
00884     cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_CLEAR);
00885     cairo_paint(cairo_ctx);
00886     cairo_set_operator(cairo_ctx, CAIRO_OPERATOR_OVER);
00887 
00888     RasterizeText(cairo_ctx, text_color_);
00889 
00890     NBitmapData* bitmap = cairo_graphics_->GetBitmap();
00891 
00892     // NTexture2D is the high level representation of an image that is backed by
00893     // an actual opengl texture.
00894 
00895     BaseTexture* rasterized_text_texture = NULL;
00896 
00897     rasterized_text_texture = GetGraphicsDisplay()->GetGpuDevice()->CreateSystemCapableTexture();
00898     rasterized_text_texture->Update(bitmap);
00899     dw_texture_ = rasterized_text_texture->GetDeviceTexture();
00900 
00901     rasterized_text_texture->UnReference();
00902     rasterized_text_texture = NULL;
00903 
00904     delete bitmap;
00905     cairo_destroy(cairo_ctx);
00906     delete cairo_graphics_;
00907     cairo_graphics_ = NULL;
00908 
00909     update_text_rendering_ = false;
00910   }
00911 
00912 #endif
00913 }