home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / wcefont.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  40.7 KB  |  1,887 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"  
  12. #include <math.h>
  13.  
  14. static FONTDESC s_fdDefault =
  15. {
  16.     sizeof(FONTDESC),
  17.     OLESTR("Tahoma"),
  18.     {8 * 10000, 0},
  19.     400,
  20.     DEFAULT_CHARSET,
  21.     FALSE,
  22.     FALSE,
  23.     FALSE
  24. };
  25.  
  26. HRESULT CharSetOfFace(HDC hdc, OLECHAR *szFaceName, WORD *pwCharset);
  27. double RoundFloatDiv(double numer, double denom);
  28. long RoundDiv(long numer, long denom);
  29.  
  30.  
  31. int  CCeFont::s_cFcr = 0;        // Count of records in the font cache
  32. FCR *CCeFont::s_rgfcr = NULL;    // Array of font cache records (the font cache)
  33. BOOL CCeFont::s_fInit = FALSE;    // Has font cache been initialized?
  34. HDC CCeFont::m_hdc = NULL;
  35.  
  36. CCeFont::CCeFont(void)
  37.     :CUnknown(NULL)
  38. {
  39.     m_hfont = NULL;
  40.     m_nFcr  = -1;
  41.     m_fr.cySize.Lo  = 80000; // Default to 8 point
  42.     m_fr.cySize.Hi  = 0;
  43.     m_fr.cyLogical  = 1;
  44.     m_fr.cyHimetric = 1;
  45.     m_fr.sCharset   = DEFAULT_CHARSET;
  46.     m_fr.sWeight    = FW_DONTCARE;
  47.     m_fr.bFlags     = 0;
  48.     m_fr.rgchFace[0] = 0;
  49.     m_fNameDirty    = FALSE;
  50.     m_fCharSetDirty = FALSE;
  51.     m_bModified     = FALSE;
  52. }
  53.  
  54. CCeFont::~CCeFont(void)
  55. {
  56.     if (m_nFcr != -1) 
  57.     {
  58.         ASSERT(s_rgfcr[m_nFcr].cRefs > 0);
  59.         s_rgfcr[m_nFcr].cRefs--;
  60.     }
  61. }
  62.  
  63. //
  64. // Return the font name
  65. //
  66. STDMETHODIMP CCeFont::get_Name(BSTR* pbstrName)
  67. {
  68.     if (!pbstrName)
  69.         {
  70.         return E_INVALIDARG;
  71.         }
  72.  
  73.     HRESULT hr = NOERROR;
  74.  
  75.     hr = UpdateFont();
  76.     if (FAILED(hr)) 
  77.         {
  78.         return hr;
  79.         }
  80.     
  81.     Lock();
  82.  
  83.     *pbstrName = SysAllocString(m_fr.rgchFace);
  84.     if (!*pbstrName)
  85.         {
  86.         hr = E_OUTOFMEMORY;
  87.         goto LReturn;
  88.         }
  89.  
  90. LReturn:
  91.     Unlock();
  92.  
  93.     return hr;
  94. }
  95.  
  96. //
  97. // Answer if the given string is a valid name
  98. //
  99. HRESULT CCeFont::ChkName(LPOLESTR szName)
  100. {
  101.     if (!szName || (::lstrlenW(szName) >= LF_FACESIZE))
  102.         {
  103.         return CTL_E_INVALIDPROPERTYVALUE;
  104.         }
  105.  
  106.     return NOERROR;
  107. }
  108.  
  109. //
  110. // Set the font name
  111. //
  112. STDMETHODIMP CCeFont::put_Name(BSTR bstrName)
  113. {
  114.     HRESULT hr;
  115.  
  116.     hr = ChkName(bstrName);
  117.     if (FAILED(hr))
  118.         {
  119.         return hr;
  120.         }
  121.  
  122.     if (::lstrcmpW(m_fr.rgchFace, bstrName)) 
  123.         {
  124.         ::wcsncpy(m_fr.rgchFace, bstrName, LF_FACESIZE);
  125.         m_fNameDirty = TRUE;
  126.         DiscardFont(TRUE, DISPID_FONT_NAME);
  127.         UpdateFont();
  128.         }
  129.  
  130.     return NOERROR;
  131. }
  132.  
  133. STDMETHODIMP CCeFont::get_Size(CY *pcySize)
  134. {
  135.     if (!pcySize)
  136.         {
  137.         return E_INVALIDARG;
  138.         }
  139.  
  140.     HRESULT hr;
  141.  
  142.     hr = UpdateFont();
  143.     if (FAILED(hr)) 
  144.         {
  145.         return hr;
  146.         }
  147.     
  148.     Lock();
  149.  
  150.     pcySize->Hi = m_fr.cySize.Hi;
  151.     pcySize->Lo = m_fr.cySize.Lo;
  152.     
  153.     Unlock();
  154.  
  155.     return NOERROR;
  156. }
  157.  
  158. STDMETHODIMP CCeFont::put_Size(CY cySize)
  159. {
  160.     unsigned long ulHeight;
  161.  
  162.     if (cySize.Hi < 0 || (cySize.Lo == 0 && cySize.Hi == 0))
  163.         {
  164.         return CTL_E_INVALIDPROPERTYVALUE;
  165.         }
  166.     //
  167.     // currently only accept values from 1 to 65535 (what VB used to accept)
  168.     //
  169.     if (cySize.Hi != 0 || cySize.Lo > 655350000)
  170.         {
  171.         return CTL_E_OVERFLOW;
  172.         }
  173.     //
  174.     // have to scale cySize.Lo back down to avoid overflow when
  175.     // multiplying by GetDeviceCaps()
  176.     //
  177.     ulHeight = ((cySize.Lo / 10000) * GetDeviceCaps(Hdc(), LOGPIXELSY)) / 72;
  178.     if (ulHeight > 32767)
  179.         {
  180.         return ResultFromScode(CTL_E_OVERFLOW);
  181.         }
  182.     
  183.     Lock();
  184.     if (cySize.Lo == m_fr.cySize.Lo) 
  185.         {
  186.         goto LReturn;
  187.         }
  188.     
  189.     m_fr.cySize = cySize;
  190.     DiscardFont(TRUE, DISPID_FONT_SIZE);
  191.     UpdateFont();
  192.  
  193. LReturn:
  194.     Unlock();
  195.  
  196.     return NOERROR;
  197. }
  198.  
  199. STDMETHODIMP CCeFont::get_Bold(BOOL *pfBold)
  200. {
  201.     if (!pfBold)
  202.         {
  203.         return E_INVALIDARG;
  204.         }
  205.  
  206.     HRESULT hr;
  207.  
  208.     hr = UpdateFont();
  209.     if (FAILED(hr)) 
  210.         {
  211.         return hr;
  212.         }
  213.     
  214.     Lock();
  215.  
  216.     *pfBold = m_fr.sWeight > ((FW_MEDIUM + FW_SEMIBOLD) / 2);
  217.  
  218.     Unlock();
  219.  
  220.     return NOERROR;
  221. }
  222.  
  223. STDMETHODIMP CCeFont::put_Bold(BOOL bold)
  224. {
  225.     return put_Weight((short)(bold ? FW_BOLD : FW_NORMAL));
  226. }
  227.  
  228. STDMETHODIMP CCeFont::get_Italic(BOOL *pfItalic)
  229. {
  230.     if (!pfItalic)
  231.         {
  232.         return E_INVALIDARG;
  233.         }
  234.  
  235.     HRESULT hr;
  236.  
  237.     hr = UpdateFont();
  238.     if (FAILED(hr)) 
  239.         {
  240.         return hr;
  241.         }
  242.     
  243.     Lock();
  244.  
  245.     *pfItalic = m_fr.fItalic;
  246.  
  247.     Unlock();
  248.  
  249.     return NOERROR;
  250. }
  251.  
  252. STDMETHODIMP CCeFont::put_Italic(BOOL fItalic)
  253. {
  254.     Lock();
  255.  
  256.     if (m_fr.fItalic != fItalic) 
  257.         {
  258.         m_fr.fItalic = fItalic;
  259.         DiscardFont(TRUE, DISPID_FONT_ITALIC);
  260.         UpdateFont();
  261.         }
  262.     
  263.     Unlock();
  264.  
  265.     return NOERROR;
  266. }
  267.  
  268. STDMETHODIMP CCeFont::get_Underline(BOOL *pfUnderline)
  269. {
  270.     if (!pfUnderline)
  271.         {
  272.         return E_INVALIDARG;
  273.         } 
  274.  
  275.     HRESULT hr;
  276.  
  277.     hr = UpdateFont();
  278.     if (FAILED(hr)) 
  279.         {
  280.         return hr;
  281.         }
  282.     
  283.     Lock();
  284.  
  285.     *pfUnderline = m_fr.fUnderline;
  286.     
  287.     Unlock();
  288.  
  289.     return NOERROR;
  290. }
  291.  
  292. STDMETHODIMP CCeFont::put_Underline(BOOL fUnderline)
  293. {
  294.     Lock();
  295.  
  296.     if (m_fr.fUnderline != fUnderline) 
  297.         {
  298.         m_fr.fUnderline = fUnderline;
  299.         DiscardFont(TRUE, DISPID_FONT_UNDER);
  300.         UpdateFont();
  301.         }
  302.  
  303.     Unlock();
  304.  
  305.     return NOERROR;
  306. }
  307.  
  308. STDMETHODIMP CCeFont::get_Strikethrough(BOOL* pfStrikethrough)
  309. {
  310.     if (!pfStrikethrough)
  311.         {
  312.         return E_INVALIDARG;
  313.         }
  314.  
  315.     HRESULT hr;
  316.   
  317.     hr = UpdateFont();
  318.     if (FAILED(hr)) 
  319.         {
  320.         return hr;
  321.         }
  322.     
  323.     Lock();
  324.  
  325.     *pfStrikethrough = m_fr.fStrikethrough;
  326.  
  327.     Unlock();
  328.  
  329.     return NOERROR;
  330. }
  331.  
  332. STDMETHODIMP CCeFont::put_Strikethrough(BOOL fStrikethrough)
  333. {
  334.     Lock();
  335.  
  336.     if (m_fr.fStrikethrough != fStrikethrough) 
  337.         {
  338.         m_fr.fStrikethrough = fStrikethrough;
  339.         DiscardFont(TRUE, DISPID_FONT_STRIKE);
  340.         UpdateFont();
  341.         } 
  342.  
  343.     Unlock();
  344.  
  345.     return NOERROR;
  346. }
  347.  
  348. STDMETHODIMP CCeFont::get_Weight(short* psWeight)
  349. {
  350.     if (!psWeight)
  351.         {
  352.         return E_INVALIDARG;
  353.         }
  354.  
  355.     HRESULT hr;
  356.       
  357.     hr = UpdateFont();
  358.     if (FAILED(hr)) 
  359.         {
  360.         return hr;
  361.         }
  362.     
  363.     Lock();
  364.  
  365.     *psWeight = m_fr.sWeight;
  366.  
  367.     Unlock();
  368.  
  369.     return NOERROR;
  370. }
  371.  
  372. STDMETHODIMP CCeFont::put_Weight(short sWeight)
  373. {
  374.     if (sWeight < 0 || sWeight > 1000)
  375.       return CTL_E_INVALIDPROPERTYVALUE;
  376.     
  377.     Lock();
  378.  
  379.     if (m_fr.sWeight != sWeight) 
  380.         {
  381.         m_fr.sWeight = sWeight;
  382.         DiscardFont(TRUE, DISPID_FONT_WEIGHT);
  383.         UpdateFont();
  384.         }
  385.  
  386.     Unlock();
  387.  
  388.     return NOERROR;
  389. }
  390.  
  391. STDMETHODIMP CCeFont::get_Charset(short *psCharset)
  392. {
  393.     if (!psCharset)
  394.         {
  395.         return E_INVALIDARG;
  396.         }
  397.  
  398.     HRESULT hr;
  399.       
  400.     hr = UpdateFont();
  401.     if (FAILED(hr)) 
  402.         {
  403.         return hr;
  404.         }
  405.     
  406.     Lock();
  407.  
  408.     *psCharset = m_fr.sCharset;
  409.  
  410.     Unlock();
  411.  
  412.     return NOERROR;
  413. }
  414.  
  415. STDMETHODIMP CCeFont::put_Charset(short sCharset)
  416. {
  417.     if (sCharset > 255 || sCharset < 0)
  418.         {
  419.         return CTL_E_INVALIDPROPERTYVALUE;
  420.         }
  421.     
  422.     Lock();
  423.  
  424.     if (m_fr.sCharset != sCharset) 
  425.         {
  426.         m_fr.sCharset = sCharset;
  427.         m_fCharSetDirty = TRUE;
  428.         DiscardFont(TRUE, DISPID_FONT_CHARSET);
  429.         UpdateFont();
  430.         }
  431.     
  432.     Unlock();
  433.  
  434.     return NOERROR;
  435. }
  436.  
  437. STDMETHODIMP CCeFont::get_hFont(HFONT *phfont)
  438. {
  439.     if (!phfont)
  440.         {
  441.         return E_INVALIDARG;
  442.         }
  443.       
  444.     HRESULT hr;
  445.  
  446.     hr = UpdateFont();
  447.     if (FAILED(hr)) 
  448.         {
  449.         return hr;
  450.         }
  451.     
  452.     Lock();
  453.  
  454.     *phfont = m_hfont;
  455.  
  456.     Unlock();
  457.  
  458.     return NOERROR;
  459. }
  460.  
  461. STDMETHODIMP CCeFont::Clone(IFont **ppfont)
  462. {
  463.     if (!ppfont)
  464.         {
  465.         return E_INVALIDARG;
  466.         }
  467.  
  468.     HRESULT hr;
  469.  
  470.     hr = UpdateFont();
  471.     if (FAILED(hr)) 
  472.         {
  473.         return hr;
  474.         }
  475.  
  476.     CCeFont *pfontClone;
  477.     
  478.     pfontClone = new CCeFont();
  479.     if (!pfontClone) 
  480.         {
  481.         return E_OUTOFMEMORY;
  482.         }
  483.     
  484.     Lock();
  485.  
  486.     pfontClone->m_hfont = m_hfont;
  487.     memcpy(&pfontClone->m_fr, &m_fr, sizeof(FR));
  488.  
  489.     if ((pfontClone->m_nFcr = m_nFcr) != -1)
  490.         {
  491.         s_rgfcr[m_nFcr].cRefs++;
  492.         }
  493.     
  494.     Unlock();
  495.  
  496.     hr = pfontClone->QueryInterface(IID_IFont, (PVOID *) ppfont);
  497.     if (FAILED(hr))
  498.         {
  499.         delete pfontClone;
  500.         }
  501.  
  502.     return hr;
  503. }
  504.  
  505. STDMETHODIMP CCeFont::IsEqual(IFont *pfontOther)
  506. {
  507.     return E_NOTIMPL;
  508. }
  509.  
  510. STDMETHODIMP CCeFont::SetRatio(long cyLogical, long cyHimetric)
  511. {
  512.     if (cyLogical == 0 || cyHimetric == 0)
  513.         {
  514.         return E_FAIL;
  515.         }
  516.     
  517.     Lock();
  518.  
  519.     if (cyLogical != m_fr.cyLogical || cyHimetric != m_fr.cyHimetric) 
  520.         {
  521.         m_fr.cyLogical = cyLogical;
  522.         m_fr.cyHimetric = cyHimetric;
  523.         DiscardFont(FALSE, DISPID_UNKNOWN);
  524.         UpdateFont();
  525.         }
  526.     
  527.     Unlock();
  528.  
  529.     return NOERROR;
  530. }
  531.  
  532. STDMETHODIMP CCeFont::QueryTextMetrics(LPTEXTMETRICOLE ptm)
  533. {
  534.     if (!ptm)
  535.         {
  536.         return E_INVALIDARG;
  537.         }
  538.  
  539.     HRESULT hr;
  540.  
  541.  
  542.     hr = UpdateFont();
  543.     if (FAILED(hr))
  544.         {
  545.         return hr;
  546.         }
  547.     
  548.     Lock();
  549.  
  550.     memcpy(ptm, &s_rgfcr[m_nFcr].tm, sizeof(TEXTMETRICOLE));
  551.  
  552.     Unlock();
  553.  
  554.     return NOERROR;
  555. }
  556.  
  557. //
  558. // Find the font in the font cache and up its ref count
  559. //
  560. STDMETHODIMP CCeFont::AddRefHfont(HFONT hfont)
  561. {
  562.     if (!hfont)
  563.         {
  564.         return E_INVALIDARG;
  565.         }
  566.  
  567.     HRESULT hr;
  568.     FCR *pfcr, *pfcrEnd;
  569.  
  570.     hr = S_FALSE;
  571.  
  572.     Lock();
  573.  
  574.     pfcrEnd = &s_rgfcr[s_cFcr];
  575.     // 
  576.     // Find the font in the cache
  577.     //
  578.     for (pfcr = s_rgfcr; pfcr < pfcrEnd; ++pfcr) 
  579.         {
  580.         if (pfcr->hfont == hfont) 
  581.             {
  582.             pfcr->cRefs++;
  583.             hr = NOERROR;
  584.             break;
  585.             }
  586.         }
  587.  
  588.     Unlock();
  589.  
  590.     return hr;
  591. }
  592.  
  593. //
  594. // Reduce the ref count on the given hfont by one.
  595. //
  596. // Note, we don't actually delete the font when the ref count goes
  597. // to 0.  This will happen if the cache record is reused by another
  598. // font, or when the last font object is released.
  599. //
  600. STDMETHODIMP CCeFont::ReleaseHfont(HFONT hfont)
  601. {
  602.     if (!hfont)
  603.         {
  604.         return E_INVALIDARG;
  605.         }
  606.  
  607.     HRESULT hr;
  608.     FCR *pfcr, *pfcrEnd;
  609.  
  610.     hr = S_FALSE;
  611.  
  612.     Lock();
  613.  
  614.     pfcrEnd = &s_rgfcr[s_cFcr];
  615.     //
  616.     // Find the font by looping through the cache
  617.     //
  618.     for (pfcr = s_rgfcr; pfcr < pfcrEnd; ++pfcr) 
  619.         {
  620.         if (pfcr->hfont == hfont) 
  621.             {
  622.             if (pfcr->cRefs > 1) 
  623.                 {
  624.                 pfcr->cRefs--;
  625.                 hr = NOERROR;
  626.                 } 
  627.             else
  628.                 {
  629.                 hr = S_FALSE;    // We always have 1 reference by the font obj
  630.                 }
  631.             break;
  632.             }
  633.         }
  634.  
  635.     Unlock();
  636.  
  637.     return hr;
  638. }
  639.  
  640. STDMETHODIMP CCeFont::SetHdc(HDC hdc)
  641. {
  642.     return E_NOTIMPL;
  643. }
  644.  
  645. //
  646. // Return system information about the given font.
  647. //
  648. HRESULT CCeFont::QueryFontInfo(HFONT hfont, TEXTMETRICOLE *ptm, OLECHAR rgchFace[LF_FACESIZE])
  649. {
  650.     HRESULT hr = E_FAIL;
  651.     HDC hdc = Hdc();
  652.     HFONT hfontPrev = (HFONT) ::SelectObject(hdc, (HGDIOBJ) hfont);
  653.  
  654.     if (!FontGetTextMetrics(hdc, ptm))
  655.         {
  656.         goto LReturn;
  657.         }
  658.  
  659.     if (!FontGetTextFace(hdc, LF_FACESIZE, rgchFace))
  660.         {
  661.         goto LReturn;
  662.         }
  663.     
  664.     hr = NOERROR;
  665.  
  666. LReturn:
  667.     ::SelectObject(hdc, (HGDIOBJ) hfontPrev);
  668.  
  669.     return hr;
  670. }
  671.  
  672. //
  673. // Make sure that we have ahold of an HFONT that reflects corresponds
  674. // to the current font settings.
  675. //
  676. HRESULT CCeFont::UpdateFont()
  677. {
  678.     FCR *pfcr;
  679.     HRESULT hr;
  680.     
  681.     Lock();
  682.  
  683.     if (m_nFcr != -1)
  684.         {
  685.         hr = NOERROR; // got one!
  686.         goto LReturn;
  687.         }
  688.     //
  689.     // Look for a match in the font cache
  690.     //
  691.     hr = FindMatchingFont(&m_nFcr);
  692.     ASSERT(SUCCEEDED(hr)); // Should return S_OK or S_FALSE
  693.  
  694.     if (hr == NOERROR) 
  695.         {
  696.         //
  697.         // Found a match in the cache
  698.         //
  699.         pfcr = &s_rgfcr[m_nFcr];
  700.         pfcr->cRefs++;
  701.         m_hfont = pfcr->hfont;
  702.         //
  703.         // Update our state to reflect the cache entry we matched
  704.         //
  705.         memcpy(&m_fr, &pfcr->frActual, sizeof(FR));
  706.         goto LDone;
  707.         }
  708.  
  709.     HFONT hfont;
  710.     TEXTMETRICOLE tm;
  711.     OLECHAR rgchFace[LF_FACESIZE];
  712.     //
  713.     // Realize a new font, and stuff it into the cache
  714.     //
  715.     hr = NewFcr(&m_nFcr); // allocate a new cache slot
  716.     if (FAILED(hr))
  717.         {
  718.         goto LReturn;
  719.         }
  720.     //
  721.     // Create a font that matches our FR
  722.     //
  723.     hr = CreateMatchingFont(&hfont);
  724.     //
  725.     // If this failed, try to keep going with the old hfont.
  726.     //
  727.     if (FAILED(hr)) 
  728.         {
  729.         if (!m_hfont) 
  730.             {
  731.             m_nFcr = -1;
  732.             goto LReturn;
  733.             }
  734.         
  735.         hfont = m_hfont;
  736.         hr = NOERROR;
  737.         }
  738.     //
  739.     // The create succeeded, make sure we like what we got...
  740.     //
  741.     QueryFontInfo(hfont, &tm, rgchFace);
  742.     //
  743.     // If the font name we get out is different than the one we requested
  744.     // then we may have had a problem with the charset. So enumerate all
  745.     // fonts to see if there is a font that matches in name, but has a
  746.     // different charset, and try to use it instead.
  747.     //
  748.     // NOTE, This is a very expensive operation, so we avoid it in the
  749.     // mainline case. We also do work to avoid unless we know it was a
  750.     // name or charset change that has caused us to realize a new font.
  751.     //
  752.     // NOTE: We should never execute this when realizing a font after
  753.     // loading from binary.
  754.     //
  755.     WORD wCharset;
  756.     HFONT hfontWithCharset;
  757.  
  758.     if (m_fNameDirty || m_fCharSetDirty) 
  759.         {
  760.         if (::lstrcmpiW(m_fr.rgchFace, rgchFace)) 
  761.             {
  762.             if (SUCCEEDED(CharSetOfFace(Hdc(), m_fr.rgchFace, &wCharset))) 
  763.                 {
  764.                 if (m_fr.sCharset != wCharset) 
  765.                     {
  766.                     m_fr.sCharset = wCharset;
  767.                     if (SUCCEEDED(CreateMatchingFont(&hfontWithCharset))) 
  768.                         {
  769.                         //
  770.                         // Replace with the better match
  771.                         //
  772.                         ::DeleteObject((HGDIOBJ) hfont);
  773.                         hfont = hfontWithCharset;
  774.                         QueryFontInfo(hfont, &tm, rgchFace);
  775.                         }
  776.                     }
  777.                 }
  778.             }
  779.         }
  780.     //
  781.     // Add it to the font cache
  782.     //
  783.     pfcr = &s_rgfcr[m_nFcr];
  784.     pfcr->cRefs++;
  785.     pfcr->hfont = hfont;
  786.     //
  787.     // Record the font we requested
  788.     //
  789.     memcpy(&pfcr->frRequest, &m_fr, sizeof(FR));
  790.     //
  791.     // Update our state based on the font we actually mapped to
  792.     //
  793.     UpdateFr(hfont, &tm, rgchFace);
  794.     memcpy(&pfcr->frActual, &m_fr, sizeof(FR));
  795.  
  796. LDone:
  797.     m_fNameDirty = FALSE;
  798.     m_fCharSetDirty = FALSE;
  799.  
  800.     hr = NOERROR;
  801.  
  802. LReturn:
  803.     Unlock();
  804.  
  805.     return hr;
  806. }
  807.  
  808. //
  809. // Refresh our current FR based on the given HFONT.
  810. //
  811. HRESULT CCeFont::UpdateFr(HFONT hfont, TEXTMETRICOLE *ptm, OLECHAR rgchFace[LF_FACESIZE])
  812. {
  813.     double n, d;
  814.  
  815.     ASSERT(m_nFcr != -1);
  816.     
  817.     Lock();
  818.  
  819.     m_hfont = hfont;
  820.     //
  821.     // Cache the metrics in the FCR
  822.     //
  823.     memcpy(&s_rgfcr[m_nFcr].tm, ptm, sizeof(*ptm));
  824.  
  825.     m_fr.fItalic        = ptm->tmItalic;
  826.     m_fr.fUnderline     = ptm->tmUnderlined;
  827.     m_fr.fStrikethrough = ptm->tmStruckOut;
  828.     m_fr.sWeight        = (SHORT)ptm->tmWeight;
  829.     m_fr.sCharset       = (SHORT)ptm->tmCharSet;
  830.     //
  831.     // Convert font height in logical pixels back to our
  832.     // internal representation, which is a currency rep of points.
  833.     //
  834.     n = (double)(ptm->tmHeight - ptm->tmInternalLeading);
  835.  
  836.     if (m_fr.cyLogical == 1 && m_fr.cyHimetric == 1) 
  837.         {
  838.         d = (double)GetDeviceCaps(Hdc(), LOGPIXELSY);
  839.         m_fr.cySize.Lo = (ULONG)RoundFloatDiv(n * 720000.0, d);
  840.         } 
  841.     else 
  842.         {
  843.         n = RoundFloatDiv(n * 72000.0, 254.0) * (double)m_fr.cyHimetric;
  844.         m_fr.cySize.Lo = (ULONG)RoundFloatDiv(n, (double)m_fr.cyLogical);
  845.         m_fr.cySize.Lo = RoundDiv(m_fr.cySize.Lo, 100) * 100;
  846.         }
  847.  
  848.     ASSERT(m_fr.cySize.Lo > 0);
  849.     m_fr.cySize.Hi = 0;
  850.  
  851.     ::lstrcpyW(m_fr.rgchFace, rgchFace);
  852.     
  853.     Unlock();
  854.  
  855.     return NOERROR;
  856. }
  857.  
  858. //
  859. // Discard our current font handle, reducing the ref count by one.
  860. //
  861. // Note: this routine doesn't actually delete the HFONT if the ref
  862. // count goes to zero.  This will happen if the font cache record
  863. // is reused by another object, or when the cache itself is released.
  864. //
  865. HRESULT CCeFont::DiscardFont(BOOL fNotify, DISPID dispidChanged)
  866. {
  867.     Lock();
  868.  
  869.     if (m_nFcr != -1) 
  870.         {
  871.         ASSERT(s_rgfcr[m_nFcr].cRefs > 0);
  872.         ASSERT(s_rgfcr[m_nFcr].hfont == m_hfont);
  873.         s_rgfcr[m_nFcr].cRefs--;
  874.         m_nFcr = -1;
  875.         }
  876.  
  877.     Unlock();
  878.  
  879.     if (fNotify) 
  880.         {
  881.         //
  882.         // Notification not currently supported!
  883.         //
  884.         }
  885.  
  886.     return NOERROR;
  887. }
  888.  
  889. //
  890. // Answers TRUE if the 2 given FR structs match.
  891. //
  892. inline BOOL FrEq(FR *pfr1, FR *pfr2)
  893. {
  894.     //
  895.     // NOTE: these should be orderd beginning with fields most likely to differ
  896.     //
  897.     // CONSIDER: chould keep a CRC-type field at the beginning of
  898.     // CONSIDER: the struct to speed up detection of non-matches...
  899.     //
  900.     if (pfr1->cySize.Lo != pfr2->cySize.Lo)
  901.         {
  902.         return FALSE;
  903.         }
  904.     if (::lstrcmpiW(pfr1->rgchFace, pfr2->rgchFace))
  905.         {
  906.         return FALSE;
  907.         }
  908.     if (pfr1->bFlags != pfr2->bFlags)
  909.         {
  910.         return FALSE;
  911.         }
  912.     if (pfr1->sWeight != pfr2->sWeight)
  913.         {
  914.         return FALSE;
  915.         }
  916.     if (pfr1->sCharset != pfr2->sCharset)
  917.         {
  918.         return FALSE;
  919.         }
  920.     if (pfr1->cyLogical != pfr2->cyLogical)
  921.         {
  922.         return FALSE;
  923.         }
  924.     if (pfr1->cyHimetric != pfr2->cyHimetric)
  925.         {
  926.         return FALSE;
  927.         }
  928.     if (pfr1->cySize.Hi != pfr2->cySize.Hi)
  929.         {
  930.         return FALSE;
  931.         }
  932.  
  933.     return TRUE;
  934. }
  935.  
  936. //
  937. // Try to locate a matching font in the font cache.
  938. //
  939. // NOTE: access synchronized by the caller!
  940. //
  941. HRESULT CCeFont::FindMatchingFont(int *pnFcr)
  942. {
  943.     int i;
  944.     FCR *pfcr;
  945.  
  946.     for (i = 0, pfcr = s_rgfcr; i < s_cFcr; ++i, ++pfcr) 
  947.         {
  948.         if (!pfcr->hfont)
  949.             {
  950.             continue; // skip empty entry
  951.             }
  952.         if (FrEq(&pfcr->frRequest, &m_fr) || FrEq(&pfcr->frActual, &m_fr)) 
  953.             {
  954.             *pnFcr = i;
  955.             return NOERROR; // Found one!
  956.             }
  957.         }
  958.  
  959.     return S_FALSE;
  960. }
  961.  
  962. //
  963. // Realize a font that matches our current FR description.
  964. //
  965. // NOTE: access synchronized by the caller!
  966. //
  967. HRESULT CCeFont::CreateMatchingFont(HFONT *phfont)
  968. {
  969.     double n;
  970.     LOGFONT lf;
  971.     HFONT hfont;
  972.     //
  973.     //  Font properties we ignore...
  974.     //
  975.     lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  976.     lf.lfEscapement = 0;
  977.     lf.lfOrientation = 0;
  978.     lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
  979.     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  980.     lf.lfQuality = DEFAULT_QUALITY;
  981.     lf.lfWidth = 0;
  982.     //
  983.     // properties that we dont ignore...
  984.     //
  985.     ::lstrcpyW(lf.lfFaceName, m_fr.rgchFace);
  986.     
  987.     lf.lfWeight    = m_fr.sWeight;
  988.     lf.lfCharSet   = (BYTE)m_fr.sCharset;
  989.     lf.lfItalic    = m_fr.fItalic;
  990.     lf.lfUnderline = m_fr.fUnderline;
  991.     lf.lfStrikeOut = m_fr.fStrikethrough;
  992.  
  993.     if (m_fr.cyLogical == 1 && m_fr.cyHimetric == 1) 
  994.     {
  995.         n = (double)m_fr.cySize.Lo * (double)GetDeviceCaps(Hdc(), LOGPIXELSY);
  996.         lf.lfHeight = (int)RoundFloatDiv(n, 720000.0);
  997.     } 
  998.     else 
  999.     {
  1000.         n = RoundFloatDiv((double)m_fr.cySize.Lo * 254.0, 72000.0);
  1001.         lf.lfHeight = (int)RoundFloatDiv(n * (double)m_fr.cyLogical,
  1002.             (double)m_fr.cyHimetric);
  1003.     }
  1004.  
  1005.     if (lf.lfHeight <= 0) 
  1006.     {
  1007.         ASSERT(lf.lfHeight == 0);
  1008.         lf.lfHeight = 1;
  1009.     }
  1010.  
  1011.     lf.lfHeight = -lf.lfHeight; //  Use character height
  1012.  
  1013.     hfont = ::CreateFontIndirect(&lf);
  1014.     if (!hfont)
  1015.         {
  1016.         return HRESULT_FROM_WIN32(GetLastError());
  1017.         }
  1018.  
  1019.     *phfont = hfont;
  1020.  
  1021.     return NOERROR;
  1022. }
  1023.  
  1024. //
  1025. // Return an unused font cache record.  This may require growing
  1026. // the font cache.
  1027. //
  1028. // NOTE: access synchronized by the caller!
  1029. //
  1030. HRESULT CCeFont::NewFcr(int *pnFcr)
  1031. {
  1032.     int i;
  1033.     FCR *pfcr;
  1034.     //
  1035.     // Look for an unused cache slot...
  1036.     //
  1037.     for (i = 0, pfcr = s_rgfcr; i < s_cFcr; ++i, ++pfcr) 
  1038.         {
  1039.         if (pfcr->cRefs == 0) 
  1040.             {
  1041.             if (pfcr->hfont)
  1042.                 {
  1043.                 ::DeleteObject((HGDIOBJ) pfcr->hfont);
  1044.                 memset(pfcr, 0, sizeof(FCR));
  1045.                 *pnFcr = i;
  1046.                 return NOERROR;
  1047.                 }
  1048.     // Grow the cache by a few
  1049.             }
  1050.         }
  1051.     //
  1052.     //
  1053.     pfcr = (FCR*)wce_CoTaskMemRealloc(s_rgfcr, sizeof(FCR) * s_cFcr,
  1054.                                       sizeof(FCR) * (s_cFcr+FONT_CACHE_GROWBY));
  1055.     if(pfcr == NULL)
  1056.         {
  1057.         return E_OUTOFMEMORY;
  1058.         }
  1059.     //
  1060.     // Zero out thew new nodes
  1061.     //
  1062.     memset(&pfcr[s_cFcr], 0, sizeof(FCR) * FONT_CACHE_GROWBY);
  1063.     //
  1064.     // Take the next available slot
  1065.     //
  1066.     *pnFcr = s_cFcr;
  1067.  
  1068.     s_cFcr += FONT_CACHE_GROWBY;
  1069.     s_rgfcr = pfcr;
  1070.  
  1071.     return NOERROR;
  1072. }
  1073.  
  1074. //
  1075. // CUnknown
  1076. //
  1077. STDMETHODIMP CCeFont::InternalQueryInterface(REFIID riid, PVOID *ppv)
  1078. {
  1079.     if ((IID_IFont == riid) || (IID_IUnknown == riid))
  1080.     {
  1081.         return GetInterface((IFont *) this, ppv);        
  1082.     }
  1083.  
  1084.     if (IID_IDispatch == riid)
  1085.     {
  1086.         return GetInterface((IFontDisp *) this, ppv);
  1087.     }
  1088.  
  1089.     if(IID_IFontDisp == riid)
  1090.     {
  1091.         return GetInterface((IFontDisp *) this, ppv);
  1092.     }
  1093.  
  1094.     if (IID_IPersistStream == riid)
  1095.     {
  1096.         return GetInterface((IPersistStream *) this, ppv);
  1097.     }
  1098.  
  1099.     if (IID_IPersistStreamInit == riid)
  1100.     {
  1101.         return GetInterface((IPersistStreamInit *) this, ppv);
  1102.     }
  1103.  
  1104.     if (IID_IPersistPropertyBag == riid)
  1105.     {
  1106.         return GetInterface((IPersistPropertyBag *) this, ppv);
  1107.     }
  1108.  
  1109.     return CUnknown::InternalQueryInterface(riid, ppv);
  1110. }
  1111.  
  1112. const int NUM_FONTPROPS=8;
  1113.  
  1114. struct tag_fontprop
  1115. {
  1116.     OLECHAR* szName;
  1117.     OLECHAR* szPersistName;
  1118.     DISPID dispid;
  1119. } szFontProps[NUM_FONTPROPS] = 
  1120. {
  1121.     {OLESTR("Name"),          OLESTR("OLECE_Name"),          DISPID_FONT_NAME},
  1122.     {OLESTR("Size"),          OLESTR("OLECE_Size"),          DISPID_FONT_SIZE},  
  1123.     {OLESTR("Bold"),          OLESTR("OLECE_Bold"),          DISPID_FONT_BOLD},
  1124.     {OLESTR("Italic"),        OLESTR("OLECE_Italic"),        DISPID_FONT_ITALIC},
  1125.     {OLESTR("Underline"),     OLESTR("OLECE_Underline"),     DISPID_FONT_UNDER},
  1126.     {OLESTR("Strikethrough"), OLESTR("OLECE_Strikethrough"), DISPID_FONT_STRIKE},
  1127.     {OLESTR("Weight"),        OLESTR("OLECE_Weight"),        DISPID_FONT_WEIGHT},
  1128.     {OLESTR("Charset"),       OLESTR("OLECE_Charset"),       DISPID_FONT_CHARSET}
  1129. };
  1130.  
  1131.  
  1132. HRESULT CCeFont::GetTypeInfoCount(UINT *pctInfo)            
  1133. {                                                    
  1134.     return E_NOTIMPL;                                    
  1135. }                                                    
  1136.  
  1137. HRESULT CCeFont::GetTypeInfo(UINT itinfo, LCID lcid,        
  1138.                         ITypeInfo **pptinfo)            
  1139. {                                                    
  1140.     return E_NOTIMPL;                                
  1141. }                                                    
  1142.  
  1143. HRESULT CCeFont::GetIDsOfNames(REFIID riid,                
  1144.                         OLECHAR **rgszNames,        
  1145.                         UINT    cNames,                
  1146.                         LCID    lcid,                
  1147.                         DISPID    *rgdispids)                            
  1148. {            
  1149.     // check arguments
  1150.     if (riid != IID_NULL)
  1151.         return DISP_E_UNKNOWNINTERFACE;
  1152.  
  1153.     // find a match for the property name (assume that no method names will be requested)
  1154.     rgdispids[0] = DISPID_UNKNOWN;
  1155.     for(UINT n=0; n < NUM_FONTPROPS; n++)
  1156.     {
  1157.         if(lstrcmpi(*rgszNames, szFontProps[n].szName) == 0)
  1158.         {
  1159.             rgdispids[0] = szFontProps[n].dispid;
  1160.             break;
  1161.         }
  1162.     }
  1163.     if(rgdispids[0] == DISPID_UNKNOWN)
  1164.         return DISP_E_UNKNOWNNAME;
  1165.  
  1166.     // argument names are always DISPID_UNKNOWN (for this implementation)
  1167.     for (n=1; n < cNames; n++)
  1168.         rgdispids[n] = DISPID_UNKNOWN;
  1169.  
  1170.     return S_OK;                                    
  1171. }    
  1172.  
  1173. HRESULT CCeFont::Invoke(DISPID dispid,                        
  1174.                     REFIID riid, LCID, WORD wFlags,
  1175.                     DISPPARAMS *pdispparams,            
  1176.                     VARIANT *pVarResult, EXCEPINFO *,
  1177.                     UINT *puArgErr)                        
  1178. {    
  1179.     if (riid != IID_NULL)
  1180.         return DISP_E_UNKNOWNINTERFACE;
  1181.  
  1182.     if(wFlags & (DISPATCH_PROPERTYGET | DISPATCH_METHOD))
  1183.     {
  1184.         if(pVarResult == NULL)
  1185.             return DISP_E_PARAMNOTOPTIONAL;
  1186.  
  1187.         AfxVariantInit(pVarResult);    
  1188.     
  1189.         switch(dispid)
  1190.         {
  1191.             case DISPID_FONT_NAME:
  1192.                 pVarResult->vt = VT_BSTR;
  1193.                 return get_Name(&pVarResult->bstrVal);
  1194.             break;
  1195.             case DISPID_FONT_SIZE:
  1196.                 pVarResult->vt = VT_CY;
  1197.                 return get_Size(&pVarResult->cyVal);
  1198.             break;
  1199.             case DISPID_FONT_BOLD:
  1200.                 pVarResult->vt = VT_BOOL;
  1201.                 return get_Bold((BOOL*)&pVarResult->boolVal);
  1202.             break;
  1203.             case DISPID_FONT_ITALIC:
  1204.                 pVarResult->vt = VT_BOOL;
  1205.                 return get_Italic((BOOL*)&pVarResult->boolVal);
  1206.             break;
  1207.             case DISPID_FONT_UNDER:
  1208.                 pVarResult->vt = VT_BOOL;
  1209.                 return get_Underline((BOOL*)&pVarResult->boolVal);
  1210.             break;
  1211.             case DISPID_FONT_STRIKE:
  1212.                 pVarResult->vt = VT_BOOL;
  1213.                 return get_Strikethrough((BOOL*)&pVarResult->boolVal);
  1214.             break;
  1215.             case DISPID_FONT_WEIGHT:
  1216.                 pVarResult->vt = VT_I2;
  1217.                 return get_Weight(&pVarResult->iVal);
  1218.             break;
  1219.             case DISPID_FONT_CHARSET:
  1220.                 pVarResult->vt = VT_I2;
  1221.                 return get_Charset(&pVarResult->iVal);
  1222.             break;
  1223.             default:
  1224.                 return DISP_E_MEMBERNOTFOUND;
  1225.             break;
  1226.         }
  1227.     }
  1228.     else if(wFlags & DISPATCH_PROPERTYPUT)
  1229.     {
  1230.         // Crack/validate pdispparams
  1231.         if(pdispparams->cArgs != 1) // exactly one argument required
  1232.             return DISP_E_BADPARAMCOUNT;
  1233.     
  1234.         if(pdispparams->rgvarg == NULL)
  1235.             return DISP_E_PARAMNOTOPTIONAL;
  1236.  
  1237.         if(puArgErr != NULL)
  1238.             *puArgErr = 0; // if rgvarg->vt (the first type) is the wrong type, then set the index to 0
  1239.  
  1240.         VARIANTARG* rgvarg = pdispparams->rgvarg;
  1241.  
  1242.         switch(dispid)
  1243.         {
  1244.             case DISPID_FONT_NAME:
  1245.                 if(rgvarg->vt != VT_BSTR)
  1246.                     return DISP_E_TYPEMISMATCH;
  1247.                 return put_Name(rgvarg->bstrVal);
  1248.             break;
  1249.             case DISPID_FONT_SIZE:
  1250.                 if(rgvarg->vt == VT_CY)
  1251.                 {
  1252.                     return put_Size(rgvarg->cyVal);
  1253.                 }
  1254.                 else if(rgvarg->vt == VT_I2)
  1255.                 {
  1256.                     CY cy = {rgvarg->iVal * 10000, 0};
  1257.                     return put_Size(cy);
  1258.                 }
  1259.                 else if(rgvarg->vt == VT_I4)
  1260.                 {
  1261.                     CY cy = {rgvarg->lVal * 10000, 0};
  1262.                     return put_Size(cy);
  1263.                 }
  1264.                 else
  1265.                 {
  1266.                     return DISP_E_TYPEMISMATCH;
  1267.                 }
  1268.             break;
  1269.             case DISPID_FONT_BOLD:
  1270.                 if(rgvarg->vt != VT_BOOL)
  1271.                     return DISP_E_TYPEMISMATCH;
  1272.                 return put_Bold((BOOL)rgvarg->boolVal);
  1273.             break;
  1274.             case DISPID_FONT_ITALIC:
  1275.                 if(rgvarg->vt != VT_BOOL)
  1276.                     return DISP_E_TYPEMISMATCH;
  1277.                 return put_Italic((BOOL)rgvarg->boolVal);
  1278.             break;
  1279.             case DISPID_FONT_UNDER:
  1280.                 if(rgvarg->vt != VT_BOOL)
  1281.                     return DISP_E_TYPEMISMATCH;
  1282.                 return put_Underline((BOOL)rgvarg->boolVal);
  1283.             break;
  1284.             case DISPID_FONT_STRIKE:
  1285.                 if(rgvarg->vt != VT_BOOL)
  1286.                     return DISP_E_TYPEMISMATCH;
  1287.                 return put_Strikethrough((BOOL)rgvarg->boolVal);
  1288.             break;
  1289.             case DISPID_FONT_WEIGHT:
  1290.                 if(rgvarg->vt != VT_I2)
  1291.                     return DISP_E_TYPEMISMATCH;
  1292.                 return put_Weight(rgvarg->iVal);
  1293.             break;
  1294.             case DISPID_FONT_CHARSET:
  1295.                 if(rgvarg->vt != VT_I2)
  1296.                     return DISP_E_TYPEMISMATCH;
  1297.                 return put_Charset(rgvarg->iVal);
  1298.             break;
  1299.             default:
  1300.                 return DISP_E_MEMBERNOTFOUND;
  1301.             break;
  1302.         }
  1303.     }
  1304.  
  1305.     return E_NOTIMPL;                                    
  1306. }    
  1307.  
  1308. //
  1309. // Initialize the font cache
  1310. //
  1311. // NOTE: access synchronized by the caller!
  1312. //
  1313. HRESULT CCeFont::InitFontObject()
  1314. {
  1315.     // Allocate the font cache, start it out with a few slots
  1316.     CCeFont::s_rgfcr = (FCR*)::CoTaskMemAlloc(sizeof(FCR) * FONT_CACHE_GROWBY);
  1317.     if (CCeFont::s_rgfcr == NULL)
  1318.         {
  1319.         return E_OUTOFMEMORY;
  1320.         }
  1321.  
  1322.     memset(s_rgfcr, 0, sizeof(FCR) * FONT_CACHE_GROWBY);
  1323.  
  1324.     CCeFont::s_cFcr = FONT_CACHE_GROWBY;
  1325.  
  1326.     return NOERROR;
  1327. }
  1328.  
  1329. //
  1330. // Un-initialize the font cache
  1331. //
  1332. // NOTE: access synchronized by the caller!
  1333. //
  1334. HRESULT CCeFont::UninitFontObject()
  1335. {
  1336.     FCR *pfcr, *pfcrEnd;
  1337.     //
  1338.     // Delete any fonts remaining in the cache
  1339.     pfcrEnd = &s_rgfcr[s_cFcr];
  1340.     for (pfcr = s_rgfcr; pfcr < pfcrEnd; ++pfcr) 
  1341.         {
  1342.         if (pfcr->hfont != NULL) 
  1343.             {
  1344.             ::DeleteObject((HGDIOBJ) pfcr->hfont);
  1345.             }
  1346.         }
  1347.     //
  1348.     // Free the font cache
  1349.     //
  1350.     s_cFcr = 0;
  1351.     ::CoTaskMemFree(s_rgfcr);
  1352.  
  1353.     CCeFont::s_fInit = FALSE;
  1354.  
  1355.     return NOERROR;
  1356. }
  1357.  
  1358. //
  1359. // Routine used by the class object
  1360. //
  1361. HRESULT CCeFont::CreateFont(LPFONTDESC pfd, REFIID riid, PVOID *ppv)
  1362. {
  1363.     if (!ppv)
  1364.         {
  1365.         return E_INVALIDARG;
  1366.         }
  1367.  
  1368.     CCeFont *pfont;
  1369.     HRESULT hr;
  1370.  
  1371.     if (!m_hdc)
  1372.         {
  1373.         HWND hWnd = ::GetForegroundWindow(); // any window will do
  1374.         if(hWnd == NULL)
  1375.             hWnd = ::GetActiveWindow();
  1376.         ASSERT(hWnd != NULL);
  1377.         HDC hdc = ::GetDC(hWnd);
  1378.         ASSERT(hdc != NULL);
  1379.         if (hdc != NULL)
  1380.             {
  1381.             m_hdc = ::CreateCompatibleDC(hdc);
  1382.             ::ReleaseDC(hWnd,hdc);
  1383.             }
  1384.         }
  1385.  
  1386.     if (!m_hdc)
  1387.         {
  1388.         ASSERT(m_hdc);
  1389.         return E_FAIL;
  1390.         }
  1391.  
  1392.     pfont = new CCeFont();
  1393.     if (!pfont)
  1394.         {
  1395.         return E_OUTOFMEMORY;
  1396.         }
  1397.     //
  1398.     // If no font description provided, create a default font
  1399.     //
  1400.     if (!pfd)
  1401.         {
  1402.         pfd = &s_fdDefault;
  1403.         }
  1404.     //
  1405.     // Set up the font record
  1406.     //
  1407.     pfont->m_fr.sWeight     = pfd->sWeight;
  1408.     pfont->m_fr.sCharset    = pfd->sCharset;
  1409.     pfont->m_fr.fItalic     = pfd->fItalic;
  1410.     pfont->m_fr.fUnderline  = pfd->fUnderline;
  1411.     pfont->m_fr.fStrikethrough = pfd->fStrikethrough;
  1412.     pfont->m_fr.cySize.Hi   = pfd->cySize.Hi;
  1413.     pfont->m_fr.cySize.Lo   = pfd->cySize.Lo;
  1414.     ::wcsncpy(pfont->m_fr.rgchFace, pfd->lpstrName, LF_FACESIZE);
  1415.     //
  1416.     // Get the requested pointer..
  1417.     //
  1418.     hr = pfont->QueryInterface(riid, ppv);
  1419.  
  1420.     if (FAILED(hr))
  1421.         {
  1422.         delete pfont;
  1423.         }
  1424.     
  1425.     return hr;
  1426. }
  1427.  
  1428. //
  1429. // RoundFloatDiv -- rounded floating-point division
  1430. //
  1431. double CCeFont::RoundFloatDiv(double numer, double denom)
  1432. {
  1433.     double quotient = numer / denom;
  1434.  
  1435.     double absrem = fabs(fmod(numer, denom));
  1436.  
  1437.     if (fabs(denom) - absrem <= absrem)
  1438.         {
  1439.         if (quotient >= 0)
  1440.             {
  1441.             quotient++;
  1442.             }
  1443.           else
  1444.             {
  1445.             quotient--;
  1446.             }
  1447.         }
  1448.     return quotient;
  1449. }
  1450.  
  1451. // Rounded long division
  1452. long RoundDiv(long numer, long denom)
  1453. {
  1454.     long quotient;
  1455.  
  1456.     if (numer < 0) {
  1457.       if (denom < 0) {
  1458.         // neg / neg = pos
  1459.         quotient = (numer - ((-denom)>>1)) / denom;
  1460.       }
  1461.       else {
  1462.         // neg / pos = neg
  1463.         quotient = (numer - (denom>>1)) / denom;
  1464.       }
  1465.     }
  1466.     else {
  1467.       if (denom < 0) {
  1468.         // pos / neg = neg
  1469.         quotient = (numer + ((-denom)>>1)) / denom;
  1470.       }
  1471.       else {
  1472.         // pos / pos = pos
  1473.         quotient = (numer + (denom>>1)) / denom;
  1474.       }
  1475.     }
  1476.     return quotient;
  1477. }
  1478.  
  1479.  
  1480. //
  1481. // Call-back function to find the char set of a face name.
  1482. //
  1483. int CALLBACK CharSetOfFaceCallBack(ENUMLOGFONT *pelfx, TEXTMETRIC *ptm, int FontType,
  1484.                                 LPARAM  lp)
  1485. {
  1486.     UNUSED(pelfx);
  1487.     UNUSED(FontType);
  1488.  
  1489.     *(DWORD*)lp = (DWORD)ptm->tmCharSet;
  1490.  
  1491.     return 0;
  1492. }
  1493.  
  1494. //
  1495. // Lookup the CharSet that the given font face name belongs to.
  1496. //
  1497. HRESULT CharSetOfFace(HDC hdc, OLECHAR *szFaceName, WORD *pwCharset)
  1498. {
  1499.     TCHAR  lfFaceName[LF_FACESIZE];
  1500.     DWORD dwCharset = (DWORD)(-1);
  1501.  
  1502.     ::lstrcpyW(lfFaceName, szFaceName);
  1503.     ::EnumFontFamilies(hdc, lfFaceName, (FONTENUMPROC)CharSetOfFaceCallBack,
  1504.                       (LPARAM)&dwCharset);
  1505.  
  1506.     if (dwCharset == (DWORD)-1)
  1507.         {
  1508.         return E_FAIL;
  1509.         }
  1510.  
  1511.     *pwCharset = (WORD)dwCharset;
  1512.  
  1513.     return NOERROR;
  1514. }
  1515.  
  1516.  
  1517.  
  1518.  
  1519. //
  1520. // Statics
  1521. //
  1522. PFNADDREF CUnknown::m_pfnAddRef = NULL;
  1523. PFNRELEASE CUnknown::m_pfnRelease = NULL;
  1524. CRITICAL_SECTION CUnknown::m_csUnkLock;
  1525.  
  1526. //
  1527. // Constructor
  1528. // 1. Initialize Ref count to 0.
  1529. // 2. Save aggregating unknown, if any is provided. Else set the aggregating unknown to be
  1530. //  this object itself (keeps code simple.. so there is ALWAYS an aggregating unknown)
  1531. //
  1532. // Parameters:
  1533. //  pUnk: aggregating unknown, if any
  1534. //
  1535. CUnknown::CUnknown(IUnknown *pUnk)
  1536. {
  1537.     m_cRef = 0;    // should always be zero
  1538.     if (pUnk)
  1539.         {
  1540.         //
  1541.         // This object is being aggregated
  1542.         //
  1543.         m_pUnkOwner = pUnk;
  1544.         }
  1545.     else
  1546.         {
  1547.         //
  1548.         // the object owns itself! This greatly simplifies the code. This cast from 
  1549.         // IInternalUnknown to IUnknown is a dirty trick, but really makes life easier, and
  1550.         // gets around the compiler. It exploits the fact that IUnknown and IInternalUnknown
  1551.         // are identical interfaces, with identical V-tables and identical type information.
  1552.         //
  1553.         //
  1554.         m_pUnkOwner = (IUnknown *) (IInternalUnknown *) this;    
  1555.         }
  1556. }
  1557.  
  1558. //
  1559. // Virtual Destructor
  1560. //
  1561. CUnknown::~CUnknown(void)
  1562. {
  1563.     ASSERT(0 == m_cRef);
  1564. }
  1565.  
  1566. //
  1567. // A generic implementation of a QueryInterface for IUnknown
  1568. //
  1569. // Parameters:
  1570. //  riid:   interface requrested
  1571. //  ppv: receives the interface
  1572. //
  1573. // Returns:
  1574. //  E_INVALIDARG, E_NOINTERFACE
  1575. //  NOERROR
  1576. //
  1577. STDMETHODIMP CUnknown::InternalQueryInterface(REFIID riid, PVOID *ppv)
  1578. {
  1579.     if (!ppv)
  1580.         {
  1581.         ASSERT(ppv);
  1582.         return E_INVALIDARG;
  1583.         }
  1584.  
  1585.     if (riid == IID_IUnknown)
  1586.         {
  1587.         //
  1588.         // An explicit request for the internal IUnknown query interface..
  1589.         //
  1590.         *ppv = (PVOID) (IUnknown *) (IInternalUnknown *) this;
  1591.         }
  1592.  
  1593.     return E_NOINTERFACE;
  1594. }
  1595.  
  1596. //
  1597. // Up the ref count on this object. 
  1598. // If the component using this class keeps global ref counts, up that
  1599. // Global ref counts are accessed using hte static m_pfnAddRef variable
  1600. //
  1601. STDMETHODIMP_(ULONG) CUnknown::InternalAddRef(void)
  1602. {
  1603.     ::InterlockedIncrement(&m_cRef);
  1604.  
  1605.     //
  1606.     // Up the global ref count
  1607.     //
  1608.     if (m_pfnAddRef) // global ref count is accessed using this function
  1609.         {
  1610.         (*m_pfnAddRef) ();
  1611.         }
  1612.  
  1613.     return m_cRef; 
  1614. }
  1615.  
  1616. //
  1617. // Decrement the ref count. If the count is 0, commit suicide
  1618. // If the component using this class keeps global ref counts, decrement that
  1619. // Global ref counts are accessed using hte static m_pfnRelease variable
  1620. //
  1621. STDMETHODIMP_(ULONG) CUnknown::InternalRelease(void)
  1622. {
  1623.     LONG cRef;
  1624.     
  1625.     cRef = ::InterlockedDecrement(&m_cRef);
  1626.  
  1627.     //
  1628.     // Lower the global count
  1629.     //
  1630.     if (m_pfnRelease)
  1631.         {
  1632.         (*m_pfnRelease) ();
  1633.         }
  1634.     if (cRef > 0)
  1635.         {
  1636.         return m_cRef;
  1637.         }
  1638.     //
  1639.     // The moment the ref count == 0, we kill this object
  1640.     //
  1641.     delete this;
  1642.  
  1643.     return 0; // ref count is now zero
  1644. }
  1645.  
  1646. //
  1647. // Just a simple useful little wrapper that does AddRef() on a retrieve interface
  1648. //
  1649. HRESULT CUnknown::GetInterface(IUnknown *pUnk, PVOID *ppv)
  1650. {
  1651.     ASSERT(pUnk);
  1652.     
  1653.     if (pUnk)
  1654.         {        
  1655.         *ppv = pUnk;
  1656.         ((IUnknown *) pUnk)->AddRef();
  1657.         
  1658.         return NOERROR;
  1659.         }
  1660.  
  1661.     return E_INVALIDARG;
  1662. }
  1663.  
  1664.  
  1665. // IPersistStream implementation for CCeFont
  1666.  
  1667. STDMETHODIMP CCeFont::GetClassID(LPCLSID lpClassID)
  1668. {
  1669.     *lpClassID = IID_IFont;
  1670.     return S_OK;
  1671. }
  1672.  
  1673. STDMETHODIMP CCeFont::IsDirty()
  1674. {
  1675.     return m_bModified ? S_OK : S_FALSE;
  1676. }
  1677.  
  1678.  
  1679. STDMETHODIMP CCeFont::Load(LPSTREAM pStm)
  1680. {
  1681.     unsigned char buf1[11], buf2[LF_FACESIZE];
  1682.     ULONG cb, nLen;
  1683.  
  1684.     pStm->Read(buf1, 11, &cb);
  1685.     if(cb != 11)
  1686.         return E_OUTOFMEMORY;
  1687.  
  1688.     m_fr.cyLogical  = 1;
  1689.     m_fr.cyHimetric = 1;
  1690.     m_fr.sCharset   = (SHORT)buf1[1];
  1691.     m_fr.bFlags     = buf1[3];
  1692.     m_fr.sWeight    = ((SHORT)buf1[5] << 8) + (SHORT)buf1[4];
  1693.     m_fr.cySize.Lo  = (long)(((ULONG)buf1[9] << 24) + 
  1694.                              ((ULONG)buf1[8] << 16) +
  1695.                              ((ULONG)buf1[7] << 8)  +
  1696.                              ((ULONG)buf1[6]));
  1697.  
  1698.     nLen = (ULONG)buf1[10];
  1699.     ASSERT(nLen < LF_FACESIZE);
  1700.  
  1701.     pStm->Read(buf2, nLen, &cb);
  1702.     if(cb != nLen)
  1703.         return E_OUTOFMEMORY;
  1704.  
  1705.     buf2[nLen] = L'\0';
  1706.     wce_AsciiToWide(m_fr.rgchFace, (char*)buf2);
  1707.  
  1708.     return S_OK;
  1709. }
  1710.  
  1711. STDMETHODIMP CCeFont::Save(LPSTREAM pStm, BOOL fClearDirty)
  1712. {
  1713.     unsigned char buf1[11], buf2[LF_FACESIZE];
  1714.     ULONG cb, nLen;
  1715.  
  1716.     nLen = (ULONG)wcslen(m_fr.rgchFace);
  1717.  
  1718.     buf1[0]  = 1;                              // unknown flag
  1719.     buf1[1]  = (BYTE)m_fr.sCharset;            // charset
  1720.     buf1[2]  = 0;                              // unknown flag
  1721.     buf1[3]  = m_fr.bFlags;                    // style bits
  1722.     buf1[4]  = LOBYTE((WORD)m_fr.sWeight);     // weight (lo byte)
  1723.     buf1[5]  = HIBYTE((WORD)m_fr.sWeight);     // weight (hi byte)
  1724.     DWORD dwSize = (DWORD)m_fr.cySize.Lo;      // size
  1725.     buf1[6]  = LOBYTE(LOWORD(dwSize));   
  1726.     buf1[7]  = HIBYTE(LOWORD(dwSize)); 
  1727.     buf1[8]  = LOBYTE(HIWORD(dwSize)); 
  1728.     buf1[9]  = HIBYTE(HIWORD(dwSize));                               
  1729.     buf1[10] = (BYTE)nLen;                     // length of face name (excluding null terminator)
  1730.     wce_T2CAHelper((char*)buf2, m_fr.rgchFace);
  1731.  
  1732.     pStm->Write(buf1, 11, &cb);
  1733.     if(cb != 11)
  1734.         return STG_E_MEDIUMFULL;
  1735.  
  1736.     pStm->Write(buf2, nLen, &cb);
  1737.     if(cb != nLen)
  1738.         return STG_E_MEDIUMFULL;
  1739.     
  1740.     if (fClearDirty)
  1741.         m_bModified = FALSE;
  1742.  
  1743.     return S_OK;
  1744. }
  1745.  
  1746. STDMETHODIMP CCeFont::GetSizeMax(ULARGE_INTEGER*)
  1747. {
  1748.     return E_NOTIMPL;
  1749. }
  1750.  
  1751.  
  1752.  
  1753.  
  1754. // IPersistStream implementation for CCeFont
  1755.  
  1756. STDMETHODIMP CCeFont::InitNew()
  1757. {
  1758.     FONTDESC* pfd = &s_fdDefault;
  1759.  
  1760.     m_fr.cyLogical  = 1;
  1761.     m_fr.cyHimetric = 1;
  1762.     m_fr.sWeight     = pfd->sWeight;
  1763.     m_fr.sCharset    = pfd->sCharset;
  1764.     m_fr.fItalic     = pfd->fItalic;
  1765.     m_fr.fUnderline  = pfd->fUnderline;
  1766.     m_fr.fStrikethrough = pfd->fStrikethrough;
  1767.     m_fr.cySize.Hi   = pfd->cySize.Hi;
  1768.     m_fr.cySize.Lo   = pfd->cySize.Lo;
  1769.     ::wcsncpy(m_fr.rgchFace, pfd->lpstrName, LF_FACESIZE);
  1770.  
  1771.     return S_OK;
  1772. }
  1773.  
  1774. // Note: Unlike the IPersistStream implementation, this IPersistPropertyBag implemenation
  1775. //        does NOT match the bahavior of OleCreateFontIndirect's.
  1776. STDMETHODIMP CCeFont::Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog)
  1777. {
  1778.     ASSERT_POINTER(pPropBag, IPropertyBag);
  1779.  
  1780.     VARIANT varSig;
  1781.     AfxVariantInit(&varSig);
  1782.     if(FAILED(pPropBag->Read(OLESTR("OLECE_Signature"), &varSig, pErrorLog)))
  1783.         return E_OUTOFMEMORY;
  1784.  
  1785.     if((varSig.vt == VT_I2) && (V_I2(&varSig) == (short)0xA77A))
  1786.     {
  1787.         // Our test says that OLECE.DLL's CCeFont was used to save the data
  1788.         VARIANT var[NUM_FONTPROPS];
  1789.         int i;
  1790.  
  1791.         for(i=0; i < NUM_FONTPROPS; i++ )
  1792.             AfxVariantInit(&var[i]);
  1793.  
  1794.         for(i=0; i < NUM_FONTPROPS; i++ )
  1795.         {    
  1796.             if(FAILED(pPropBag->Read(szFontProps[i].szPersistName, &var[i], pErrorLog)))
  1797.                 return E_OUTOFMEMORY;
  1798.         }
  1799.  
  1800.         m_fr.cyLogical  = 1;
  1801.         m_fr.cyHimetric = 1;
  1802.         put_Name(V_BSTR(&var[0])); 
  1803.         put_Size(V_CY(&var[1])); 
  1804.         put_Bold(V_BOOL(&var[2])); 
  1805.         put_Italic(V_BOOL(&var[3])); 
  1806.         put_Underline(V_BOOL(&var[4])); 
  1807.         put_Strikethrough(V_BOOL(&var[5])); 
  1808.         put_Weight(V_I2(&var[6])); 
  1809.         put_Charset(V_I2(&var[7]));
  1810.         
  1811.         SysFreeString(V_BSTR(&var[0])); // assuming pPropBag->Read allocated it
  1812.     }
  1813.     else 
  1814.     {
  1815.         // If we get here, we should assume OleCreateFontIndirect persisted the data, 
  1816.         // because that's the only thing that would make sense.  However, this is not 
  1817.         // a WinCE function.  For now, it's a bad situation.  
  1818.         ASSERT(FALSE);
  1819.         InitNew();
  1820.     }
  1821.  
  1822.     return S_OK;
  1823. }
  1824.  
  1825. STDMETHODIMP CCeFont::Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, 
  1826.                            BOOL fSaveAllProperties)
  1827. {
  1828.     HRESULT hResult = S_OK;
  1829.  
  1830.     ASSERT_POINTER(pPropBag, IPropertyBag);
  1831.  
  1832.     // Write out signature so that we know who persisted this data (i.e. OleCreateFontIndirect didn't)
  1833.     VARIANT varSig;
  1834.     AfxVariantInit(&varSig);
  1835.     varSig.vt = VT_I2;
  1836.     V_I2(&varSig) = (short)0xA77A; 
  1837.     if(FAILED(pPropBag->Write(OLESTR("OLECE_Signature"), &varSig)))
  1838.         return STG_E_MEDIUMFULL;
  1839.  
  1840.     // Write out font data (using our own CCeFont persistence format, NOT OleCreateFontIndirect's)
  1841.     VARIANT var[NUM_FONTPROPS];
  1842.     for(int i=0; i < NUM_FONTPROPS; i++)
  1843.         AfxVariantInit(&var[i]);
  1844.  
  1845.     var[0].vt = VT_BSTR;
  1846.     V_BSTR(&var[0]) = SysAllocString(m_fr.rgchFace);
  1847.     if(V_BSTR(&var[0]) == NULL)
  1848.         return E_OUTOFMEMORY;
  1849.     
  1850.     var[1].vt = VT_CY;
  1851.     V_CY(&var[1]) = m_fr.cySize;
  1852.  
  1853.     var[2].vt = VT_BOOL;
  1854.     V_BOOL(&var[2]) = m_fr.fBold;
  1855.  
  1856.     var[3].vt = VT_BOOL;
  1857.     V_BOOL(&var[3]) = m_fr.fItalic;
  1858.  
  1859.     var[4].vt = VT_BOOL;
  1860.     V_BOOL(&var[4]) = m_fr.fUnderline;
  1861.  
  1862.     var[5].vt = VT_BOOL;
  1863.     V_BOOL(&var[5]) = m_fr.fStrikethrough;
  1864.  
  1865.     var[6].vt = VT_I2;
  1866.     V_I2(&var[6]) = m_fr.sWeight;
  1867.  
  1868.     var[7].vt = VT_I2;
  1869.     V_I2(&var[7]) = m_fr.sCharset;
  1870.  
  1871.     for(i=0; i < NUM_FONTPROPS; i++ )
  1872.     {
  1873.         if(FAILED(pPropBag->Write(szFontProps[i].szPersistName, &var[i])))
  1874.         {
  1875.             hResult = STG_E_MEDIUMFULL;
  1876.             break;
  1877.         }
  1878.     }
  1879.  
  1880.     if (fClearDirty && (hResult == S_OK))
  1881.         m_bModified = FALSE;
  1882.  
  1883.     SysFreeString(V_BSTR(&var[0]));
  1884.  
  1885.     return hResult;
  1886. }
  1887.