Back to index

lightning-sunbird  0.9+nobinonly
nsSVGLibartGlyphGeometryFT.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 project.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Leon Sha <leon.sha@sun.com>
00024  *   Alex Fritze <alex@croczilla.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either of the GNU General Public License Version 2 or later (the "GPL"),
00028  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 
00041 #include "nsCOMPtr.h"
00042 #include "nsISVGRendererGlyphGeometry.h"
00043 #include "nsIDOMSVGMatrix.h"
00044 #include "nsISVGGlyphGeometrySource.h"
00045 #include "nsPromiseFlatString.h"
00046 #include "nsPresContext.h"
00047 #include "nsMemory.h"
00048 
00049 #include "nsSVGLibartFreetype.h"
00050 #include "nsIServiceManager.h"
00051 #include "nsISVGLibartGlyphMetricsFT.h"
00052 #include "libart-incs.h"
00053 #include "nsISVGLibartCanvas.h"
00054 
00055 #include "nsPresContext.h"
00056 #include "nsIDeviceContext.h"
00057 #include "nsIComponentManager.h"
00058 
00059 #include "nsSVGLibartGradient.h"
00060 
00061 #include "nsSVGTypeCIDs.h"
00062 #include "nsIComponentManager.h"
00063 #include "nsIDOMSVGRect.h"
00064 
00069 
00070 
00073 class nsSVGLibartGlyphGeometryFT : public nsISVGRendererGlyphGeometry
00074 {
00075 protected:
00076   friend nsresult NS_NewSVGLibartGlyphGeometryFT(nsISVGRendererGlyphGeometry **result,
00077                                                  nsISVGGlyphGeometrySource *src);
00078 
00079   nsSVGLibartGlyphGeometryFT();
00080   ~nsSVGLibartGlyphGeometryFT();
00081   nsresult Init(nsISVGGlyphGeometrySource* src);
00082 
00083 public:
00084   // nsISupports interface:
00085   NS_DECL_ISUPPORTS
00086 
00087   // nsISVGRendererGlyphGeometry interface:
00088   NS_DECL_NSISVGRENDERERGLYPHGEOMETRY
00089 
00090 protected:
00091   void PaintFill(nsISVGLibartCanvas* canvas, nsISVGLibartGlyphMetricsFT* metrics);
00092   nsCOMPtr<nsISVGGlyphGeometrySource> mSource;
00093 
00094 
00095   
00096 };
00097 
00100 //----------------------------------------------------------------------
00101 // implementation:
00102 
00103 nsSVGLibartGlyphGeometryFT::nsSVGLibartGlyphGeometryFT()
00104 {
00105 }
00106 
00107 nsSVGLibartGlyphGeometryFT::~nsSVGLibartGlyphGeometryFT()
00108 {
00109 }
00110 
00111 nsresult
00112 nsSVGLibartGlyphGeometryFT::Init(nsISVGGlyphGeometrySource* src)
00113 {
00114   mSource = src;
00115   return NS_OK;
00116 }
00117 
00118 nsresult
00119 NS_NewSVGLibartGlyphGeometryFT(nsISVGRendererGlyphGeometry **result,
00120                                nsISVGGlyphGeometrySource *src)
00121 {
00122   *result = nsnull;
00123   
00124   nsSVGLibartGlyphGeometryFT* gg = new nsSVGLibartGlyphGeometryFT();
00125   if (!gg) return NS_ERROR_OUT_OF_MEMORY;
00126 
00127   NS_ADDREF(gg);
00128 
00129   nsresult rv = gg->Init(src);
00130 
00131   if (NS_FAILED(rv)) {
00132     NS_RELEASE(gg);
00133     return rv;
00134   }
00135   
00136   *result = gg;
00137   return rv;
00138 }
00139 
00140 //----------------------------------------------------------------------
00141 // nsISupports methods:
00142 
00143 NS_IMPL_ADDREF(nsSVGLibartGlyphGeometryFT)
00144 NS_IMPL_RELEASE(nsSVGLibartGlyphGeometryFT)
00145 
00146 NS_INTERFACE_MAP_BEGIN(nsSVGLibartGlyphGeometryFT)
00147   NS_INTERFACE_MAP_ENTRY(nsISVGRendererGlyphGeometry)
00148   NS_INTERFACE_MAP_ENTRY(nsISupports)
00149 NS_INTERFACE_MAP_END
00150 
00151 
00152 //----------------------------------------------------------------------
00153 // nsISVGRendererGlyphGeometry methods:
00154 
00156 NS_IMETHODIMP
00157 nsSVGLibartGlyphGeometryFT::Render(nsISVGRendererCanvas *canvas)
00158 {
00159   nsCOMPtr<nsISVGLibartCanvas> libartCanvas = do_QueryInterface(canvas);
00160   NS_ASSERTION(libartCanvas, "wrong svg render context for geometry!");
00161   if (!libartCanvas) return NS_ERROR_FAILURE;
00162   
00163   nsCOMPtr<nsISVGLibartGlyphMetricsFT> metrics;
00164   {
00165     nsCOMPtr<nsISVGRendererGlyphMetrics> xpmetrics;
00166     mSource->GetMetrics(getter_AddRefs(xpmetrics));
00167     metrics = do_QueryInterface(xpmetrics);
00168     NS_ASSERTION(metrics, "wrong metrics object!");
00169     if (!metrics) return NS_ERROR_FAILURE;
00170   }
00171 
00172   PRBool hasFill = PR_FALSE;
00173   {
00174     PRUint16 filltype;
00175     mSource->GetFillPaintType(&filltype);
00176     if (filltype == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR || 
00177         filltype == nsISVGGeometrySource::PAINT_TYPE_SERVER)
00178       hasFill = PR_TRUE;
00179   }
00180 
00181   PRBool hasStroke = PR_FALSE;
00182   {
00183     PRUint16 stroketype;
00184     mSource->GetStrokePaintType(&stroketype);
00185     if (stroketype == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR || 
00186         stroketype == nsISVGGeometrySource::PAINT_TYPE_SERVER)
00187       hasStroke = PR_TRUE;
00188   }
00189 
00190   if (hasFill)
00191     PaintFill(libartCanvas, metrics);
00192 
00193 //  XXX
00194 //  if (hasStroke)
00195 //    PaintStroke(libartCanvas, metrics);
00196   
00197   return NS_OK;
00198 }
00199 
00200 
00202 NS_IMETHODIMP
00203 nsSVGLibartGlyphGeometryFT::Update(PRUint32 updatemask, nsISVGRendererRegion **_retval)
00204 {
00205   *_retval = nsnull;      
00206   return NS_OK;
00207 }
00208 
00210 NS_IMETHODIMP
00211 nsSVGLibartGlyphGeometryFT::GetCoveredRegion(nsISVGRendererRegion **_retval)
00212 {
00213   *_retval = nsnull;
00214   return NS_OK;
00215 }
00216 
00218 NS_IMETHODIMP
00219 nsSVGLibartGlyphGeometryFT::ContainsPoint(float x, float y, PRBool *_retval)
00220 {
00221   *_retval = PR_FALSE;
00222   return NS_OK;
00223 }
00224 
00225 void
00226 nsSVGLibartGlyphGeometryFT::PaintFill(nsISVGLibartCanvas* canvas,
00227                                       nsISVGLibartGlyphMetricsFT* metrics)
00228 {
00229   FT_Matrix xform;
00230   FT_Vector delta;
00231   {
00232     float x,y;
00233     mSource->GetX(&x);
00234     mSource->GetY(&y);
00235     
00236     nsCOMPtr<nsIDOMSVGMatrix> ctm;
00237     mSource->GetCanvasTM(getter_AddRefs(ctm));
00238     NS_ASSERTION(ctm, "graphic source didn't specify a ctm");
00239 
00240     // negations of B,C,F are to transform matrix from y-down to y-up
00241 
00242     float a,b,c,d,e,f;
00243     ctm->GetA(&a);
00244     xform.xx = (FT_Fixed)(a*0x10000L); // convert to 16.16 fixed
00245     ctm->GetB(&b);
00246     xform.yx = (FT_Fixed)(-b*0x10000L);
00247     ctm->GetC(&c);
00248     xform.xy = (FT_Fixed)(-c*0x10000L);
00249     ctm->GetD(&d);
00250     xform.yy = (FT_Fixed)(d*0x10000L);
00251     ctm->GetE(&e);
00252     delta.x = (FT_Pos)((a*x+c*y+e)*64); // convert to 26.6 fixed
00253     ctm->GetF(&f);
00254     delta.y = (FT_Pos)(-(b*x+d*y+f)*64);
00255   }
00256   
00257   float opacity;
00258   mSource->GetFillOpacity(&opacity);
00259 
00260   // Define the variables we want to fill only once and use in the loop
00261   ArtColor fill_color;
00262   PRUint16 type;
00263   nsCOMPtr<nsISVGGradient> aGrad;
00264   nsCOMPtr<nsISVGLibartRegion> aLibartRegion;
00265 
00266   // Get the fill type
00267   mSource->GetFillPaintType(&type);
00268   if (type == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR) {
00269     nscolor rgb;
00270     mSource->GetFillPaint(&rgb);
00271     canvas->GetArtColor(rgb, fill_color);
00272   } else if (type == nsISVGGeometrySource::PAINT_TYPE_SERVER) {
00273     // Handle gradients
00274     mSource->GetFillGradient(getter_AddRefs(aGrad));
00275 
00276     // Now, get the appropriate gradient fill
00277     nsCOMPtr<nsISVGRendererRegion> region;
00278     GetCoveredRegion(getter_AddRefs(region));
00279     aLibartRegion = do_QueryInterface(region);
00280   }
00281   
00282   PRUint32 glyph_count = metrics->GetGlyphCount();
00283   
00284   for (PRUint32 i=0; i<glyph_count; ++i) {
00285     FT_Glyph glyph;
00286     nsSVGLibartFreetype::ft2->GlyphCopy(metrics->GetGlyphAt(i), &glyph);
00287 
00288     nsSVGLibartFreetype::ft2->GlyphTransform(glyph, &xform, &delta);
00289     
00290     if (NS_SUCCEEDED(nsSVGLibartFreetype::ft2->GlyphToBitmap(&glyph,
00291                                                              FT_RENDER_MODE_NORMAL,
00292                                                              nsnull, // translation
00293                                                              1 // destroy glyph copy
00294                                                              ))) {
00295       FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyph;
00296       
00297       ArtRender* render = canvas->NewRender(bitmap->left,
00298                                             -bitmap->top,
00299                                             bitmap->left+bitmap->bitmap.width,
00300                                             -bitmap->top+bitmap->bitmap.rows);
00301       if (render) {
00302         if(type == nsISVGGeometrySource::PAINT_TYPE_SOLID_COLOR)
00303           art_render_image_solid(render, fill_color);
00304         else if (type == nsISVGGeometrySource::PAINT_TYPE_SERVER) {
00305           nsCOMPtr<nsIDOMSVGMatrix> ctm;
00306           mSource->GetCanvasTM(getter_AddRefs(ctm));
00307           LibartGradient(render, ctm, aGrad, aLibartRegion, mSource);
00308         }
00309         art_render_mask_solid(render, (int)(0x10000*opacity));
00310         
00311         art_render_mask(render,
00312                         bitmap->left,
00313                         -bitmap->top,
00314                         bitmap->left+bitmap->bitmap.width,
00315                         -bitmap->top+bitmap->bitmap.rows,
00316                         bitmap->bitmap.buffer,
00317                         bitmap->bitmap.pitch);
00318         canvas->InvokeRender(render);
00319       }
00320     }
00321     nsSVGLibartFreetype::ft2->DoneGlyph(glyph);
00322   }
00323 }
00324 
00325 NS_IMETHODIMP
00326 nsSVGLibartGlyphGeometry::GetBoundingBox(nsIDOMSVGRect * *aBoundingBox)
00327 {
00328   *aBoundingBox = nsnull;
00329 
00330   nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00331   NS_ASSERTION(rect, "could not create rect");
00332   if (!rect)
00333     return NS_ERROR_FAILURE;
00334 
00335   nsCOMPtr<nsISVGLibartGlyphMetricsFT> metrics;
00336   {
00337     nsCOMPtr<nsISVGRendererGlyphMetrics> xpmetrics;
00338     mSource->GetMetrics(getter_AddRefs(xpmetrics));
00339     metrics = do_QueryInterface(xpmetrics);
00340     NS_ASSERTION(metrics, "wrong metrics object!");
00341     if (!metrics) return NS_ERROR_FAILURE;
00342   }
00343 
00344   const FT_BBox *box = metrics->GetBoundingBox();
00345 
00346   float x,y;
00347   mSource->GetX(&x);
00348   mSource->GetY(&y);
00349   
00350   rect->SetX(box->xMin + x);
00351   rect->SetY(box->yMin + y);
00352   rect->SetWidth(box->xMax - box->xMin);
00353   rect->SetHeight(box->yMax - box->yMin);
00354 
00355   *aBoundingBox = rect;
00356   NS_ADDREF(*aBoundingBox);
00357 
00358   return NS_OK;
00359 }