1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * The contents of this file are subject to the Netscape Public
4 * License Version 1.1 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of
6 * the License at http://www.mozilla.org/NPL/
8 * Software distributed under the License is distributed on an "AS
9 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10 * implied. See the License for the specific language governing
11 * rights and limitations under the License.
13 * The Original Code is mozilla.org code.
15 * The Initial Developer of the Original Code is Netscape
16 * Communications Corporation. Portions created by Netscape are
17 * Copyright (C) 1998 Netscape Communications Corporation. All
21 * Roland Mainz <Roland.Mainz@informatik.med.uni-giessen.de>
23 * This Original Code has been modified by IBM Corporation. Modifications made by IBM
24 * described herein are Copyright (c) International Business Machines Corporation, 2000.
25 * Modifications to Mozilla code or documentation identified per MPL Section 3.3
27 * Date Modified by Description of modification
28 * 04/20/2000 IBM Corp. OS/2 VisualAge build.
31 #include "nsDeviceContext.h"
34 #include "nsGfxCIID.h"
35 #include "nsVoidArray.h"
36 #include "nsIFontMetrics.h"
37 #include "nsHashtable.h"
38 #include "nsILanguageAtomService.h"
39 #include "nsIServiceManager.h"
41 // Needed for Localization
42 #include "nsIServiceManager.h"
43 #include "nsIIOService.h"
45 #include "nsIStringBundle.h"
46 #include "nsITextContent.h"
47 #include "nsISupportsArray.h"
48 #include "nsXPIDLString.h"
51 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
52 static NS_DEFINE_CID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
55 NS_IMPL_ISUPPORTS1(DeviceContextImpl, nsIDeviceContext)
57 DeviceContextImpl :: DeviceContextImpl()
61 mDevUnitsToAppUnits = 1.0f;
62 mAppUnitsToDevUnits = 1.0f;
65 mGammaTable = new PRUint8[256];
69 mFontAliasTable = nsnull;
72 static PRBool PR_CALLBACK DeleteValue(nsHashKey* aKey, void* aValue, void* closure)
74 delete ((nsString*)aValue);
78 DeviceContextImpl :: ~DeviceContextImpl()
80 if (nsnull != mFontCache)
86 if (nsnull != mGammaTable)
92 if (nsnull != mFontAliasTable) {
93 mFontAliasTable->Enumerate(DeleteValue);
94 delete mFontAliasTable;
98 NS_IMETHODIMP DeviceContextImpl :: Init(nsNativeWidget aWidget)
107 void DeviceContextImpl :: CommonInit(void)
109 for (PRInt32 cnt = 0; cnt < 256; cnt++)
110 mGammaTable[cnt] = cnt;
113 NS_IMETHODIMP DeviceContextImpl :: GetTwipsToDevUnits(float &aTwipsToDevUnits) const
115 aTwipsToDevUnits = mTwipsToPixels;
119 NS_IMETHODIMP DeviceContextImpl :: GetDevUnitsToTwips(float &aDevUnitsToTwips) const
121 aDevUnitsToTwips = mPixelsToTwips;
125 NS_IMETHODIMP DeviceContextImpl :: SetAppUnitsToDevUnits(float aAppUnits)
127 mAppUnitsToDevUnits = aAppUnits;
131 NS_IMETHODIMP DeviceContextImpl :: SetDevUnitsToAppUnits(float aDevUnits)
133 mDevUnitsToAppUnits = aDevUnits;
137 NS_IMETHODIMP DeviceContextImpl :: GetAppUnitsToDevUnits(float &aAppUnits) const
139 aAppUnits = mAppUnitsToDevUnits;
143 NS_IMETHODIMP DeviceContextImpl :: GetDevUnitsToAppUnits(float &aDevUnits) const
145 aDevUnits = mDevUnitsToAppUnits;
149 NS_IMETHODIMP DeviceContextImpl :: GetCanonicalPixelScale(float &aScale) const
151 aScale = mCPixelScale;
155 static NS_DEFINE_CID(kRCCID, NS_RENDERING_CONTEXT_CID);
157 NS_IMETHODIMP DeviceContextImpl :: CreateRenderingContext(nsIView *aView, nsIRenderingContext *&aContext)
159 nsIRenderingContext *pContext;
161 aView->GetWidget(win);
165 rv = nsComponentManager::CreateInstance(kRCCID, nsnull, NS_GET_IID(nsIRenderingContext), (void **)&pContext);
168 rv = InitRenderingContext(pContext, win);
170 NS_RELEASE(pContext);
179 NS_IMETHODIMP DeviceContextImpl :: CreateRenderingContext(nsIWidget *aWidget, nsIRenderingContext *&aContext)
181 nsIRenderingContext *pContext;
185 rv = nsComponentManager::CreateInstance(kRCCID, nsnull, NS_GET_IID(nsIRenderingContext), (void **)&pContext);
188 rv = InitRenderingContext(pContext, aWidget);
190 NS_RELEASE(pContext);
198 NS_IMETHODIMP DeviceContextImpl :: InitRenderingContext(nsIRenderingContext *aContext, nsIWidget *aWin)
200 return aContext->Init(this, aWin);
203 NS_IMETHODIMP DeviceContextImpl::CreateFontCache()
205 mFontCache = new nsFontCache();
206 if (nsnull == mFontCache) {
207 return NS_ERROR_OUT_OF_MEMORY;
209 mFontCache->Init(this);
214 DeviceContextImpl::GetLocaleLangGroup(void)
216 if (!mLocaleLangGroup) {
217 nsCOMPtr<nsILanguageAtomService> langService;
218 langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
220 langService->GetLocaleLanguageGroup(getter_AddRefs(mLocaleLangGroup));
222 if (!mLocaleLangGroup) {
223 mLocaleLangGroup = getter_AddRefs(NS_NewAtom("x-western"));
228 NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont,
229 nsIAtom* aLangGroup, nsIFontMetrics*& aMetrics)
231 if (nsnull == mFontCache) {
232 nsresult rv = CreateFontCache();
237 // XXX temporary fix for performance problem -- erik
238 GetLocaleLangGroup();
241 // XXX figure out why aLangGroup is NULL sometimes
243 aLangGroup = mLocaleLangGroup;
246 return mFontCache->GetMetricsFor(aFont, aLangGroup, aMetrics);
249 NS_IMETHODIMP DeviceContextImpl::GetMetricsFor(const nsFont& aFont, nsIFontMetrics*& aMetrics)
251 if (nsnull == mFontCache) {
252 nsresult rv = CreateFontCache();
257 // XXX temporary fix for performance problem -- erik
258 GetLocaleLangGroup();
260 return mFontCache->GetMetricsFor(aFont, mLocaleLangGroup, aMetrics);
263 NS_IMETHODIMP DeviceContextImpl :: SetZoom(float aZoom)
265 if (mZoom != aZoom) {
272 NS_IMETHODIMP DeviceContextImpl :: GetZoom(float &aZoom) const
278 NS_IMETHODIMP DeviceContextImpl :: SetTextZoom(float aTextZoom)
280 if (mTextZoom != aTextZoom) {
281 mTextZoom = aTextZoom;
287 NS_IMETHODIMP DeviceContextImpl :: GetTextZoom(float &aTextZoom) const
289 aTextZoom = mTextZoom;
293 NS_IMETHODIMP DeviceContextImpl :: GetGamma(float &aGamma)
295 aGamma = mGammaValue;
299 NS_IMETHODIMP DeviceContextImpl :: SetGamma(float aGamma)
301 if (aGamma != mGammaValue)
303 //we don't need to-recorrect existing images for this case
304 //so pass in 1.0 for the current gamma regardless of what it
305 //really happens to be. existing images will get a one time
306 //re-correction when they're rendered the next time. MMP
308 SetGammaTable(mGammaTable, 1.0f, aGamma);
310 mGammaValue = aGamma;
315 NS_IMETHODIMP DeviceContextImpl :: GetGammaTable(PRUint8 *&aGammaTable)
317 //XXX we really need to ref count this somehow. MMP
318 aGammaTable = mGammaTable;
322 void DeviceContextImpl :: SetGammaTable(PRUint8 * aTable, float aCurrentGamma, float aNewGamma)
324 double fgval = (1.0f / aCurrentGamma) * (1.0f / aNewGamma);
326 for (PRInt32 cnt = 0; cnt < 256; cnt++)
327 aTable[cnt] = (PRUint8)(pow((double)cnt * (1. / 256.), fgval) * 255.99999999);
330 NS_IMETHODIMP DeviceContextImpl::GetDepth(PRUint32& aDepth)
336 struct FontEnumData {
337 FontEnumData(nsIDeviceContext* aDC, nsString& aFaceName)
338 : mDC(aDC), mFaceName(aFaceName)
340 nsIDeviceContext* mDC;
344 static PRBool FontEnumCallback(const nsString& aFamily, PRBool aGeneric, void *aData)
346 FontEnumData* data = (FontEnumData*)aData;
347 // XXX for now, all generic fonts are presumed to exist
348 // we may want to actually check if there's an installed conversion
350 data->mFaceName = aFamily;
351 return PR_FALSE; // found one, stop.
356 data->mDC->GetLocalFontName(aFamily, local, aliased);
357 if (aliased || (NS_OK == data->mDC->CheckFontExistence(local))) {
358 data->mFaceName = local;
359 return PR_FALSE; // found one, stop.
362 return PR_TRUE; // didn't exist, continue looking
365 NS_IMETHODIMP DeviceContextImpl::FirstExistingFont(const nsFont& aFont, nsString& aFaceName)
367 FontEnumData data(this, aFaceName);
368 if (aFont.EnumerateFamilies(FontEnumCallback, &data)) {
369 return NS_ERROR_FAILURE; // ran out
374 class FontAliasKey: public nsHashKey
377 FontAliasKey(const nsString& aString)
378 {mString.Assign(aString);}
380 virtual PRUint32 HashCode(void) const;
381 virtual PRBool Equals(const nsHashKey *aKey) const;
382 virtual nsHashKey *Clone(void) const;
384 nsAutoString mString;
387 PRUint32 FontAliasKey::HashCode(void) const
390 const PRUnichar* string = mString.get();
392 while ((ch = *string++) != 0) {
393 // FYI: hash = hash*37 + ch
394 ch = nsCRT::ToUpper(ch);
395 hash = ((hash << 5) + (hash << 2) + hash) + ch;
400 PRBool FontAliasKey::Equals(const nsHashKey *aKey) const
402 return mString.EqualsIgnoreCase(((FontAliasKey*)aKey)->mString);
405 nsHashKey* FontAliasKey::Clone(void) const
407 return new FontAliasKey(mString);
409 nsresult DeviceContextImpl::CreateFontAliasTable()
411 nsresult result = NS_OK;
413 if (nsnull == mFontAliasTable) {
414 mFontAliasTable = new nsHashtable();
415 if (nsnull != mFontAliasTable) {
417 nsAutoString times; times.AssignWithConversion("Times");
418 nsAutoString timesNewRoman; timesNewRoman.AssignWithConversion("Times New Roman");
419 nsAutoString timesRoman; timesRoman.AssignWithConversion("Times Roman");
420 nsAutoString arial; arial.AssignWithConversion("Arial");
421 nsAutoString helvetica; helvetica.AssignWithConversion("Helvetica");
422 nsAutoString courier; courier.AssignWithConversion("Courier");
423 nsAutoString courierNew; courierNew.AssignWithConversion("Courier New");
424 nsAutoString nullStr;
426 AliasFont(times, timesNewRoman, timesRoman, PR_FALSE);
427 AliasFont(timesRoman, timesNewRoman, times, PR_FALSE);
428 AliasFont(timesNewRoman, timesRoman, times, PR_FALSE);
429 AliasFont(arial, helvetica, nullStr, PR_FALSE);
430 AliasFont(helvetica, arial, nullStr, PR_FALSE);
431 AliasFont(courier, courierNew, nullStr, PR_TRUE);
432 AliasFont(courierNew, courier, nullStr, PR_FALSE);
435 result = NS_ERROR_OUT_OF_MEMORY;
441 nsresult DeviceContextImpl::AliasFont(const nsString& aFont,
442 const nsString& aAlias, const nsString& aAltAlias,
445 nsresult result = NS_OK;
447 if (nsnull != mFontAliasTable) {
448 if (aForceAlias || (NS_OK != CheckFontExistence(aFont))) {
449 if (NS_OK == CheckFontExistence(aAlias)) {
450 nsString* entry = aAlias.ToNewString();
451 if (nsnull != entry) {
452 FontAliasKey key(aFont);
453 mFontAliasTable->Put(&key, entry);
456 result = NS_ERROR_OUT_OF_MEMORY;
459 else if ((0 < aAltAlias.Length()) && (NS_OK == CheckFontExistence(aAltAlias))) {
460 nsString* entry = aAltAlias.ToNewString();
461 if (nsnull != entry) {
462 FontAliasKey key(aFont);
463 mFontAliasTable->Put(&key, entry);
466 result = NS_ERROR_OUT_OF_MEMORY;
472 result = NS_ERROR_FAILURE;
477 NS_IMETHODIMP DeviceContextImpl::GetLocalFontName(const nsString& aFaceName, nsString& aLocalName,
480 nsresult result = NS_OK;
482 if (nsnull == mFontAliasTable) {
483 result = CreateFontAliasTable();
486 if (nsnull != mFontAliasTable) {
487 FontAliasKey key(aFaceName);
488 const nsString* alias = (const nsString*)mFontAliasTable->Get(&key);
489 if (nsnull != alias) {
494 aLocalName = aFaceName;
501 NS_IMETHODIMP DeviceContextImpl :: FlushFontCache(void)
503 if (nsnull != mFontCache)
509 //----------------------------------------------------------------------------------
510 // Return localized bundle for resource strings
512 DeviceContextImpl::GetLocalizedBundle(const char * aPropFileName, nsIStringBundle** aStrBundle)
514 NS_ENSURE_ARG_POINTER(aPropFileName);
515 NS_ENSURE_ARG_POINTER(aStrBundle);
518 nsCOMPtr<nsIStringBundle> bundle;
520 // Create a URL for the string resource file
521 // Create a bundle for the localization
522 nsCOMPtr<nsIIOService> pNetService(do_GetService(kIOServiceCID, &rv));
523 if (NS_SUCCEEDED(rv) && pNetService) {
524 nsCOMPtr<nsIURI> uri;
525 rv = pNetService->NewURI(aPropFileName, nsnull, getter_AddRefs(uri));
526 if (NS_SUCCEEDED(rv) && uri) {
529 nsCOMPtr<nsIStringBundleService> stringService =
530 do_GetService(kStringBundleServiceCID, &rv);
531 if (NS_SUCCEEDED(rv) && stringService) {
533 rv = uri->GetSpec(getter_Copies(spec));
534 if (NS_SUCCEEDED(rv) && spec) {
535 rv = stringService->CreateBundle(spec, aStrBundle);
543 //--------------------------------------------------------
544 // Return localized string
546 DeviceContextImpl::GetLocalizedString(nsIStringBundle* aStrBundle, const char* aKey, nsString& oVal)
548 NS_ENSURE_ARG_POINTER(aStrBundle);
549 NS_ENSURE_ARG_POINTER(aKey);
551 // Determine default label from string bundle
552 nsXPIDLString valUni;
554 key.AssignWithConversion(aKey);
555 nsresult rv = aStrBundle->GetStringFromName(key.get(), getter_Copies(valUni));
556 if (NS_SUCCEEDED(rv) && valUni) {
565 /////////////////////////////////////////////////////////////
567 MOZ_DECL_CTOR_COUNTER(nsFontCache)
569 nsFontCache :: nsFontCache()
571 MOZ_COUNT_CTOR(nsFontCache);
575 nsFontCache :: ~nsFontCache()
577 MOZ_COUNT_DTOR(nsFontCache);
582 nsFontCache :: Init(nsIDeviceContext* aContext)
584 NS_PRECONDITION(nsnull != aContext, "null ptr");
585 // Note: we don't hold a reference to the device context, because it
586 // holds a reference to us and we don't want circular references
592 nsFontCache :: GetDeviceContext(nsIDeviceContext *&aContext) const
594 NS_IF_ADDREF(mContext);
600 nsFontCache :: GetMetricsFor(const nsFont& aFont, nsIAtom* aLangGroup,
601 nsIFontMetrics *&aMetrics)
603 // First check our cache
604 PRInt32 n = mFontMetrics.Count();
606 for (PRInt32 cnt = 0; cnt < n; cnt++)
608 nsIFontMetrics* metrics = NS_STATIC_CAST(nsIFontMetrics*, mFontMetrics[cnt]);
611 metrics->GetFont(font);
612 if (aFont.Equals(*font)) {
613 nsCOMPtr<nsIAtom> langGroup;
614 metrics->GetLangGroup(getter_AddRefs(langGroup));
615 if (aLangGroup == langGroup.get()) {
617 // promote it to the front of the cache
618 for (PRInt32 i = cnt; i > 0; --i)
619 mFontMetrics.ReplaceElementAt(mFontMetrics[i - 1], i);
621 mFontMetrics.ReplaceElementAt(metrics, 0);
623 NS_ADDREF(aMetrics = metrics);
629 // It's not in the cache. Get font metrics and then cache them.
631 nsIFontMetrics *fm = nsnull;
632 nsresult rv = CreateFontMetricsInstance(&fm);
639 rv = fm->Init(aFont, aLangGroup, mContext);
646 mFontMetrics.AppendElement(fm);
653 /* PostScript and Xprint module may override this method to create
654 * nsIFontMetrics objects with their own classes
657 nsFontCache::CreateFontMetricsInstance(nsIFontMetrics** fm)
659 static NS_DEFINE_CID(kFontMetricsCID, NS_FONT_METRICS_CID);
660 return CallCreateInstance(kFontMetricsCID, fm);
664 nsresult nsFontCache :: Flush()
666 PRInt32 i, n = mFontMetrics.Count();
668 for (i = 0; i < n; i++)
670 nsIFontMetrics* fm = (nsIFontMetrics*) mFontMetrics.ElementAt(i);
675 mFontMetrics.Clear();