Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.1 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module KERN.CPP -- CCKernCache class |
  5. *
  6. * Class which implements a kerning pair cache. Note that these widths
  7. * are stored in the font's design units (2048 pixel high font)
  8. * This allows us to share the same kerning pair information for all
  9. * sizes of a font.
  10. *
  11. * The kerning cache assumes you know in advance how many entries
  12. * you will put into the cache. It does not support the expensive
  13. * operations of growing and re-hashing all the data.
  14. *
  15. * Owner:<nl>
  16. * Keith Curtis: Stolen from Quill '98, simplified and improved upon.
  17. *
  18. * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
  19. */
  20. #include <_common.h>
  21. #include <_kern.h>
  22. const int dvpDesign = 2048;
  23. /*
  24. * CKernCache::FetchDup(chFirst, chSecond, dvpFont)
  25. *
  26. * @mfunc
  27. * Looks up the characters in the table and returns their pair
  28. * adjustment if found.
  29. *
  30. * We will scale the value from the font's design units.
  31. *
  32. * This routine is very important for performance.
  33. * Many optimizations (double hashing, early returns if the data
  34. * didn't match but a collision wasn't found) actually slowed things down!
  35. *
  36. * Note this is very similar to the below function but having
  37. * separate functions makes pagination 7% faster.
  38. */
  39. LONG CKernCache::FetchDup(WCHAR chFirst, WCHAR chSecond, LONG dvpFont)
  40. {
  41. KERNHASHKEY kernhashkey = MakeHashKey(chFirst, chSecond);
  42. int ikpe = Hash(kernhashkey);
  43. KPE *pkpe = _pmpkpe.Elem(ikpe);
  44. for(;;)
  45. {
  46. if (pkpe->chFirst == chFirst && pkpe->chSecond == chSecond)
  47. return MulDiv(pkpe->du, dvpFont, dvpDesign);
  48. if (pkpe->chFirst == 0) //Empty slot, so no pair
  49. return 0;
  50. ikpe++;
  51. pkpe++;
  52. if (ikpe == _pmpkpe.Count()) //Loop around if necessary
  53. {
  54. ikpe = 0;
  55. pkpe = _pmpkpe.Elem(0);
  56. }
  57. }
  58. }
  59. /*
  60. * CKernCache::Add(chFirst, chSecond, du)
  61. *
  62. * @mfunc
  63. * Finds a free spot to put the kerning pair information.
  64. * This function cannot fail because the array has been preallocated.
  65. *
  66. */
  67. void CKernCache::Add(WCHAR chFirst, WCHAR chSecond, LONG du)
  68. {
  69. KERNHASHKEY kernhashkey = MakeHashKey(chFirst, chSecond);
  70. int ikpe = Hash(kernhashkey);
  71. KPE *pkpe = _pmpkpe.Elem(ikpe);
  72. for(;;)
  73. {
  74. if (pkpe->chFirst == 0)
  75. {
  76. pkpe->chFirst = chFirst;
  77. pkpe->chSecond = chSecond;
  78. pkpe->du = du;
  79. return;
  80. }
  81. ikpe++;
  82. pkpe++;
  83. if (ikpe == _pmpkpe.Count())
  84. {
  85. ikpe = 0;
  86. pkpe = _pmpkpe.Elem(0);
  87. }
  88. }
  89. }
  90. /*
  91. * CKernCache::FInit(hfont)
  92. *
  93. * @mfunc
  94. * If the kern cache is uninitialized, Init it. If there are no
  95. * kerning pairs (or it failed) return FALSE.
  96. *
  97. * @rdesc
  98. * Return TRUE if you can fetch kerning pairs for this cache
  99. *
  100. */
  101. BOOL CKernCache::FInit(HFONT hfont)
  102. {
  103. if (_kcis == Unitialized)
  104. Init(hfont);
  105. return _kcis == Initialized;
  106. }
  107. /*
  108. * CKernCache::Init(hfont)
  109. *
  110. * @mfunc
  111. * Fetches the kerning pairs from the OS in design units and hashes them
  112. * all into a table. Updates _ckis with result
  113. *
  114. */
  115. void CKernCache::Init(HFONT hfont)
  116. {
  117. KERNINGPAIR *pkp = 0;
  118. int prime, ikp;
  119. HFONT hfontOld = 0;
  120. HFONT hfontIdeal = 0;
  121. int ckpe = 0;
  122. HDC hdc = W32->GetScreenDC();
  123. LOGFONT lfIdeal;
  124. W32->GetObject(hfont, sizeof(LOGFONT), &lfIdeal);
  125. //FUTURE (keithcu) Support kerning of Greek, Cyrillic, etc.
  126. lfIdeal.lfHeight = -dvpDesign;
  127. lfIdeal.lfCharSet = ANSI_CHARSET;
  128. hfontIdeal = CreateFontIndirect(&lfIdeal);
  129. if (!hfontIdeal)
  130. goto LNone;
  131. hfontOld = SelectFont(hdc, hfontIdeal);
  132. Assert(hfontOld);
  133. ckpe = GetKerningPairs(hdc, 0, 0);
  134. if (ckpe == 0)
  135. goto LNone;
  136. prime = FindPrimeLessThan(ckpe * 5 / 2);
  137. if (prime == 0)
  138. goto LNone;
  139. pkp = new KERNINGPAIR[ckpe];
  140. if (!pkp)
  141. goto LNone;
  142. GetKerningPairs(hdc, ckpe, pkp);
  143. _pmpkpe.Add(prime, 0);
  144. PvSet(*(void**) &_pmpkpe);
  145. for (ikp = 0; ikp < ckpe; ikp++)
  146. Add(pkp[ikp].wFirst, pkp[ikp].wSecond, pkp[ikp].iKernAmount);
  147. _kcis = Initialized;
  148. goto LDone;
  149. LNone:
  150. _kcis = NoKerningPairs;
  151. LDone:
  152. delete []pkp;
  153. if (hfontOld)
  154. SelectObject(hdc, hfontOld);
  155. DeleteObject(hfontIdeal);
  156. }