00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <windows.h>
00040
00041
00042 #include <unknwn.h>
00043
00044 #include <Gdiplus.h>
00045 using namespace Gdiplus;
00046
00047 #include "nsCOMPtr.h"
00048 #include "nsISVGGlyphMetricsSource.h"
00049 #include "nsPromiseFlatString.h"
00050 #include "nsFont.h"
00051 #include "nsIPresContext.h"
00052 #include "nsDeviceContextWin.h"
00053 #include "nsISVGGDIPlusGlyphMetrics.h"
00054 #include "nsSVGGDIPlusGlyphMetrics.h"
00055 #include "float.h"
00056 #include "nsIDOMSVGMatrix.h"
00057 #include "nsIDOMSVGRect.h"
00058 #include "nsSVGTypeCIDs.h"
00059 #include "nsIComponentManager.h"
00060 #include "nsDataHashtable.h"
00061
00066
00067
00072 class nsWindowsDC {
00073 public:
00074 nsWindowsDC(nsIPresContext* presContext);
00075 ~nsWindowsDC();
00076 operator HDC() { return mHDC; }
00077 private:
00078 bool isWndDC;
00079 HWND mWND;
00080 HDC mHDC;
00081 };
00082
00086 nsWindowsDC::nsWindowsDC(nsIPresContext* presContext)
00087 {
00088 nsCOMPtr<nsIDeviceContext> devicecontext;
00089 presContext->GetDeviceContext(getter_AddRefs(devicecontext));
00090 NS_ASSERTION(devicecontext, "no device context");
00091
00092 isWndDC=((nsDeviceContextWin *)(devicecontext.get()))->mDC==nsnull;
00093 if (isWndDC) {
00094 mWND = (HWND)((nsDeviceContextWin *)(devicecontext.get()))->mWidget;
00095 NS_ASSERTION(mWND, "no window and no handle in devicecontext (continuing with screen dc)");
00096 mHDC = ::GetDC(mWND);
00097 }
00098 else
00099 mHDC = ((nsDeviceContextWin *)(devicecontext.get()))->mDC;
00100 }
00101
00102 nsWindowsDC::~nsWindowsDC()
00103 {
00104 if (isWndDC)
00105 ::ReleaseDC(mWND, mHDC);
00106 }
00107
00112
00113
00116 class nsSVGGDIPlusGlyphMetrics : public nsISVGGDIPlusGlyphMetrics
00117 {
00118 protected:
00119 friend nsresult NS_NewSVGGDIPlusGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00120 nsISVGGlyphMetricsSource *src);
00121 friend void NS_InitSVGGDIPlusGlyphMetricsGlobals();
00122 friend void NS_FreeSVGGDIPlusGlyphMetricsGlobals();
00123 nsSVGGDIPlusGlyphMetrics(nsISVGGlyphMetricsSource *src);
00124 ~nsSVGGDIPlusGlyphMetrics();
00125 public:
00126
00127 NS_DECL_ISUPPORTS
00128
00129
00130 NS_DECL_NSISVGRENDERERGLYPHMETRICS
00131
00132
00133 NS_IMETHOD_(const RectF*) GetBoundingRect();
00134 NS_IMETHOD_(void) GetSubBoundingRect(PRUint32 charoffset, PRUint32 count, RectF* retval);
00135 NS_IMETHOD_(const Font*) GetFont();
00136 NS_IMETHOD_(TextRenderingHint) GetTextRenderingHint();
00137
00138 protected:
00139 void MarkRectForUpdate() { mRectNeedsUpdate = PR_TRUE; }
00140 void ClearFontInfo() { if (mFont) { delete mFont; mFont = nsnull; }}
00141 void InitializeFontInfo();
00142 void GetGlobalTransform(Matrix *matrix);
00143 void PrepareGraphics(Graphics &g);
00144 float GetPixelScale();
00145
00146 private:
00147 PRBool mRectNeedsUpdate;
00148 RectF mRect;
00149 Font *mFont;
00150 nsCOMPtr<nsISVGGlyphMetricsSource> mSource;
00151
00152 public:
00153 static nsDataHashtable<nsStringHashKey,nsDependentString*> sFontAliases;
00154 };
00155
00158
00159
00160
00161 nsDataHashtable<nsStringHashKey,nsDependentString*>
00162 nsSVGGDIPlusGlyphMetrics::sFontAliases;
00163
00164 nsSVGGDIPlusGlyphMetrics::nsSVGGDIPlusGlyphMetrics(nsISVGGlyphMetricsSource *src)
00165 : mRectNeedsUpdate(PR_TRUE), mFont(nsnull), mSource(src)
00166 {
00167 }
00168
00169 nsSVGGDIPlusGlyphMetrics::~nsSVGGDIPlusGlyphMetrics()
00170 {
00171 ClearFontInfo();
00172 }
00173
00174 nsresult
00175 NS_NewSVGGDIPlusGlyphMetrics(nsISVGRendererGlyphMetrics **result,
00176 nsISVGGlyphMetricsSource *src)
00177 {
00178 *result = new nsSVGGDIPlusGlyphMetrics(src);
00179 if (!*result) return NS_ERROR_OUT_OF_MEMORY;
00180
00181 NS_ADDREF(*result);
00182 return NS_OK;
00183 }
00184
00185 void NS_InitSVGGDIPlusGlyphMetricsGlobals()
00186 {
00187 NS_ASSERTION(!nsSVGGDIPlusGlyphMetrics::sFontAliases.IsInitialized(),
00188 "already initialized");
00189 nsSVGGDIPlusGlyphMetrics::sFontAliases.Init(3);
00190
00191 static NS_NAMED_LITERAL_STRING(arial, "arial");
00192 nsSVGGDIPlusGlyphMetrics::sFontAliases.Put(NS_LITERAL_STRING("helvetica"),
00193 &arial);
00194
00195 static NS_NAMED_LITERAL_STRING(courier, "courier new");
00196 nsSVGGDIPlusGlyphMetrics::sFontAliases.Put(NS_LITERAL_STRING("courier"),
00197 &courier);
00198
00199 static NS_NAMED_LITERAL_STRING(times, "times new roman");
00200 nsSVGGDIPlusGlyphMetrics::sFontAliases.Put(NS_LITERAL_STRING("times"),
00201 ×);
00202 }
00203
00204 void NS_FreeSVGGDIPlusGlyphMetricsGlobals()
00205 {
00206 nsSVGGDIPlusGlyphMetrics::sFontAliases.Clear();
00207 }
00208
00209
00210
00211
00212 NS_IMPL_ADDREF(nsSVGGDIPlusGlyphMetrics)
00213 NS_IMPL_RELEASE(nsSVGGDIPlusGlyphMetrics)
00214
00215 NS_INTERFACE_MAP_BEGIN(nsSVGGDIPlusGlyphMetrics)
00216 NS_INTERFACE_MAP_ENTRY(nsISVGRendererGlyphMetrics)
00217 NS_INTERFACE_MAP_ENTRY(nsISVGGDIPlusGlyphMetrics)
00218 NS_INTERFACE_MAP_ENTRY(nsISupports)
00219 NS_INTERFACE_MAP_END
00220
00221
00222
00223
00225 NS_IMETHODIMP
00226 nsSVGGDIPlusGlyphMetrics::GetBaselineOffset(PRUint16 baselineIdentifier, float *_retval)
00227 {
00228 if (!GetFont()) {
00229 NS_ERROR("no font");
00230 return NS_ERROR_FAILURE;
00231 }
00232 NS_ASSERTION(GetFont()->GetUnit()==UnitPixel, "font unit is not in world units");
00233
00234 switch (baselineIdentifier) {
00235 case BASELINE_TEXT_BEFORE_EDGE:
00236 *_retval = GetBoundingRect()->Y;
00237 break;
00238 case BASELINE_TEXT_AFTER_EDGE:
00239 *_retval = (float)(UINT16)(GetBoundingRect()->Y + GetBoundingRect()->Height + 0.5);
00240 break;
00241 case BASELINE_CENTRAL:
00242 case BASELINE_MIDDLE:
00243 *_retval = (float)(UINT16)(GetBoundingRect()->Y + GetBoundingRect()->Height/2.0 + 0.5);
00244 break;
00245 case BASELINE_ALPHABETIC:
00246 default:
00247 {
00248 FontFamily family;
00249 GetFont()->GetFamily(&family);
00250 INT style = GetFont()->GetStyle();
00251
00252
00253 *_retval = (float)(UINT16)(GetBoundingRect()->Y
00254 + GetFont()->GetSize()
00255 *family.GetCellAscent(style)/family.GetEmHeight(style)
00256 + 0.5);
00257 #ifdef DEBUG
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 #endif
00288 }
00289 break;
00290 }
00291
00292 return NS_OK;
00293 }
00294
00295
00297 NS_IMETHODIMP
00298 nsSVGGDIPlusGlyphMetrics::GetAdvance(float *aAdvance)
00299 {
00300
00301 *aAdvance = GetBoundingRect()->Width;
00302 return NS_OK;
00303 }
00304
00306 NS_IMETHODIMP
00307 nsSVGGDIPlusGlyphMetrics::GetBoundingBox(nsIDOMSVGRect * *aBoundingBox)
00308 {
00309 *aBoundingBox = nsnull;
00310
00311 nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00312
00313 NS_ASSERTION(rect, "could not create rect");
00314 if (!rect) return NS_ERROR_FAILURE;
00315
00316 rect->SetX(GetBoundingRect()->X);
00317 rect->SetY(GetBoundingRect()->Y);
00318 rect->SetWidth(GetBoundingRect()->Width);
00319 rect->SetHeight(GetBoundingRect()->Height);
00320
00321 *aBoundingBox = rect;
00322 NS_ADDREF(*aBoundingBox);
00323
00324 return NS_OK;
00325 }
00326
00328 NS_IMETHODIMP
00329 nsSVGGDIPlusGlyphMetrics::GetExtentOfChar(PRUint32 charnum, nsIDOMSVGRect **_retval)
00330 {
00331 *_retval = nsnull;
00332
00333 RectF bounds;
00334 GetSubBoundingRect(charnum, 1, &bounds);
00335
00336 nsCOMPtr<nsIDOMSVGRect> rect = do_CreateInstance(NS_SVGRECT_CONTRACTID);
00337
00338 NS_ASSERTION(rect, "could not create rect");
00339 if (!rect) return NS_ERROR_FAILURE;
00340
00341 rect->SetX(bounds.X);
00342 rect->SetY(bounds.Y);
00343 rect->SetWidth(bounds.Width);
00344 rect->SetHeight(bounds.Height);
00345
00346 *_retval = rect;
00347 NS_ADDREF(*_retval);
00348
00349 return NS_OK;
00350 }
00351
00353 NS_IMETHODIMP
00354 nsSVGGDIPlusGlyphMetrics::Update(PRUint32 updatemask, PRBool *_retval)
00355 {
00356 *_retval = PR_FALSE;
00357
00358 if (updatemask & nsISVGGlyphMetricsSource::UPDATEMASK_CHARACTER_DATA) {
00359 MarkRectForUpdate();
00360 *_retval = PR_TRUE;
00361 }
00362
00363 if (updatemask & nsISVGGlyphMetricsSource::UPDATEMASK_FONT) {
00364 ClearFontInfo();
00365 MarkRectForUpdate();
00366 *_retval = PR_TRUE;
00367 }
00368
00369 return NS_OK;
00370 }
00371
00372
00373
00374
00375 NS_IMETHODIMP_(const RectF*)
00376 nsSVGGDIPlusGlyphMetrics::GetBoundingRect()
00377 {
00378 if (!mRectNeedsUpdate) return &mRect;
00379 mRectNeedsUpdate = PR_FALSE;
00380
00381 nsAutoString text;
00382 mSource->GetCharacterData(text);
00383
00384 GetSubBoundingRect(0, text.Length(), &mRect);
00385
00386 return &mRect;
00387
00388 }
00389
00390 NS_IMETHODIMP_(void)
00391 nsSVGGDIPlusGlyphMetrics::GetSubBoundingRect(PRUint32 charoffset, PRUint32 count,
00392 RectF* retval)
00393 {
00394 nsCOMPtr<nsIPresContext> presContext;
00395 mSource->GetPresContext(getter_AddRefs(presContext));
00396 NS_ASSERTION(presContext, "null prescontext");
00397
00398 nsWindowsDC devicehandle(presContext);
00399 Graphics graphics(devicehandle);
00400 PrepareGraphics(graphics);
00401
00402 nsAutoString text;
00403 mSource->GetCharacterData(text);
00404
00405 StringFormat stringFormat(StringFormat::GenericTypographic());
00406 stringFormat.SetFormatFlags(stringFormat.GetFormatFlags() |
00407 StringFormatFlagsMeasureTrailingSpaces);
00408
00409 CharacterRange charRange(charoffset, count);
00410 stringFormat.SetMeasurableCharacterRanges(1, &charRange);
00411
00412 Region region;
00413 region.MakeEmpty();
00414
00415
00416 GraphicsState state = graphics.Save();
00417
00418 Matrix m;
00419 GetGlobalTransform(&m);
00420 graphics.MultiplyTransform(&m);
00421
00422 graphics.MeasureCharacterRanges(PromiseFlatString(text).get(), -1, GetFont(),
00423 RectF(0.0f, 0.0f, FLT_MAX, FLT_MAX), &stringFormat, 1, ®ion);
00424
00425 graphics.Restore(state);
00426
00427
00428 region.GetBounds(retval, &graphics);
00429 }
00430
00431 NS_IMETHODIMP_(const Font*)
00432 nsSVGGDIPlusGlyphMetrics::GetFont()
00433 {
00434 InitializeFontInfo();
00435 return mFont;
00436 }
00437
00438 NS_IMETHODIMP_(TextRenderingHint)
00439 nsSVGGDIPlusGlyphMetrics::GetTextRenderingHint()
00440 {
00441
00442
00443 bool forceUnhinted = PR_FALSE;
00444 {
00445 PRUint16 type;
00446 mSource->GetStrokePaintType(&type);
00447 forceUnhinted = (type != nsISVGGeometrySource::PAINT_TYPE_NONE);
00448 }
00449
00450 PRUint16 textRendering;
00451 mSource->GetTextRendering(&textRendering);
00452 switch (textRendering) {
00453 case nsISVGGlyphMetricsSource::TEXT_RENDERING_OPTIMIZESPEED:
00454 return TextRenderingHintSingleBitPerPixel;
00455 break;
00456 case nsISVGGlyphMetricsSource::TEXT_RENDERING_OPTIMIZELEGIBILITY:
00457 return forceUnhinted ?
00458 TextRenderingHintAntiAlias :
00459 TextRenderingHintAntiAliasGridFit;
00460 break;
00461 case nsISVGGlyphMetricsSource::TEXT_RENDERING_GEOMETRICPRECISION:
00462 case nsISVGGlyphMetricsSource::TEXT_RENDERING_AUTO:
00463 default:
00464 return TextRenderingHintAntiAlias;
00465 break;
00466 }
00467 }
00468
00469
00470
00471
00472 static PRBool FindFontFamily(const nsString& aFamily, PRBool aGeneric, void *aData)
00473 {
00474 PRBool retval = PR_TRUE;
00475
00476 #ifdef DEBUG
00477
00478
00479 #endif
00480
00481 FontFamily *family = nsnull;
00482 if (!aGeneric)
00483 family = new FontFamily(aFamily.get());
00484 else {
00485 PRUint8 id;
00486 nsFont::GetGenericID(aFamily, &id);
00487 switch (id) {
00488 case kGenericFont_serif:
00489 family = FontFamily::GenericSerif()->Clone();
00490 break;
00491 case kGenericFont_monospace:
00492 family = FontFamily::GenericMonospace()->Clone();
00493 break;
00494 case kGenericFont_sans_serif:
00495 default:
00496 family = FontFamily::GenericSansSerif()->Clone();
00497 break;
00498 }
00499 }
00500
00501 if (family->IsAvailable()) {
00502 retval = PR_FALSE;
00503 *(FontFamily**)aData = family;
00504 }
00505 else {
00506 delete family;
00507
00508
00509 nsDependentString *alias = nsnull;
00510 nsAutoString canonical_name(aFamily);
00511 ToLowerCase(canonical_name);
00512 nsSVGGDIPlusGlyphMetrics::sFontAliases.Get(canonical_name, &alias);
00513 if (alias) {
00514
00515
00516 retval = FindFontFamily(nsString(*alias), PR_FALSE, aData);
00517 }
00518 }
00519
00520 return retval;
00521 }
00522
00523 void
00524 nsSVGGDIPlusGlyphMetrics::InitializeFontInfo()
00525 {
00526 if (mFont) return;
00527
00528 nsCOMPtr<nsIPresContext> presContext;
00529 mSource->GetPresContext(getter_AddRefs(presContext));
00530 if (!presContext) {
00531 NS_ERROR("null prescontext");
00532 return;
00533 }
00534
00535 float pxPerTwips;
00536 presContext->GetTwipsToPixels(&pxPerTwips);
00537 pxPerTwips/=GetPixelScale();
00538
00539 nsFont font;
00540 mSource->GetFont(&font);
00541
00542 FontFamily *pFamily = nsnull;
00543 font.EnumerateFamilies(FindFontFamily, (void*)&pFamily);
00544 NS_ASSERTION(pFamily, "couldn't create family");
00545
00546 int style = FontStyleRegular;
00547 if (font.style == NS_FONT_STYLE_ITALIC) style |= FontStyleItalic;
00548 if (font.weight % 100 == 0) {
00549 if (font.weight >= 600) style |= FontStyleBold;
00550 }
00551 else if (font.weight % 100 < 50) {
00552 style |= FontStyleBold;
00553 }
00554
00555 if (font.decorations & NS_FONT_DECORATION_UNDERLINE) style |= FontStyleUnderline;
00556 if (font.decorations & NS_FONT_DECORATION_LINE_THROUGH) style |= FontStyleStrikeout;
00557
00558 mFont = new Font(pFamily, font.size*pxPerTwips, style, UnitPixel);
00559 NS_ASSERTION(mFont->IsAvailable(),"font not available");
00560 delete pFamily;
00561 pFamily = nsnull;
00562
00563 #ifdef DEBUG
00564
00565
00566
00567
00568
00569
00570
00571 #endif
00572 }
00573
00574 void
00575 nsSVGGDIPlusGlyphMetrics::GetGlobalTransform(Matrix *matrix)
00576 {
00577 nsCOMPtr<nsIDOMSVGMatrix> ctm;
00578 mSource->GetCTM(getter_AddRefs(ctm));
00579 NS_ASSERTION(ctm, "graphic source didn't specify a ctm");
00580
00581 float m[6];
00582 float val;
00583 ctm->GetA(&val);
00584 m[0] = val;
00585
00586 ctm->GetB(&val);
00587 m[1] = val;
00588
00589 ctm->GetC(&val);
00590 m[2] = val;
00591
00592 ctm->GetD(&val);
00593 m[3] = val;
00594
00595 ctm->GetE(&val);
00596 m[4] = val;
00597
00598 ctm->GetF(&val);
00599 m[5] = val;
00600
00601 matrix->SetElements(m[0],m[1],m[2],m[3],m[4],m[5]);
00602 }
00603
00604
00605 void
00606 nsSVGGDIPlusGlyphMetrics::PrepareGraphics(Graphics &g)
00607 {
00608 g.SetPageUnit(UnitPixel);
00609
00610
00611
00612 g.SetPageScale(GetPixelScale());
00613 g.SetSmoothingMode(SmoothingModeAntiAlias);
00614
00615 g.SetTextRenderingHint(GetTextRenderingHint());
00616 }
00617
00618 float
00619 nsSVGGDIPlusGlyphMetrics::GetPixelScale()
00620 {
00621 nsCOMPtr<nsIPresContext> presContext;
00622 mSource->GetPresContext(getter_AddRefs(presContext));
00623 if (!presContext) {
00624 NS_ERROR("null prescontext");
00625 return 1.0f;
00626 }
00627
00628 nsCOMPtr<nsIDeviceContext> devicecontext;
00629 presContext->GetDeviceContext(getter_AddRefs(devicecontext));
00630
00631 float scale;
00632 devicecontext->GetCanonicalPixelScale(scale);
00633 return scale;
00634 }