Back to index

lightning-sunbird  0.9+nobinonly
nsSVGCairoGlyphMetrics.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Mozilla SVG Cairo Renderer project.
00016  *
00017  * The Initial Developer of the Original Code is IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2004
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Parts of this file contain code derived from the following files(s)
00022  * of the Mozilla SVG project (these parts are Copyright (C) by their
00023  * respective copyright-holders):
00024  *    layout/svg/renderer/src/gdiplus/nsSVGGDIPlusGlyphMetrics.cpp
00025  *
00026  * Contributor(s):
00027  *
00028  * Alternatively, the contents of this file may be used under the terms of
00029  * either of the GNU General Public License Version 2 or later (the "GPL"),
00030  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00031  * in which case the provisions of the GPL or the LGPL are applicable instead
00032  * of those above. If you wish to allow use of your version of this file only
00033  * under the terms of either the GPL or the LGPL, and not to allow others to
00034  * use your version of this file under the terms of the MPL, indicate your
00035  * decision by deleting the provisions above and replace them with the notice
00036  * and other provisions required by the GPL or the LGPL. If you do not delete
00037  * the provisions above, a recipient may use your version of this file under
00038  * the terms of any one of the MPL, the GPL or the LGPL.
00039  *
00040  * ***** END LICENSE BLOCK ***** */
00041 
00042 #include "nsCOMPtr.h"
00043 #include "nsISVGGlyphMetricsSource.h"
00044 #include "nsPromiseFlatString.h"
00045 #include "nsFont.h"
00046 #include "nsPresContext.h"
00047 #include "nsISVGCairoGlyphMetrics.h"
00048 #include "nsSVGCairoGlyphMetrics.h"
00049 #include "nsIDOMSVGMatrix.h"
00050 #include "nsIDOMSVGRect.h"
00051 #include "nsSVGTypeCIDs.h"
00052 #include "nsIComponentManager.h"
00053 #include "cairo.h"
00054 
00055 extern cairo_surface_t *gSVGCairoDummySurface;
00056 
00066 
00067 
00070 class nsSVGCairoGlyphMetrics : public nsISVGCairoGlyphMetrics
00071 {
00072 protected:
00073   friend nsresult NS_NewSVGCairoGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00074                                              nsISVGGlyphMetricsSource *src);
00075   nsSVGCairoGlyphMetrics(nsISVGGlyphMetricsSource *src);
00076   ~nsSVGCairoGlyphMetrics();
00077 public:
00078   // nsISupports interface:
00079   NS_DECL_ISUPPORTS
00080 
00081   // nsISVGRendererGlyphMetrics interface:
00082   NS_DECL_NSISVGRENDERERGLYPHMETRICS
00083 
00084   NS_IMETHOD_(void) SelectFont(cairo_t *ctx);
00085 
00086 private:
00087   cairo_t *mCT;
00088   cairo_text_extents_t mExtents;
00089   nsCOMPtr<nsISVGGlyphMetricsSource> mSource;
00090 };
00091 
00094 //----------------------------------------------------------------------
00095 // implementation:
00096 
00097 nsSVGCairoGlyphMetrics::nsSVGCairoGlyphMetrics(nsISVGGlyphMetricsSource *src)
00098   : mSource(src)
00099 {
00100   memset(&mExtents, 0, sizeof(cairo_text_extents_t));
00101   mCT = cairo_create(gSVGCairoDummySurface);
00102 }
00103 
00104 nsSVGCairoGlyphMetrics::~nsSVGCairoGlyphMetrics()
00105 {
00106   cairo_destroy(mCT);
00107 }
00108 
00109 nsresult
00110 NS_NewSVGCairoGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00111                            nsISVGGlyphMetricsSource *src)
00112 {
00113   *result = new nsSVGCairoGlyphMetrics(src);
00114   if (!*result) return NS_ERROR_OUT_OF_MEMORY;
00115   
00116   NS_ADDREF(*result);
00117   return NS_OK;
00118 }
00119 
00120 
00121 //----------------------------------------------------------------------
00122 // nsISupports methods:
00123 
00124 NS_IMPL_ADDREF(nsSVGCairoGlyphMetrics)
00125 NS_IMPL_RELEASE(nsSVGCairoGlyphMetrics)
00126 
00127 NS_INTERFACE_MAP_BEGIN(nsSVGCairoGlyphMetrics)
00128 NS_INTERFACE_MAP_ENTRY(nsISVGRendererGlyphMetrics)
00129 NS_INTERFACE_MAP_ENTRY(nsISVGCairoGlyphMetrics)
00130 NS_INTERFACE_MAP_ENTRY(nsISupports)
00131 NS_INTERFACE_MAP_END
00132 
00133 //----------------------------------------------------------------------
00134 // nsISVGRendererGlyphMetrics methods:
00135 
00137 NS_IMETHODIMP
00138 nsSVGCairoGlyphMetrics::GetBaselineOffset(PRUint16 baselineIdentifier, float *_retval)
00139 {
00140   cairo_font_extents_t extents;
00141 
00142   SelectFont(mCT);
00143   cairo_font_extents(mCT, &extents);
00144 
00145   switch (baselineIdentifier) {
00146   case BASELINE_HANGING:
00147     // not really right, but the best we can do with the information provided
00148     // FALLTHROUGH
00149   case BASELINE_TEXT_BEFORE_EDGE:
00150     *_retval = -extents.ascent;
00151     break;
00152   case BASELINE_TEXT_AFTER_EDGE:
00153     *_retval = extents.descent;
00154     break;
00155   case BASELINE_CENTRAL:
00156   case BASELINE_MIDDLE:
00157     *_retval = - (extents.ascent - extents.descent) / 2.0;
00158     break;
00159   case BASELINE_ALPHABETIC:
00160   default:
00161     *_retval = 0.0;
00162     break;
00163   }
00164   
00165   return NS_OK;
00166 }
00167 
00168 
00170 NS_IMETHODIMP
00171 nsSVGCairoGlyphMetrics::GetAdvance(float *aAdvance)
00172 {
00173   *aAdvance = mExtents.x_advance;
00174   return NS_OK;
00175 }
00176 
00177 
00179 NS_IMETHODIMP
00180 nsSVGCairoGlyphMetrics::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
00181 {
00182   *_retval = nsnull;
00183 
00184   cairo_text_extents_t extent;
00185 
00186   nsAutoString text;
00187   mSource->GetCharacterData(text);
00188 
00189   SelectFont(mCT);
00190   cairo_text_extents(mCT,
00191                      NS_ConvertUCS2toUTF8(Substring(text, charnum, 1)).get(),
00192                      &extent);
00193 
00194   nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00195 
00196   NS_ASSERTION(rect, "could not create rect");
00197   if (!rect) return NS_ERROR_FAILURE;
00198   
00199   rect->SetX(extent.x_bearing);
00200   rect->SetY(extent.y_bearing);
00201   rect->SetWidth(extent.width);
00202   rect->SetHeight(extent.height);
00203 
00204   *_retval = rect;
00205   NS_ADDREF(*_retval);
00206   
00207   return NS_OK;
00208 }
00209 
00210 NS_IMETHODIMP
00211 nsSVGCairoGlyphMetrics::GetAdvanceOfChar(PRUint32 charnum, float *advance)
00212 {
00213   cairo_text_extents_t extent;
00214 
00215   nsAutoString text;
00216   mSource->GetCharacterData(text);
00217 
00218   SelectFont(mCT);
00219   cairo_text_extents(mCT,
00220                      NS_ConvertUCS2toUTF8(Substring(text, charnum, 1)).get(),
00221                      &extent);
00222 
00223   *advance = extent.x_advance;
00224   
00225   return NS_OK;
00226 }
00227 
00229 NS_IMETHODIMP
00230 nsSVGCairoGlyphMetrics::Update(PRUint32 updatemask, PRBool *_retval)
00231 {
00232   *_retval = PR_FALSE;
00233   
00234   if (updatemask & nsISVGGlyphMetricsSource::UPDATEMASK_CHARACTER_DATA) {
00235     *_retval = PR_TRUE;
00236   }
00237 
00238   if (updatemask & nsISVGGlyphMetricsSource::UPDATEMASK_FONT) {
00239     *_retval = PR_TRUE;
00240   }
00241 
00242   SelectFont(mCT);
00243 
00244   nsAutoString text;
00245   mSource->GetCharacterData(text);
00246 
00247   if (!text.Length()) {
00248     memset(&mExtents, 0, sizeof(cairo_text_extents_t));
00249   } else {
00250     cairo_text_extents(mCT, 
00251                        NS_ConvertUCS2toUTF8(text).get(),
00252                        &mExtents);
00253   }
00254   
00255   return NS_OK;
00256 }
00257 
00258 NS_IMETHODIMP_(void)
00259 nsSVGCairoGlyphMetrics::SelectFont(cairo_t *ctx)
00260 {
00261     nsFont font;
00262     mSource->GetFont(&font);
00263       
00264     cairo_font_slant_t slant;
00265     cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL;
00266 
00267     switch (font.style) {
00268     case NS_FONT_STYLE_NORMAL:
00269       slant = CAIRO_FONT_SLANT_NORMAL;
00270       break;
00271     case NS_FONT_STYLE_ITALIC:
00272       slant = CAIRO_FONT_SLANT_ITALIC;
00273       break;
00274     case NS_FONT_STYLE_OBLIQUE:
00275       slant = CAIRO_FONT_SLANT_OBLIQUE;
00276       break;
00277     }
00278 
00279     if (font.weight % 100 == 0) {
00280       if (font.weight >= 600)
00281              weight = CAIRO_FONT_WEIGHT_BOLD;
00282     } else if (font.weight % 100 < 50) {
00283       weight = CAIRO_FONT_WEIGHT_BOLD;
00284     }
00285 
00286     nsString family;
00287     font.GetFirstFamily(family);
00288     char *f = ToNewCString(family);
00289     cairo_select_font_face(ctx, f, slant, weight);
00290     nsMemory::Free(f);
00291 
00292     nsCOMPtr<nsPresContext> presContext;
00293     mSource->GetPresContext(getter_AddRefs(presContext));
00294     float pxPerTwips = presContext->TwipsToPixels();
00295     float pixelScale;
00296     presContext->DeviceContext()->GetCanonicalPixelScale(pixelScale);
00297 
00298     cairo_set_font_size(ctx, font.size * pxPerTwips / pixelScale);
00299 }