home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / OS / FWGraphx / SLRender.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  48.9 KB  |  1,881 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLRender.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWOS.hpp"
  11.  
  12. #ifndef SLRENDER_H
  13. #include "SLRender.h"
  14. #endif
  15.  
  16. #ifndef PRGDEV_H
  17. #include "PRGDev.h"
  18. #endif
  19.  
  20. #ifndef PRTXTBUF_H
  21. #include "PRTxtBuf.h"
  22. #endif
  23.  
  24. #ifndef SLGC_H
  25. #include "SLGC.h"
  26. #endif
  27.  
  28. #ifndef FWRECT_H
  29. #include "FWRect.h"
  30. #endif
  31.  
  32. #ifndef PRMDASH_H
  33. #include "PRMDash.h"
  34. #endif
  35.  
  36. #ifndef FWODGEOM_H
  37. #include "FWODGeom.h"
  38. #endif
  39.  
  40. #ifndef FWSTYLE_H
  41. #include "FWStyle.h"
  42. #endif
  43.  
  44. #ifndef PRPOLY_H
  45. #include "PRPoly.h"
  46. #endif
  47.  
  48. #ifndef SLGRGLOB_H
  49. #include "SLGrGlob.h"
  50. #endif
  51.  
  52. #ifndef PRPICTUR_H
  53. #include "PRPictur.h"
  54. #endif
  55.  
  56. #ifndef PRBITMAP_H
  57. #include "PRBitmap.h"
  58. #endif
  59.  
  60. #ifndef FWGRUTIL_H
  61. #include "FWGrUtil.h"
  62. #endif
  63.  
  64. #ifndef PRGRUTIL_H
  65. #include "PRGrUtil.h"
  66. #endif
  67.  
  68. #ifndef PRICON_H
  69. #include "PRIcon.h"
  70. #endif
  71.  
  72. #ifndef FWMEMMGR_H
  73. #include "FWMemMgr.h"
  74. #endif
  75.  
  76. #if defined(FW_BUILD_MAC) && !defined(__ICONS__)
  77. #include <Icons.h>
  78. #endif
  79.  
  80. #ifndef SLREGION_H
  81. #include "SLRegion.h"
  82. #endif
  83.  
  84. #ifdef FW_BUILD_MAC
  85. #pragma segment FWGraphx_Render
  86. #endif
  87.  
  88. //========================================================================================
  89. // Local helpers
  90. //========================================================================================
  91.  
  92. // All static method can fail
  93. static FW_PlatformCoordinate    PrivTextBox(Environment* ev,
  94.                                     FW_CPrivGraphicsDevice* device,
  95.                                     FW_CPrivTextBuffer *textBuffer, 
  96.                                     const FW_CPlatformRect& box,
  97.                                     FW_TextBoxOptions options,
  98.                                     FW_Boolean draw,
  99.                                     FW_HFont font);
  100.  
  101. static void                        PrivRenderTextBuffer(Environment* ev,
  102.                                     FW_SGraphicContext& gc,
  103.                                     FW_CPrivTextBuffer* textBuffer,
  104.                                     const FW_SPoint& position,
  105.                                     FW_TextAlignment textAlignment,
  106.                                     FW_ERenderVerbs renderVerb,
  107.                                     FW_HInk ink,
  108.                                     FW_HFont font);
  109.                                     
  110. static FW_Fixed                    PrivRenderTextBoxBuffer(Environment* ev,
  111.                                     FW_SGraphicContext& gc,
  112.                                     FW_CPrivTextBuffer* textBuffer, 
  113.                                     const FW_SRect& box,
  114.                                     FW_TextBoxOptions options,
  115.                                     FW_ERenderVerbs renderVerb,
  116.                                     FW_HInk ink,
  117.                                     FW_HFont font);
  118.  
  119. static void                        PrivTextBoxSizeBuffer(Environment* ev,
  120.                                     FW_SGraphicContext& gc,
  121.                                     FW_CPrivTextBuffer *textBuffer, 
  122.                                     FW_HFont font,
  123.                                     FW_TextBoxOptions options,
  124.                                     FW_SRect& textBox);
  125.                         
  126. static void                        PrivTextExtentBuffer(Environment* ev,
  127.                                     FW_SGraphicContext& gc,
  128.                                     FW_CPrivTextBuffer* textBuffer,
  129.                                     FW_HFont font, 
  130.                                     FW_SPoint& textExtent);
  131.  
  132. #ifdef FW_BUILD_MAC
  133.  
  134. static void                        MacSelectInkAndStyle(
  135.                                     FW_CPrivGraphicsDevice* device,
  136.                                     FW_EPrivShapeCategories shapeCategory,
  137.                                     FW_ERenderVerbs renderVerb,
  138.                                     FW_HInk ink,
  139.                                     FW_HStyle style,
  140.                                     FW_Boolean& styleIsDash,
  141.                                     FW_Boolean& styleIsHairline);
  142.  
  143. static FW_CPlatformPoint        MacCalcTextPosition(
  144.                                     FW_CPrivGraphicsDevice* device,
  145.                                     short byteCount, const char* text,
  146.                                     FW_TextAlignment textAlignment,
  147.                                     const FW_CPlatformPoint& position);
  148.  
  149. static void                        MacStrikeOut(
  150.                                     FW_CPrivGraphicsDevice* device,
  151.                                     short beforePosX,
  152.                                     short beforePosY);
  153.  
  154. //----------------------------------------------------------------------------------------
  155. //    FW_PrivSelectHairline -- a Mac utility class for using the SetLineWidth picComment
  156. //----------------------------------------------------------------------------------------
  157.  
  158. class FW_PrivSelectHairline
  159. {
  160. public:
  161.     FW_DECLARE_AUTO(FW_PrivSelectHairline)
  162.         
  163.     FW_PrivSelectHairline(FW_Boolean setHairline);
  164.     ~FW_PrivSelectHairline();
  165.  
  166. private:
  167.  
  168.     enum { eSetLineWidthPicComment = 182 };
  169.  
  170.     FW_PlatformHandle    fData;
  171. };
  172.  
  173. #endif
  174.  
  175. //========================================================================================
  176. // Local macros to make rendering code more straightforward
  177. //========================================================================================
  178.  
  179. #ifdef FW_BUILD_WIN
  180.  
  181. #define FW_CHECK_RENDER    \
  182.     FW_ASSERT(&gc == FW_PrivGC_GetCurrent(ev));
  183.     
  184. #endif
  185.  
  186. #ifdef FW_BUILD_MAC
  187.  
  188. #define FW_CHECK_RENDER    \
  189.     FW_ASSERT(&gc == FW_PrivGC_GetCurrent(ev)); \
  190.     FW_ASSERT(gc.fGraphicDevice->GetPlatformCanvas() == FW_QDGlobals.thePort);
  191.     
  192. #endif
  193.  
  194. #define FW_CHECK_RENDER_VERB \
  195.     if (renderVerb == FW_kNoRendering) \
  196.         return;
  197.  
  198. #define FW_RENDER_PROLOG \
  199.     FW_CHECK_RENDER \
  200.     FW_CPrivGraphicsDevice* device = gc.fGraphicDevice;
  201.  
  202. #define FW_CHECK_INK \
  203.     FW_ASSERT(ink != NULL);
  204.     
  205. #define FW_CHECK_STYLE \
  206.     FW_ASSERT(style != NULL);
  207.     
  208. #define FW_CHECK_FONT \
  209.     FW_ASSERT(font != NULL);
  210.  
  211. //========================================================================================
  212. // Rendering APIs
  213. //========================================================================================
  214.  
  215. //----------------------------------------------------------------------------------------
  216. //    FW_PrivRenderRect
  217. //----------------------------------------------------------------------------------------
  218.  
  219. void SL_API FW_PrivRenderRect(Environment* ev,
  220.                             FW_SGraphicContext&     gc,
  221.                             const FW_SRect&         rect,
  222.                             FW_ERenderVerbs         renderVerb,
  223.                             FW_HInk                 ink,
  224.                             FW_HStyle                 style)
  225. {
  226.     FW_RENDER_PROLOG
  227.     FW_CHECK_RENDER_VERB
  228.     FW_CHECK_INK
  229.     FW_CHECK_STYLE
  230.  
  231.     FW_SOM_TRY
  232.     {
  233.         FW_CPlatformRect plfmRect;
  234.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  235.         FW_FailOnEvError(ev);
  236.             
  237.     #ifdef FW_BUILD_WIN
  238.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, 
  239.                                                         FW_kGeometricShapeWithInvert, 
  240.                                                         renderVerb);
  241.     
  242.         HDC hDC = *device;
  243.         if (frameBrush)
  244.         {
  245.             int penSizeX = device->fPenSize.x;
  246.             int penSizeY = device->fPenSize.y;
  247.     
  248.             device->fGDIBrush.SelectObject(hDC);
  249.             ::PatBlt(hDC, plfmRect.left, plfmRect.top, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  250.             ::PatBlt(hDC, plfmRect.right - penSizeX, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  251.             ::PatBlt(hDC, plfmRect.left, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  252.             ::PatBlt(hDC, plfmRect.left, plfmRect.bottom - penSizeY, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  253.         }
  254.         else
  255.         {
  256.             if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite || || ink->GetTransferMode() == FW_kSystemHilite)
  257.             {
  258.                 ::InvertRect(hDC, &plfmRect);
  259.             }
  260.             else
  261.             {
  262.                 if (renderVerb == FW_kFill)
  263.                 {
  264.                     plfmRect.right++;
  265.                     plfmRect.bottom++;
  266.                 }
  267.                     
  268.                 ::Rectangle(hDC, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  269.             }
  270.         }
  271.     #endif
  272.     #ifdef FW_BUILD_MAC
  273.         FW_Boolean styleIsDash;
  274.         FW_Boolean styleIsHairline;
  275.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  276.     
  277.         if (renderVerb == FW_kFrame)
  278.         {
  279.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  280.             
  281.             if (styleIsDash)
  282.             {
  283.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  284.     
  285.                 ::MoveTo(plfmRect.left, plfmRect.top);
  286.                 draw.LineTo(plfmRect.right - 1, plfmRect.top);
  287.                 draw.LineTo(plfmRect.right - 1, plfmRect.bottom - 1);
  288.                 draw.LineTo(plfmRect.left, plfmRect.bottom - 1);
  289.                 draw.LineTo(plfmRect.left, plfmRect.top);
  290.             }
  291.             else
  292.             {
  293.                 ::FrameRect(&plfmRect);
  294.             }
  295.         }
  296.         else
  297.         {
  298.             switch (ink->GetTransferMode())
  299.             {
  300.                 case FW_kErase:
  301.                     ::EraseRect(&plfmRect);
  302.                     break;
  303.     
  304.                 case FW_kInvert:
  305.                     ::InvertRect(&plfmRect);
  306.                     break;
  307.                     
  308.                 default:
  309.                     ::PaintRect(&plfmRect);            
  310.             }
  311.         }
  312.     #endif
  313.     }
  314.     FW_SOM_CATCH
  315. }
  316.  
  317. //----------------------------------------------------------------------------------------
  318. //    FW_PrivRenderOval
  319. //----------------------------------------------------------------------------------------
  320.  
  321. void SL_API    FW_PrivRenderOval(Environment* ev,
  322.                             FW_SGraphicContext&     gc,
  323.                             const FW_SRect&         rect,
  324.                             FW_ERenderVerbs         renderVerb,
  325.                             FW_HInk                 ink,
  326.                             FW_HStyle                 style)
  327. {
  328.     FW_RENDER_PROLOG
  329.     FW_CHECK_RENDER_VERB
  330.     FW_CHECK_INK
  331.     FW_CHECK_STYLE
  332.  
  333.     FW_SOM_TRY
  334.     {
  335.         FW_CPlatformRect plfmRect;
  336.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  337.         FW_FailOnEvError(ev);
  338.             
  339.     #ifdef FW_BUILD_WIN
  340.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  341.     
  342.         if (frameBrush)
  343.         {
  344.             HRGN hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, plfmRect.right + 1, plfmRect.bottom + 1);
  345.             ::FrameRgn(*device, hrgn, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  346.             ::DeleteObject(hrgn);
  347.         }
  348.         else
  349.         {
  350.             if (renderVerb == FW_kFill)
  351.             {
  352.                 plfmRect.right++;
  353.                 plfmRect.bottom++;
  354.             }
  355.     
  356.             ::Ellipse(*device, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  357.         }
  358.     #endif
  359.     #ifdef FW_BUILD_MAC
  360.         FW_Boolean styleIsDash;
  361.         FW_Boolean styleIsHairline;
  362.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  363.         
  364.         if (renderVerb == FW_kFrame)
  365.         {
  366.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  367.             ::FrameOval(&plfmRect);
  368.         }
  369.         else
  370.         {
  371.             switch (ink->GetTransferMode())
  372.             {
  373.                 case FW_kErase:
  374.                     ::EraseOval(&plfmRect);
  375.                     break;
  376.                     
  377.                 case FW_kInvert:
  378.                     ::InvertOval(&plfmRect);
  379.                     break;
  380.                     
  381.                 default:
  382.                     ::PaintOval(&plfmRect);            
  383.             }
  384.         }
  385.     #endif
  386.     }
  387.     FW_SOM_CATCH
  388. }
  389.                             
  390. //----------------------------------------------------------------------------------------
  391. //    FW_PrivRenderRoundRect
  392. //----------------------------------------------------------------------------------------
  393.  
  394. void SL_API    FW_PrivRenderRoundRect(Environment* ev,
  395.                                     FW_SGraphicContext&     gc,
  396.                                     const FW_SRect&     rect,
  397.                                     const FW_SPoint&     ovalSize,
  398.                                     FW_ERenderVerbs     renderVerb,
  399.                                     FW_HInk             ink,
  400.                                     FW_HStyle             style)
  401. {
  402.     FW_RENDER_PROLOG
  403.     FW_CHECK_RENDER_VERB
  404.     FW_CHECK_INK
  405.     FW_CHECK_STYLE
  406.  
  407.     FW_SOM_TRY
  408.     {
  409.         FW_CPlatformRect plfmRect;
  410.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmRect);
  411.         FW_FailOnEvError(ev);
  412.             
  413.         FW_CPlatformPoint plfmOvalSize;
  414.         FW_PrivGC_LogicalToDeviceSize(ev, gc, ovalSize.x, ovalSize.y, plfmOvalSize);
  415.         FW_FailOnEvError(ev);
  416.     
  417. #ifdef FW_BUILD_WIN
  418.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  419.     
  420.         if (frameBrush)
  421.         {
  422.             HRGN hrgn = NULL;
  423.             // There is a bug in Windows. If the size of the round rect is smaller than 1,  we are dead.
  424.             if ((plfmRect.right - plfmRect.left <= 1) || (plfmRect.bottom - plfmRect.top <= 1))
  425.                 hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, 
  426.                                             plfmRect.right + 1, plfmRect.bottom + 1);
  427.             else
  428.                 hrgn = ::CreateRoundRectRgn(plfmRect.left, plfmRect.top, 
  429.                                             plfmRect.right + 1, plfmRect.bottom + 1, 
  430.                                             plfmOvalSize.x, plfmOvalSize.y);
  431.                                             
  432.             ::FrameRgn(*device, hrgn, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  433.             ::DeleteObject(hrgn);
  434.         }
  435.         else
  436.         {
  437.             if (renderVerb == FW_kFill)
  438.             {
  439.                 plfmRect.right++;
  440.                 plfmRect.bottom++;
  441.             }
  442.         
  443.             ::RoundRect(*device, 
  444.                         plfmRect.left, plfmRect.top, 
  445.                         plfmRect.right, plfmRect.bottom,
  446.                         plfmOvalSize.x, plfmOvalSize.y);
  447.         }
  448. #endif
  449. #ifdef FW_BUILD_MAC
  450.         FW_Boolean styleIsDash;
  451.         FW_Boolean styleIsHairline;
  452.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  453.         
  454.         if (renderVerb == FW_kFrame)
  455.         {
  456.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  457.             ::FrameRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  458.         }
  459.         else
  460.         {
  461.             switch (ink->GetTransferMode())
  462.             {
  463.                 case FW_kErase:
  464.                     ::EraseRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  465.                     break;
  466.                 case FW_kInvert:
  467.                     ::InvertRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  468.                     break;
  469.                 default:
  470.                     ::PaintRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);            
  471.             }
  472.         }
  473. #endif
  474.     }
  475.     FW_SOM_CATCH
  476. }
  477.                             
  478. //----------------------------------------------------------------------------------------
  479. //    FW_PrivRenderRoundRect
  480. //----------------------------------------------------------------------------------------
  481.  
  482. void SL_API    FW_PrivRenderArc(Environment* ev,
  483.                             FW_SGraphicContext&     gc,
  484.                             const FW_SRect&         rect, 
  485.                             short                     startAngle, 
  486.                             short                     arcAngle,
  487.                             FW_ERenderVerbs         renderVerb,
  488.                             FW_HInk                 ink,
  489.                             FW_HStyle                 style)
  490. {    
  491.     FW_RENDER_PROLOG
  492.     FW_CHECK_RENDER_VERB
  493.     FW_CHECK_INK
  494.     FW_CHECK_STYLE
  495.     
  496.     FW_SOM_TRY
  497.     {
  498.         FW_CPlatformRect arcRect;
  499.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, arcRect);
  500.         FW_FailOnEvError(ev);
  501.  
  502. #ifdef FW_BUILD_WIN    
  503.         short angle1 = startAngle;
  504.         
  505.         // Normalize the start angle
  506.         angle1 = angle1 % 360;
  507.         if (angle1 < 0)
  508.             angle1 += 360;
  509.             
  510.         // Compute and normalize the end angle
  511.         short angle2 = angle1 + arcAngle;
  512.         if (arcAngle < 0)
  513.         {
  514.             short temp = angle1;
  515.             angle1 = angle2;
  516.             angle2 = temp;
  517.         }
  518.     
  519.         FW_CPlatformPoint endPoint, startPoint;
  520.         FW_PrivCalcArcPoints(arcRect, angle1, endPoint);        // on Windows, arc and pie are drawn counterclockwise
  521.         FW_PrivCalcArcPoints(arcRect, angle2, startPoint);
  522.     
  523.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  524.     
  525.         if (renderVerb == FW_kFrame)
  526.         {
  527.             if(frameBrush)
  528.             {
  529.                 FW_CRect r = arcRect;
  530.                 ODRgnHandle rgnHandle = ::FW_CreateArcRegion(r, startAngle, arcAngle);
  531.                 ::FrameRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  532.                 ::FW_DisposeRegion(rgnHandle);
  533.             }
  534.             else
  535.             {
  536.                 ::Arc(*device, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  537.                     startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  538.             }
  539.         }
  540.         else
  541.         {
  542.             arcRect.right++;
  543.             arcRect.bottom++;
  544.             ::Pie(*device, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  545.                     startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  546.         }
  547. #endif
  548. #ifdef FW_BUILD_MAC
  549.         FW_Boolean styleIsDash;
  550.         FW_Boolean styleIsHairline;
  551.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);
  552.         
  553.         if (renderVerb == FW_kFrame)
  554.         {
  555.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  556.             ::FrameArc(&arcRect, startAngle, arcAngle);
  557.         }
  558.         else
  559.         {
  560.             switch (ink->GetTransferMode())
  561.             {
  562.                 case FW_kErase:
  563.                     ::EraseArc(&arcRect, startAngle, arcAngle);
  564.                     break;
  565.                 case FW_kInvert:
  566.                     ::InvertArc(&arcRect, startAngle, arcAngle);
  567.                     break;
  568.                 default:
  569.                     ::PaintArc(&arcRect, startAngle, arcAngle);            
  570.             }
  571.         }
  572. #endif
  573.     }
  574.     FW_SOM_CATCH
  575. }
  576.  
  577. //----------------------------------------------------------------------------------------
  578. //     FW_RenderLine
  579. //----------------------------------------------------------------------------------------
  580.  
  581. void SL_API    FW_PrivRenderLine(Environment* ev,
  582.                                 FW_SGraphicContext&     gc,
  583.                                 const FW_SPoint&     start, 
  584.                                 const FW_SPoint&     end,
  585.                                 FW_ERenderVerbs     renderVerb,
  586.                                 FW_HInk             ink,
  587.                                 FW_HStyle             style)
  588. {
  589.     FW_RENDER_PROLOG
  590.     FW_CHECK_RENDER_VERB
  591.     FW_CHECK_INK
  592.     FW_CHECK_STYLE
  593.     
  594.     FW_SOM_TRY
  595.     {
  596.         FW_CPlatformPoint plfmStart;
  597.         FW_PrivGC_LogicalToDevicePoint(ev, gc, start, plfmStart);
  598.         FW_FailOnEvError(ev);
  599.  
  600.     
  601.         FW_CPlatformPoint plfmEnd;
  602.         FW_PrivGC_LogicalToDevicePoint(ev, gc, end, plfmEnd);
  603.         FW_FailOnEvError(ev);
  604.  
  605. #ifdef FW_BUILD_WIN
  606.         HDC hDC = device->GetPlatformCanvas();
  607.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, FW_kFrame);
  608.         
  609.         if (frameBrush)
  610.         {
  611.             int penSizeX = device->fPenSize.x;
  612.             int penHalfX = penSizeX / 2;
  613.             int penSizeY = device->fPenSize.y;
  614.             int penHalfY = penSizeY / 2;
  615.             if (plfmStart.x == plfmEnd.x)
  616.             {
  617.                 device->fGDIBrush.SelectObject(hDC);
  618.                 ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, penSizeX, plfmEnd.y - plfmStart.y, PATCOPY);
  619.             }
  620.             else if (plfmStart.y == plfmEnd.y)
  621.             {
  622.                 device->fGDIBrush.SelectObject(hDC);
  623.                 ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, plfmEnd.x - plfmStart.x, penSizeY, PATCOPY);
  624.             }
  625.             else
  626.             {
  627.                 HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(plfmStart), FW_CPoint(plfmEnd), FW_CPoint(device->fPenSize));        
  628.                 ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  629.                 ::DeleteObject(hRgn);
  630.             }
  631.         }
  632.         else
  633.         {
  634.             ::MoveToEx(hDC, plfmStart.x, plfmStart.y, NULL);
  635.             ::LineTo(hDC, plfmEnd.x, plfmEnd.y);
  636.         }
  637. #endif
  638. #ifdef FW_BUILD_MAC
  639.         FW_Boolean styleIsDash;
  640.         FW_Boolean styleIsHairline;
  641.         MacSelectInkAndStyle(device,
  642.             FW_kLineShape,
  643.             FW_kFrame,                        // We never use FW_kFill for lines
  644.             ink,
  645.             style,
  646.             styleIsDash,
  647.             styleIsHairline);    
  648.  
  649.         short halfPenh = FW_QDGlobals.thePort->pnSize.h / 2;
  650.         short halfPenv = FW_QDGlobals.thePort->pnSize.v / 2;
  651.         
  652.         ::MoveTo(plfmStart.h - halfPenh, plfmStart.v - halfPenv);
  653.         
  654.         {
  655.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  656.             
  657.             if (styleIsDash)
  658.             {
  659.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  660.                 draw.LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  661.             }
  662.             else
  663.             {
  664.                 ::LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  665.             }
  666.         }
  667. #endif
  668.     }
  669.     FW_SOM_CATCH
  670. }
  671.  
  672. //----------------------------------------------------------------------------------------
  673. //    FW_PrivRenderRegion
  674. //----------------------------------------------------------------------------------------
  675.  
  676. void SL_API    FW_PrivRenderRegion(Environment* ev,
  677.                                 FW_SGraphicContext&     gc,
  678.                                 ODShape*                 odShape,
  679.                                 FW_ERenderVerbs         renderVerb,
  680.                                 FW_HInk                 ink,
  681.                                 FW_HStyle                 style)
  682. {
  683.     FW_RENDER_PROLOG
  684.     FW_CHECK_RENDER_VERB
  685.     FW_CHECK_INK
  686.     FW_CHECK_STYLE
  687.     
  688.     FW_SOM_TRY
  689.     {
  690.         ODShape* deviceShape = FW_PrivGC_LogicalToDeviceShape(ev, gc, odShape);
  691.         FW_FailOnEvError(ev);
  692.         
  693.         ODRgnHandle rgnHandle = ::FW_GetShapeRegion(ev, deviceShape);
  694.         FW_ASSERT(rgnHandle != NULL);
  695.  
  696. #ifdef FW_BUILD_WIN
  697.         FW_ERenderVerbs localVerb = renderVerb == FW_kFrame ? FW_kFill : renderVerb;
  698.         device->SelectInkAndStyle(ink, style, FW_kGeometricShapeWithInvert, localVerb);
  699.     
  700.         switch (renderVerb)
  701.         {
  702.             case FW_kFrame:
  703.                 ::FrameRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  704.                 break;
  705.     
  706.             case FW_kFill:
  707.                 if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite || ink->GetTransferMode() == FW_kSystemHilite)
  708.                     ::InvertRgn(*device, rgnHandle);
  709.                 else
  710.                     ::FillRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device));
  711.                 break;
  712.         }
  713. #endif
  714. #ifdef FW_BUILD_MAC
  715.         FW_Boolean styleIsDash;
  716.         FW_Boolean styleIsHairline;
  717.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);        
  718.         
  719.         if (renderVerb == FW_kFrame)
  720.         {
  721.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  722.             ::FrameRgn(rgnHandle);
  723.         }
  724.         else
  725.         {
  726.             switch (ink->GetTransferMode())
  727.             {
  728.                 case FW_kErase:
  729.                     ::EraseRgn(rgnHandle);
  730.                     break;
  731.                 case FW_kInvert:
  732.                     ::InvertRgn(rgnHandle);
  733.                     break;
  734.                 default:
  735.                     ::PaintRgn(rgnHandle);            
  736.             }
  737.         }
  738. #endif
  739.         deviceShape->Release(ev);
  740.     }
  741.     FW_SOM_CATCH
  742. }
  743.  
  744. //----------------------------------------------------------------------------------------
  745. //    FW_PrivRenderPolygon
  746. //----------------------------------------------------------------------------------------
  747.  
  748. void SL_API    FW_PrivRenderPolygon(Environment* ev,
  749.                                 FW_SGraphicContext&     gc,
  750.                                 FW_HPolygon             polygon,
  751.                                 FW_ERenderVerbs         renderVerb,
  752.                                 FW_Boolean                 autoCloseFrame,
  753.                                 FW_HInk                 ink,
  754.                                 FW_HStyle                 style)
  755. {
  756.     FW_RENDER_PROLOG
  757.     FW_CHECK_RENDER_VERB
  758.     FW_CHECK_INK
  759.     FW_CHECK_STYLE
  760.     
  761.     FW_SOM_TRY
  762.     {
  763.         long count = polygon->GetCount();
  764.         const FW_SPoint* points = polygon->GetPoints();
  765.  
  766. #ifdef FW_BUILD_WIN
  767.         // Convert points to platform points
  768.         unsigned long plfmCount = count;
  769.         FW_Boolean needClose = FALSE;
  770.         if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  771.         {
  772.             ++ plfmCount;
  773.             needClose = TRUE;
  774.         }
  775.         
  776.         FW_CPlatformPoint* plfmPoints = new FW_CPlatformPoint[plfmCount];
  777.         for(long i = 0; i < count; i ++)
  778.             FW_PrivGC_LogicalToDevicePoint(gc, points[i], plfmPoints[i]);
  779.     
  780.         if(needClose)
  781.             plfmPoints[plfmCount - 1] = plfmPoints[0];
  782.     
  783.         // Prepare the graphics device
  784.         FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  785.     
  786.         int penSizeX = device->fPenSize.x;
  787.         int penHalfX = penSizeX / 2;
  788.         int penSizeY = device->fPenSize.y;
  789.         int penHalfY = penSizeY / 2;
  790.         
  791.         HDC hDC = *device;
  792.     
  793.         // Render the polygon
  794.         switch (renderVerb)
  795.         {
  796.             case FW_kFrame:
  797.                 if(frameBrush)
  798.                 {
  799.                     // Doing it like this is way, way faster than creating a polygon
  800.                     // region for the whole thing and framing it
  801.                     FW_CPlatformPoint pt0, pt1;
  802.                     BOOL bBrushSelected = FALSE;
  803.     
  804.                     for(unsigned long p = 0; p < plfmCount - 1; p ++)
  805.                     {
  806.                         pt0 = plfmPoints[p];
  807.                         pt1 = plfmPoints[p + 1];
  808.                         
  809.                         if (pt0.x == pt1.x)
  810.                         {
  811.                             if (!bBrushSelected)
  812.                             {
  813.                                 device->fGDIBrush.SelectObject(hDC);
  814.                                 bBrushSelected = TRUE;
  815.                             }
  816.     
  817.                             ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, penSizeX, pt1.y - pt0.y, PATCOPY);
  818.                         }
  819.                         else if (pt0.y == pt1.y)
  820.                         {
  821.                             if (!bBrushSelected)
  822.                             {
  823.                                 device->fGDIBrush.SelectObject(hDC);
  824.                                 bBrushSelected = TRUE;
  825.                             }
  826.     
  827.                             ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, pt1.x - pt0.x, penSizeY, PATCOPY);
  828.                         }
  829.                         else
  830.                         {
  831.                             HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(pt0), FW_CPoint(pt1), FW_CPoint(device->fPenSize));
  832.                             ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  833.                             ::DeleteObject(hRgn);
  834.                         }
  835.                     }
  836.                 }
  837.                 else
  838.                 {
  839.                     ::Polyline(hDC, plfmPoints, plfmCount);
  840.                 }
  841.                 break;
  842.     
  843.             case FW_kFill:
  844.                 ::Polygon(hDC, plfmPoints, plfmCount);
  845.                 break;
  846.         }
  847.         
  848.         delete[] plfmPoints;
  849. #endif
  850. #ifdef FW_BUILD_MAC
  851.         // Create a polygon
  852.         GrafPtr savePort;
  853.         ::GetPort(&savePort);
  854.         ::SetPort(FW_gScratchPort);
  855.         PolyHandle polyHandle = ::OpenPoly();
  856.         
  857.         if(polyHandle == NULL)
  858.         {
  859.             ::SetPort(savePort);
  860.             FW_Failure(FW_xMemoryExhausted);
  861.         }
  862.     
  863.         FW_CPlatformPoint plfmPoint;
  864.         FW_PrivGC_LogicalToDevicePoint(ev, gc, points[0], plfmPoint);
  865.         FW_FailOnEvError(ev);
  866.         
  867.         ::MoveTo(plfmPoint.h, plfmPoint.v);
  868.     
  869.         for(long i = 1; i < count; i ++)
  870.         {
  871.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[i], plfmPoint);
  872.             FW_FailOnEvError(ev);
  873.             
  874.             ::LineTo(plfmPoint.h, plfmPoint.v);
  875.         }
  876.         
  877.         // Close the polygon if needed
  878.         if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  879.         {
  880.             FW_PrivGC_LogicalToDevicePoint(ev, gc, points[0], plfmPoint);
  881.             FW_FailOnEvError(ev);
  882.             
  883.             ::LineTo(plfmPoint.h, plfmPoint.v);
  884.         }
  885.     
  886.         ::ClosePoly();
  887.         ::SetPort(savePort);
  888.     
  889.         // Prepare the grafport
  890.         FW_Boolean styleIsDash;
  891.         FW_Boolean styleIsHairline;
  892.         MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style, styleIsDash, styleIsHairline);        
  893.         
  894.         // Render the polygon
  895.         if (renderVerb == FW_kFrame)
  896.         {
  897.             FW_PrivSelectHairline hairSelector(styleIsHairline && !device->GetODCanvas()->IsDynamic(ev));
  898.             
  899.             if (styleIsDash)
  900.             {
  901.                 FW_CPrivMacDashDraw draw(style->GetDashStyle());
  902.                 short nPolyCount = ((*polyHandle)->polySize - 10) / sizeof(Point);
  903.                 ::MoveTo((*polyHandle)->polyPoints[0].h, (*polyHandle)->polyPoints[0].v);
  904.                 for (short n = 1; n < nPolyCount; ++ n)
  905.                     draw.LineTo((*polyHandle)->polyPoints[n].h, (*polyHandle)->polyPoints[n].v);
  906.             }
  907.             else
  908.             {
  909.                 ::FramePoly(polyHandle);
  910.             }
  911.         }
  912.         else
  913.         {
  914.             switch (ink->GetTransferMode())
  915.             {
  916.                 case FW_kErase:
  917.                     ::ErasePoly(polyHandle);
  918.                     break;
  919.                 case FW_kInvert:
  920.                     ::InvertPoly(polyHandle);
  921.                     break;
  922.                 default:
  923.                     ::PaintPoly(polyHandle);            
  924.             }
  925.         }
  926.     
  927.         ::KillPoly(polyHandle);
  928. #endif
  929.     }
  930.     FW_SOM_CATCH
  931. }                                            
  932.  
  933. //----------------------------------------------------------------------------------------
  934. //    FW_PrivRenderTextString
  935. //----------------------------------------------------------------------------------------
  936.  
  937. void SL_API    FW_PrivRenderTextString(Environment* ev,
  938.                                     FW_SGraphicContext&    gc,
  939.                                     FW_HString            string,
  940.                                     const FW_SPoint&    position,
  941.                                     FW_TextAlignment    textAlignment,
  942.                                     FW_ERenderVerbs        renderVerb,
  943.                                     FW_HInk             ink,
  944.                                     FW_HFont             font)
  945. {
  946.     FW_SOM_TRY
  947.     {
  948.         FW_CPrivTextBuffer buffer(string);
  949.         PrivRenderTextBuffer(ev, gc, &buffer, position, textAlignment, renderVerb, ink, font);
  950.     }
  951.     FW_SOM_CATCH
  952. }
  953.                                 
  954. //----------------------------------------------------------------------------------------
  955. //    FW_PrivRenderTextReader
  956. //----------------------------------------------------------------------------------------
  957.  
  958. void SL_API    FW_PrivRenderTextReader(Environment* ev,
  959.                                     FW_SGraphicContext&    gc,
  960.                                     FW_HTextReader        reader,
  961.                                     const FW_SPoint&    position,
  962.                                     FW_TextAlignment    textAlignment,
  963.                                     FW_ERenderVerbs        renderVerb,
  964.                                     FW_HInk                ink,
  965.                                     FW_HFont            font)
  966. {
  967.     FW_SOM_TRY
  968.     {
  969.         FW_CPrivTextBuffer buffer(reader);
  970.         PrivRenderTextBuffer(ev, gc, &buffer, position, textAlignment, renderVerb, ink, font);
  971.     }
  972.     FW_SOM_CATCH
  973. }
  974.  
  975. //----------------------------------------------------------------------------------------
  976. //    PrivRenderTextBuffer
  977. //----------------------------------------------------------------------------------------
  978.  
  979. static void    PrivRenderTextBuffer(Environment* ev,
  980.                                 FW_SGraphicContext&    gc,
  981.                                 FW_CPrivTextBuffer*    textBuffer,
  982.                                 const FW_SPoint&    position,
  983.                                 FW_TextAlignment    textAlignment,
  984.                                 FW_ERenderVerbs        renderVerb,
  985.                                 FW_HInk                ink,
  986.                                 FW_HFont            font)
  987. {    
  988.     FW_RENDER_PROLOG
  989.     FW_CHECK_RENDER_VERB
  990.     FW_CHECK_FONT
  991.     FW_CHECK_INK
  992.  
  993.     FW_ASSERT(textBuffer != NULL);
  994.     if (textBuffer->IsDone())    // No text to draw
  995.         return;
  996.  
  997.     FW_CPlatformPoint plfmPos;
  998.     FW_PrivGC_LogicalToDevicePoint(ev, gc, position, plfmPos);
  999.     FW_FailOnEvError(ev);
  1000.  
  1001.     // ----- RenderText only cares about the first line -----    
  1002.     const char* text;
  1003.     FW_ByteCount count;
  1004.     textBuffer->GetCurrentLine(text, count);
  1005.  
  1006. #ifdef FW_BUILD_WIN
  1007.     device->SelectInkAndFont(ink, font);
  1008.         
  1009.     // ----- Set the text alignment - always use TA_UPDATECP (see below)
  1010.     TEXTMETRIC tm;
  1011.     UINT newAlign = TA_UPDATECP;
  1012.     
  1013.     switch (textAlignment & FW_kPrivTextAlignVertAlignMask)
  1014.     {
  1015.         case FW_kTextAlignTop:
  1016.             newAlign |= TA_TOP;
  1017.             break;
  1018.             
  1019.         case FW_kTextAlignBottom:
  1020.             newAlign |= TA_BOTTOM;
  1021.             break;
  1022.             
  1023.         case FW_kTextAlignVCenter:
  1024.             ::GetTextMetrics(*device, &tm);
  1025.             plfmPos.y -= (tm.tmHeight - tm.tmInternalLeading) / 2;
  1026.             break;
  1027.             
  1028.         case FW_kTextAlignBaseLine:
  1029.             newAlign |= TA_BASELINE;
  1030.             break;
  1031.     }
  1032.  
  1033.     switch (textAlignment & FW_kPrivTextAlignHorzAlignMask)
  1034.     {
  1035.         case FW_kTextAlignLeft:
  1036.             newAlign |= TA_LEFT;
  1037.             break;
  1038.             
  1039.         case FW_kTextAlignRight:
  1040.             newAlign |= TA_RIGHT;
  1041.             break;
  1042.             
  1043.         case FW_kTextAlignHCenter:
  1044.             newAlign |= TA_CENTER;
  1045.             break;
  1046.     }
  1047.     
  1048.     // It is necessary to use TA_UPDATECP because the next call may want to use
  1049.     //    FW_kTextAlignUseCurrentPos.  However, TA_UPDATECP also means "use CP", so
  1050.     //    if this is not what the user wants, we should move to the right pos first
  1051.  
  1052.     if((textAlignment & FW_kPrivTextAlignUsePosMask) == FW_kTextAlignUseSpecifiedPos)
  1053.         ::MoveToEx(*device, plfmPos.x, plfmPos.y, NULL);
  1054.  
  1055.     ::SetTextAlign(*device, newAlign);
  1056.     ::TextOut(*device,
  1057.             0, 0,        // we use TA_UPDATECP, remember?
  1058.             text,
  1059.             count);
  1060.             
  1061.     ::SetTextAlign(*device, TA_LEFT | TA_TOP | TA_NOUPDATECP);        // restore the flags
  1062. #endif
  1063. #ifdef FW_BUILD_MAC
  1064.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1065.     device->SelectFont(font, TRUE);        // SetInGrafPort called by SelectFont
  1066.  
  1067.     // ----- The Mac only knows to draw text from the baseline, so we need to do some adjustment
  1068.     FW_CPlatformPoint plfmTextPos = MacCalcTextPosition(device, count, text, textAlignment, plfmPos);
  1069.     
  1070.     // ----- Draw the text
  1071.     ::MoveTo(plfmTextPos.h, plfmTextPos.v);
  1072.     ::DrawText(text, 0, count);
  1073.  
  1074.     // ----- StrikeOut if necessary
  1075.     if ((font->GetFontStyle() & FW_kStrikeOut) != 0)
  1076.         MacStrikeOut(device, plfmTextPos.h, plfmTextPos.v);
  1077. #endif
  1078. }
  1079.                                 
  1080. //----------------------------------------------------------------------------------------
  1081. //    FW_PrivRenderTextBoxString
  1082. //----------------------------------------------------------------------------------------
  1083.  
  1084. FW_Fixed SL_API FW_PrivRenderTextBoxString(Environment* ev,
  1085.                                             FW_SGraphicContext&    gc,
  1086.                                             FW_HString            string, 
  1087.                                             const FW_SRect&        box,
  1088.                                             FW_TextBoxOptions    options,
  1089.                                             FW_ERenderVerbs        renderVerb,
  1090.                                             FW_HInk                ink,
  1091.                                             FW_HFont            font)
  1092. {
  1093.     FW_SOM_TRY
  1094.     {
  1095.         FW_CPrivTextBuffer buffer(string);
  1096.         return PrivRenderTextBoxBuffer(ev, gc, &buffer, box, options, renderVerb, ink, font);
  1097.     }
  1098.     FW_SOM_CATCH
  1099.     return FW_kFixed0;
  1100. }
  1101.  
  1102. //----------------------------------------------------------------------------------------
  1103. //    FW_PrivRenderTextBoxReader
  1104. //----------------------------------------------------------------------------------------
  1105.  
  1106. FW_Fixed SL_API FW_PrivRenderTextBoxReader(Environment* ev,
  1107.                                             FW_SGraphicContext&    gc,
  1108.                                             FW_HTextReader        reader, 
  1109.                                             const FW_SRect&        box,
  1110.                                             FW_TextBoxOptions    options,
  1111.                                             FW_ERenderVerbs        renderVerb,
  1112.                                             FW_HInk                ink,
  1113.                                             FW_HFont            font)
  1114. {
  1115.     FW_SOM_TRY
  1116.     {
  1117.         FW_CPrivTextBuffer buffer(reader);
  1118.         return PrivRenderTextBoxBuffer(ev, gc, &buffer, box, options, renderVerb, ink, font);
  1119.     }
  1120.     FW_SOM_CATCH
  1121.     return FW_kFixed0;
  1122. }
  1123.  
  1124. //----------------------------------------------------------------------------------------
  1125. //    PrivRenderTextBoxBuffer
  1126. //----------------------------------------------------------------------------------------
  1127.  
  1128. static FW_Fixed    PrivRenderTextBoxBuffer(Environment* ev,
  1129.                                         FW_SGraphicContext& gc,
  1130.                                         FW_CPrivTextBuffer* textBuffer, 
  1131.                                         const FW_SRect& box,
  1132.                                         FW_TextBoxOptions options,
  1133.                                         FW_ERenderVerbs renderVerb,
  1134.                                         FW_HInk ink,
  1135.                                         FW_HFont font)
  1136. {
  1137.     FW_RENDER_PROLOG
  1138.     FW_CHECK_FONT
  1139.     FW_CHECK_INK
  1140.     
  1141.     FW_ASSERT(textBuffer != NULL);
  1142.     if (renderVerb == FW_kNoRendering || textBuffer->IsDone())
  1143.         return box.top;
  1144.         
  1145.     FW_CPlatformRect plfmBox;
  1146.     FW_PrivGC_LogicalToDeviceRect(ev, gc, box, plfmBox);
  1147.     FW_FailOnEvError(ev);
  1148.  
  1149. #ifdef FW_BUILD_WIN
  1150.     device->SelectInkAndFont(ink, font);
  1151. #endif
  1152. #ifdef FW_BUILD_MAC
  1153.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1154.     device->SelectFont(font, TRUE);
  1155. #endif
  1156.  
  1157.     FW_PlatformCoordinate bottom = PrivTextBox(ev, device, textBuffer, plfmBox, options, TRUE, font);
  1158.  
  1159.     if (bottom != plfmBox.bottom)
  1160.     {
  1161.         FW_CPlatformPoint pt(0, bottom);
  1162.         FW_CPoint cPt;
  1163.         FW_PrivGC_DeviceToLogicalPoint(ev, gc, pt, cPt);
  1164.         FW_FailOnEvError(ev);
  1165.         return cPt.y;
  1166.     }
  1167.     
  1168.     return box.bottom;
  1169. }
  1170.                                 
  1171. //----------------------------------------------------------------------------------------
  1172. //    FW_PrivTextBoxSizeString
  1173. //----------------------------------------------------------------------------------------
  1174.  
  1175. void SL_API FW_PrivTextBoxSizeString(Environment* ev,
  1176.                                     FW_SGraphicContext&    gc,
  1177.                                     FW_HString            string, 
  1178.                                     FW_HFont            font,
  1179.                                     FW_TextBoxOptions    options,
  1180.                                     FW_SRect&            textBox)
  1181. {
  1182.     FW_SOM_TRY
  1183.     {
  1184.         FW_CPrivTextBuffer buffer(string);
  1185.         PrivTextBoxSizeBuffer(ev, gc, &buffer, font, options, textBox);
  1186.     }
  1187.     FW_SOM_CATCH
  1188. }
  1189.  
  1190. //----------------------------------------------------------------------------------------
  1191. //    FW_PrivTextBoxSizeReader
  1192. //----------------------------------------------------------------------------------------
  1193.  
  1194. void SL_API FW_PrivTextBoxSizeReader(Environment* ev,
  1195.                                     FW_SGraphicContext&    gc,
  1196.                                     FW_HTextReader        reader, 
  1197.                                     FW_HFont            font,
  1198.                                     FW_TextBoxOptions    options,
  1199.                                     FW_SRect&            textBox)
  1200. {
  1201.     FW_SOM_TRY
  1202.     {
  1203.         FW_CPrivTextBuffer buffer(reader);
  1204.         PrivTextBoxSizeBuffer(ev, gc, &buffer, font, options, textBox);
  1205.     }
  1206.     FW_SOM_CATCH
  1207. }
  1208.  
  1209. //----------------------------------------------------------------------------------------
  1210. //    PrivTextBoxSizeBuffer
  1211. //----------------------------------------------------------------------------------------
  1212.  
  1213. static void PrivTextBoxSizeBuffer(Environment* ev,
  1214.                                     FW_SGraphicContext& gc,
  1215.                                     FW_CPrivTextBuffer *textBuffer, 
  1216.                                     FW_HFont font,
  1217.                                     FW_TextBoxOptions options,
  1218.                                     FW_SRect& textBox)
  1219. {
  1220.     FW_RENDER_PROLOG
  1221.     FW_CHECK_FONT
  1222.     
  1223.     FW_ASSERT((const void*)font != NULL);
  1224.     FW_ASSERT(textBuffer != NULL);
  1225.  
  1226.     FW_CPlatformRect plfmBox;
  1227.     FW_PrivGC_LogicalToDeviceRect(ev, gc, textBox, plfmBox);
  1228.     FW_FailOnEvError(ev);
  1229.  
  1230.     if (textBuffer->IsDone())
  1231.     {
  1232.         plfmBox.bottom = plfmBox.top;
  1233.     }
  1234.     else
  1235.     {
  1236.         device->SelectFont(font, TRUE);                    // TRUE: scale
  1237.         plfmBox.bottom = PrivTextBox(ev, device, textBuffer, plfmBox, options, FALSE, font);    // FALSE: don't draw
  1238.     }
  1239.  
  1240.     FW_CPoint textBoxSize;
  1241.     FW_PrivGC_DeviceToLogicalSize(ev, gc, plfmBox.right, plfmBox.bottom, textBoxSize);
  1242.     FW_FailOnEvError(ev);
  1243.     
  1244.     textBox.right    = textBox.left + textBoxSize.x;
  1245.     textBox.bottom    = textBox.top  + textBoxSize.y;
  1246. }
  1247.  
  1248. //----------------------------------------------------------------------------------------
  1249. //    FW_PrivCalcTextExtentString
  1250. //----------------------------------------------------------------------------------------
  1251.  
  1252. void SL_API FW_PrivCalcTextExtentString(Environment* ev,
  1253.                                         FW_SGraphicContext&        gc,
  1254.                                         FW_HString                 string,
  1255.                                         FW_HFont                 font,
  1256.                                         FW_SPoint&                 textExtent)
  1257. {
  1258.     FW_SOM_TRY
  1259.     {
  1260.         FW_CPrivTextBuffer buffer(string);
  1261.         PrivTextExtentBuffer(ev, gc, &buffer, font, textExtent);
  1262.     }
  1263.     FW_SOM_CATCH
  1264. }
  1265.  
  1266. //----------------------------------------------------------------------------------------
  1267. //    FW_PrivCalcTextExtentReader
  1268. //----------------------------------------------------------------------------------------
  1269.  
  1270. void SL_API FW_PrivCalcTextExtentReader(Environment* ev,
  1271.                                         FW_SGraphicContext&    gc,
  1272.                                         FW_HTextReader        reader,
  1273.                                         FW_HFont            font, 
  1274.                                         FW_SPoint&            textExtent)
  1275. {
  1276.     FW_SOM_TRY
  1277.     {
  1278.         FW_CPrivTextBuffer buffer(reader);
  1279.         PrivTextExtentBuffer(ev, gc, &buffer, font, textExtent);
  1280.     }
  1281.     FW_SOM_CATCH
  1282. }
  1283.  
  1284. //----------------------------------------------------------------------------------------
  1285. //    PrivTextExtentBuffer
  1286. //----------------------------------------------------------------------------------------
  1287.  
  1288. static void PrivTextExtentBuffer(Environment* ev,
  1289.                                 FW_SGraphicContext& gc,
  1290.                                 FW_CPrivTextBuffer* textBuffer,
  1291.                                 FW_HFont font, 
  1292.                                 FW_SPoint& textExtent)
  1293. {
  1294.     FW_RENDER_PROLOG
  1295.     FW_CHECK_FONT
  1296.  
  1297.     if (textBuffer->IsDone())
  1298.     {
  1299.         textExtent = FW_kZeroPoint;
  1300.         return;
  1301.     }
  1302.     
  1303.     device->SelectFont(font, TRUE);
  1304.     
  1305.     // ----- TextExtent only cares about the first line -----    
  1306.     FW_ByteCount count;
  1307.     const char* text;
  1308.     textBuffer->GetCurrentLine(text, count);
  1309.  
  1310. #ifdef FW_BUILD_WIN
  1311.     SIZE size;
  1312.     ::GetTextExtentPoint32(*device, text, count, &size);
  1313.     FW_CPlatformPoint plfmExtent(size.cx, size.cy);
  1314. #endif
  1315. #ifdef FW_BUILD_MAC
  1316.     FontInfo fi;
  1317.     ::GetFontInfo(&fi);
  1318.     
  1319.     FW_CPlatformPoint plfmExtent(
  1320.             ::TextWidth(text, 0, count),
  1321.             fi.ascent + fi.descent);
  1322. #endif
  1323.  
  1324.     FW_PrivGC_DeviceToLogicalSize(ev, gc, plfmExtent.X(), plfmExtent.Y(), textExtent);
  1325.     FW_FailOnEvError(ev);
  1326. }
  1327.  
  1328. //----------------------------------------------------------------------------------------
  1329. //    FW_PrivRenderPicture
  1330. //----------------------------------------------------------------------------------------
  1331.  
  1332. void SL_API    FW_PrivRenderPicture(Environment* ev,
  1333.                                 FW_SGraphicContext& gc,
  1334.                                 FW_HPicture picture,
  1335.                                 const FW_SRect& dstRect,
  1336.                                 FW_ERenderVerbs renderVerb)
  1337. {
  1338.     FW_RENDER_PROLOG
  1339.     FW_CHECK_RENDER_VERB
  1340.     
  1341.     FW_SOM_TRY
  1342.     {
  1343.         FW_ASSERT(picture != NULL);
  1344.         FW_PlatformPict pict = picture->GetPlatformPict();
  1345.         FW_CPlatformRect plfmRect;
  1346.         FW_PrivGC_LogicalToDeviceRect(ev, gc, dstRect, plfmRect);
  1347.         FW_FailOnEvError(ev);
  1348.     
  1349. #ifdef FW_BUILD_WIN
  1350.         ::PlayEnhMetaFile(*device, pict, &plfmRect);
  1351. #endif
  1352. #ifdef FW_BUILD_MAC
  1353.         ::DrawPicture(pict, &plfmRect);
  1354. #endif
  1355.     }
  1356.     FW_SOM_CATCH
  1357. }
  1358.  
  1359. //----------------------------------------------------------------------------------------
  1360. //    FW_PrivRenderBitmap
  1361. //----------------------------------------------------------------------------------------
  1362.  
  1363. void SL_API    FW_PrivRenderBitmap(Environment* ev,
  1364.                                 FW_SGraphicContext& gc,
  1365.                                 FW_HBitmap bitmap,
  1366.                                 const FW_SRect& srcRect,
  1367.                                 const FW_SRect& dstRect,
  1368.                                 FW_ERenderVerbs renderVerb,
  1369.                                 FW_HInk ink)
  1370. {
  1371.     FW_CHECK_RENDER_VERB
  1372.  
  1373.     // If erase, invert or hilite is used then simply erase/invert/hilite the dst Rectangle
  1374.     FW_TransferModes transferMode = ink->GetTransferMode();
  1375.     if (transferMode == FW_kErase || transferMode == FW_kInvert || transferMode == FW_kHilite || transferMode == FW_kSystemHilite)
  1376.     {
  1377.         FW_CStyle style(FW_kNormalStyle);
  1378.         FW_PrivRenderRect(ev, gc, dstRect, FW_kFill, ink, style);
  1379.         return;
  1380.     }
  1381.  
  1382.     FW_RENDER_PROLOG
  1383.  
  1384.     FW_ASSERT(bitmap != NULL);
  1385.     
  1386.     FW_SOM_TRY
  1387.     {
  1388.         // Convert source and destination rectangles
  1389.         FW_CPlatformRect plfmDstRect;
  1390.         FW_PrivGC_LogicalToDeviceRect(ev, gc, dstRect, plfmDstRect);
  1391.         FW_FailOnEvError(ev);
  1392.         
  1393.         FW_CPlatformRect plfmSrcRect = srcRect;    
  1394.         
  1395. #ifdef FW_BUILD_WIN
  1396.         HDC hDC = *device;
  1397.     
  1398.         ::SetTextColor(hDC, ink->GetForeColor());
  1399.         ::SetBkColor(hDC, ink->GetBackColor());
  1400.  
  1401.         HBITMAP plfmBitmap = bitmap->GetPlatformBitmap();
  1402.     
  1403.         HDC memoryDC = ::CreateCompatibleDC(hDC);
  1404.         HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, plfmBitmap);
  1405.     
  1406.         HPALETTE hPal = bitmap->GetPalette();
  1407.         HPALETTE hPalOld = NULL;
  1408.         if (hPal != NULL)
  1409.         {
  1410.             hPalOld = ::SelectPalette(hDC, hPal, FALSE);
  1411.             ::RealizePalette(hDC);
  1412.         }
  1413.     
  1414.         ::StretchBlt(hDC,
  1415.                     plfmDstRect.left,
  1416.                     plfmDstRect.top,
  1417.                     plfmDstRect.right - plfmDstRect.left,
  1418.                     plfmDstRect.bottom - plfmDstRect.top,
  1419.                     memoryDC,
  1420.                     plfmSrcRect.left, 
  1421.                     plfmSrcRect.top,
  1422.                     plfmSrcRect.right - plfmSrcRect.left,
  1423.                     plfmSrcRect.bottom - plfmSrcRect.top,
  1424.                     FW_PrivWinConvertRasterOp(ink->GetTransferMode()));
  1425.     
  1426.         if (hPalOld)
  1427.             ::SelectPalette(hDC, hPalOld, TRUE);
  1428.     
  1429.         ::SelectObject(memoryDC, oldBitmap);
  1430.         ::DeleteDC(memoryDC);
  1431. #endif
  1432. #ifdef FW_BUILD_MAC    
  1433.         device->SelectInk(ink, FW_kImageShape, FW_kFill);    // Never use FW_kFrame for bitmap
  1434.         device->SetInGrafPort();
  1435.  
  1436.         PixMapHandle pmh = bitmap->MacLockPixels();
  1437.         ::CopyBits((BitMap*)*pmh, &FW_QDGlobals.thePort->portBits, 
  1438.                     &plfmSrcRect, &plfmDstRect, 
  1439.                     FW_PrivMacGetMacTransferMode(ink->GetTransferMode()), NULL);
  1440.         bitmap->MacUnlockPixels();
  1441. #endif
  1442.     }
  1443.     FW_SOM_CATCH
  1444. }
  1445.  
  1446. //----------------------------------------------------------------------------------------
  1447. //    FW_PrivRenderIcon
  1448. //----------------------------------------------------------------------------------------
  1449.  
  1450. void SL_API    FW_PrivRenderIcon(Environment* ev,
  1451.                             FW_SGraphicContext& gc,
  1452.                               FW_HIcon icon,
  1453.                             const FW_SRect& rect,
  1454.                             FW_RenderIconTransform transform,
  1455.                             FW_RenderIconAlignment alignment,
  1456.                             FW_ERenderVerbs renderVerb)
  1457. {
  1458.     FW_RENDER_PROLOG
  1459.     FW_CHECK_RENDER_VERB
  1460.  
  1461.     FW_ASSERT(icon != NULL);
  1462.     
  1463.     FW_SOM_TRY
  1464.     {
  1465.         FW_PlatformIcon hIcon = icon->GetPlatformIcon();
  1466.     
  1467.         FW_PlatformRect plfmDstRect;
  1468.         FW_PrivGC_LogicalToDeviceRect(ev, gc, rect, plfmDstRect);
  1469.         FW_FailOnEvError(ev);
  1470.                 
  1471. #ifdef FW_BUILD_WIN
  1472.         FW_CPoint iconSize;
  1473.         icon->GetIconSize(iconSize);
  1474.         
  1475.         short xSize = iconSize.IntX(), ySize = iconSize.IntY();
  1476.         
  1477.         // Horizontal alignment
  1478.         if (alignment & FW_kIconAlignCenter)
  1479.         {
  1480.             plfmDstRect.left = (plfmDstRect.right + plfmDstRect.left - xSize) / 2;
  1481.             plfmDstRect.right = plfmDstRect.left + xSize;
  1482.         }
  1483.         else if (alignment & FW_kIconAlignLeft)
  1484.         {
  1485.             plfmDstRect.right = plfmDstRect.left + xSize;
  1486.         }
  1487.         else if (alignment & FW_kIconAlignRight)
  1488.         {
  1489.             plfmDstRect.left = plfmDstRect.right - xSize;
  1490.         }
  1491.                 
  1492.         // Vertical alignment
  1493.         if (alignment & FW_kIconAlignVCenter)
  1494.         {
  1495.             plfmDstRect.top = (plfmDstRect.bottom + plfmDstRect.top - ySize) / 2;
  1496.             plfmDstRect.bottom = plfmDstRect.top + ySize;
  1497.         }
  1498.         else if (alignment & FW_kIconAlignTop)
  1499.         {
  1500.             plfmDstRect.bottom = plfmDstRect.top + ySize;
  1501.         }
  1502.         else if (alignment & FW_kIconAlignBottom)
  1503.         {
  1504.             plfmDstRect.top = plfmDstRect.bottom - ySize;
  1505.         }
  1506.         
  1507.         // [HLX] Need to support tranform
  1508.         ::DrawIconEx(*device, plfmDstRect.left, plfmDstRect.top, hIcon,
  1509.             plfmDstRect.right - plfmDstRect.left,
  1510.             plfmDstRect.bottom - plfmDstRect.top,
  1511.             0, NULL, DI_NORMAL);
  1512. #endif
  1513.  
  1514. #ifdef FW_BUILD_MAC
  1515.         FW_PrivMacSetStdColors();        
  1516.         ::PlotIconSuite(&plfmDstRect, alignment, transform, hIcon);
  1517. #endif
  1518.     }
  1519.     FW_SOM_CATCH
  1520. }
  1521.  
  1522. //========================================================================================
  1523. // Local helpers
  1524. //========================================================================================
  1525.  
  1526. //----------------------------------------------------------------------------------------
  1527. //    PrivTextBox
  1528. //----------------------------------------------------------------------------------------
  1529.  
  1530. static FW_PlatformCoordinate     PrivTextBox(Environment* ev,
  1531.                                     FW_CPrivGraphicsDevice* device,
  1532.                                     FW_CPrivTextBuffer *textBuffer, 
  1533.                                     const FW_CPlatformRect& box,
  1534.                                     FW_TextBoxOptions options,
  1535.                                     FW_Boolean draw,
  1536.                                     FW_HFont font)
  1537. {
  1538. FW_UNUSED(ev);
  1539.  
  1540.     if (textBuffer->IsDone())
  1541.         return box.top;
  1542.  
  1543.     // ----- Check options for consistency
  1544.     FW_TextBoxOptions opt = options;
  1545.  
  1546.     if (!draw)
  1547.         opt &= ~FW_kTextBoxClipToBox;
  1548.     
  1549.     if ((opt & FW_kTextBoxSingleLine) != 0)
  1550.     {
  1551.         opt &= ~FW_kTextBoxWordWrap;
  1552.         opt &= ~FW_kTextBoxWordBreak;
  1553.     }
  1554.     
  1555.     if ((opt & FW_kTextBoxWordWrap) != 0)
  1556.     {
  1557.         opt &= ~FW_kTextBoxJustifyBottom;
  1558.         opt &= ~FW_kTextBoxJustifyVCenter;
  1559.     }
  1560.  
  1561.     FW_CharacterPosition segStart;        // start of the current string segment
  1562.     FW_CharacterCount segLen;            // its length (charcter count)
  1563.     FW_PlatformCoordinate actualWidth;    // its actual width (pixels)
  1564.     FW_PlatformCoordinate maxWidth = box.right - box.left;
  1565.  
  1566.     FW_Boolean bClip = (opt & FW_kTextBoxClipToBox) != 0;
  1567.  
  1568. #ifdef FW_BUILD_WIN
  1569.     // ----- Set the clipping region if we need to
  1570.     HDC hDC = device->GetPlatformCanvas();
  1571.     int savedDC = 0;
  1572.     if (bClip)
  1573.     {
  1574.         savedDC = ::SaveDC(hDC);
  1575.         ::IntersectClipRect(hDC, 
  1576.                             box.left, box.top, 
  1577.                             box.right, box.bottom);
  1578.     }
  1579.  
  1580.     // ----- Get the font height
  1581.     TEXTMETRIC textMetric;
  1582.     ::GetTextMetrics(hDC, &textMetric);
  1583.     FW_PlatformCoordinate fontHeight = textMetric.tmHeight + textMetric.tmExternalLeading;
  1584.  
  1585.     FW_PlatformCoordinate drawPosY = box.top;
  1586.     FW_PlatformCoordinate drawPosX = box.left;
  1587. #endif
  1588. #ifdef FW_BUILD_MAC
  1589.     // ----- Set the clipping region if we need to
  1590.     RgnHandle oldClipRgn = 0;
  1591.     if (bClip)
  1592.     {
  1593.         oldClipRgn = device->GetClip();
  1594.         device->IntersectClipRect(ev, box);
  1595.     }
  1596.  
  1597.     // ----- Get the font height -----
  1598.     FontInfo fi;
  1599.     ::GetFontInfo(&fi);
  1600.     FW_PlatformCoordinate fontHeight = fi.ascent + fi.descent + fi.leading;
  1601.  
  1602.     FW_PlatformCoordinate drawPosY = box.top + fi.ascent;
  1603.     FW_PlatformCoordinate drawPosX = box.left;
  1604.     
  1605.     FW_Boolean bIsStrikeOut = (font->GetFontStyle() & FW_kStrikeOut) != 0;
  1606. #endif
  1607.  
  1608.     // ----- Check vertical jusitficaiton
  1609.     switch (opt & FW_kPrivTextBoxVertJusificationMask)
  1610.     {
  1611.     case FW_kTextBoxJustifyVCenter:
  1612. #ifdef FW_BUILD_WIN
  1613.         drawPosY = (box.top + box.bottom - fontHeight) / 2;
  1614. #endif
  1615. #ifdef FW_BUILD_MAC
  1616.         drawPosY = (box.top + box.bottom + fi.ascent - fi.descent) / 2;
  1617. #endif
  1618.         break;
  1619.         
  1620.     case FW_kTextBoxJustifyBottom:
  1621.         drawPosY = box.bottom - fontHeight;
  1622.         break;
  1623.     }
  1624.  
  1625.     // ----- Draw string segments one by one
  1626.     FW_Boolean wordWrap = (opt & FW_kTextBoxWordWrap) != 0;
  1627.     FW_Boolean wordBreak = (opt & FW_kTextBoxWordBreak) != 0;
  1628.     FW_Boolean reachedBottom = FALSE;
  1629.     while (TRUE)
  1630.     {
  1631.         const char* line;
  1632.         FW_ByteCount lineLength;
  1633.         textBuffer->GetCurrentLine(line, lineLength);
  1634.         
  1635.         // ----- Draw the current segment
  1636.         FW_Boolean bCalledBefore = FALSE;
  1637.         while (!reachedBottom && FW_PrivGetStringSegment(*device, bCalledBefore,
  1638.             line, lineLength, segStart, segLen, maxWidth, actualWidth, wordWrap, wordBreak))
  1639.         {
  1640.             // ----- Check horizontal jusitficaiton
  1641.             switch (opt & FW_kPrivTextBoxHorzJusificationMask)
  1642.             {
  1643.             case FW_kTextAlignHCenter:
  1644.                 drawPosX = (box.left + box.right - actualWidth) / 2;
  1645.                 break;
  1646.             
  1647.             case FW_kTextAlignRight:
  1648.                 drawPosX = box.right - actualWidth;
  1649.                 break;
  1650.             }
  1651.  
  1652.             if (draw)
  1653.             {
  1654.                 // ----- Draw the next line -----
  1655. #ifdef FW_BUILD_WIN
  1656.                 ::TextOut(hDC, drawPosX, drawPosY, line + segStart, segLen);
  1657. #endif
  1658. #ifdef FW_BUILD_MAC
  1659.                 ::MoveTo(drawPosX, drawPosY);
  1660.                 ::DrawText((Ptr)line, segStart, segLen);
  1661.     
  1662.                 // ----- StrikeOut if necessary -----
  1663.                 if (bIsStrikeOut)
  1664.                     MacStrikeOut(device, drawPosX, drawPosY);
  1665. #endif
  1666.             }
  1667.             
  1668.             drawPosY += fontHeight;        // Move one line down
  1669.             line += segLen + segStart;    // move on to the next segment
  1670.             lineLength -= segLen + segStart;
  1671.             
  1672.             // see if we've gotten to the bottom of the rectangle and need not to continue
  1673.             reachedBottom = bClip && (drawPosY > box.bottom);
  1674.         }
  1675.         
  1676.         if (textBuffer->IsDone())
  1677.             break;
  1678.             
  1679.         if (reachedBottom)
  1680.             break;
  1681.     
  1682.         textBuffer->Advance();
  1683.     }
  1684.  
  1685.     // ----- Restore clipping region
  1686. #ifdef FW_BUILD_WIN
  1687.     if (savedDC != 0)
  1688.         ::RestoreDC(*device, savedDC);
  1689. #endif
  1690. #ifdef FW_BUILD_MAC
  1691.     if (oldClipRgn != NULL)
  1692.     {
  1693.         ::SetClip(oldClipRgn);
  1694.         ::FW_DisposeRegion(oldClipRgn);
  1695.     }
  1696.     
  1697. #endif
  1698.  
  1699.     // ----- Return the result ----
  1700. #ifdef FW_BUILD_WIN
  1701.     return drawPosY;
  1702. #endif
  1703. #ifdef FW_BUILD_MAC
  1704.     return drawPosY - fi.ascent;
  1705. #endif
  1706. }
  1707.  
  1708. #ifdef FW_BUILD_MAC
  1709.  
  1710. //========================================================================================
  1711. // Macintosh-specific implementation
  1712. //========================================================================================
  1713.  
  1714. FW_DEFINE_AUTO(FW_PrivSelectHairline)
  1715.  
  1716. FW_PrivSelectHairline::FW_PrivSelectHairline(FW_Boolean setHairline)
  1717. :    fData(NULL)
  1718. {
  1719.     if(setHairline)
  1720.     {        
  1721.         // this memory allocation is unlikely to fail,
  1722.         // and if it does it would result in a line being drawn too fat,
  1723.         // so on failure we just refrain from setting the width
  1724.         fData = FW_PrivMemoryManager_AllocateSystemHandle(sizeof(Point));
  1725.         if(fData != nil)
  1726.         {
  1727.             const short kScaleNumerator = 1;
  1728.             const short kScaleDenominator = 28; // can be from 1 thru 128
  1729.  
  1730.             Point tempData = { kScaleNumerator, kScaleDenominator };
  1731.             **(Point**)fData = tempData;
  1732.             
  1733.             ::PicComment(eSetLineWidthPicComment, sizeof(Point), fData);
  1734.         }
  1735.     }
  1736.     
  1737.     FW_END_CONSTRUCTOR
  1738. }
  1739.  
  1740. FW_PrivSelectHairline::~FW_PrivSelectHairline()
  1741. {
  1742.     FW_START_DESTRUCTOR
  1743.     
  1744.     if(fData != NULL)
  1745.     {
  1746.         // this is done in two passes for stylewriter and laserwriter.
  1747.  
  1748.         {
  1749.             // nothing here will move memory while we have this dereferenced
  1750.             // it still contains the ratio that was set in the ctor
  1751.             Point *pData = *(Point**)fData;
  1752.             Point tempData = *pData;
  1753.             
  1754.             // 1. invert the numerator and denominator to un-scale the pen
  1755.             pData->h = tempData.v;
  1756.             pData->v = tempData.h;
  1757.         }
  1758.         
  1759.         // this inverts the scale -- for the stylewriter
  1760.         ::PicComment(eSetLineWidthPicComment, 4, fData);
  1761.         
  1762.         **(long**)fData = 0x00010001; // set the handle data to {1,1}
  1763.  
  1764.         // this is explicitly 1, 1 for the laserwriter
  1765.         ::PicComment(eSetLineWidthPicComment, 4, fData);
  1766.         
  1767.         FW_PrivMemoryManager_FreeSystemHandle(fData);
  1768.     }
  1769. }
  1770.  
  1771. //----------------------------------------------------------------------------------------
  1772. //    MacSelectInkAndStyle
  1773. //----------------------------------------------------------------------------------------
  1774.  
  1775. static void MacSelectInkAndStyle(
  1776.                         FW_CPrivGraphicsDevice* device,
  1777.                         FW_EPrivShapeCategories shapeCategory,
  1778.                         FW_ERenderVerbs renderVerb,
  1779.                         FW_HInk ink,
  1780.                         FW_HStyle style,
  1781.                         FW_Boolean& styleIsDash,
  1782.                         FW_Boolean& styleIsHairline)
  1783. {
  1784.     device->SelectInk(ink, shapeCategory, renderVerb);
  1785.     device->SelectStyle(style, ink->GetTransferMode(), styleIsDash, styleIsHairline);
  1786.     device->SetInGrafPort();
  1787. }
  1788.  
  1789. //----------------------------------------------------------------------------------------
  1790. //    MacCalcTextPosition
  1791. //----------------------------------------------------------------------------------------
  1792.  
  1793. static FW_CPlatformPoint MacCalcTextPosition(
  1794.                             FW_CPrivGraphicsDevice* device,
  1795.                             short byteCount, const char* text,
  1796.                             FW_TextAlignment textAlignment,
  1797.                             const FW_CPlatformPoint& position)
  1798. {
  1799. #ifndef FW_DEBUG
  1800.     FW_UNUSED(device);
  1801. #endif
  1802.  
  1803.     FW_ASSERT(device->GetPlatformCanvas() == FW_QDGlobals.thePort);
  1804.  
  1805.     FW_ASSERT(text != NULL);
  1806.  
  1807.     FW_CPlatformPoint plfmPos(position);
  1808.  
  1809.     if((textAlignment & FW_kPrivTextAlignUsePosMask) == FW_kTextAlignUseCurrentPos)
  1810.     {
  1811.         ::GetPen(&plfmPos);
  1812.     }
  1813.     else
  1814.     {
  1815.         // ----- Adjust Horizontal position
  1816.         FW_TextAlignment hAlign = textAlignment & FW_kPrivTextAlignHorzAlignMask;
  1817.         if (hAlign != FW_kTextAlignLeft)
  1818.         {
  1819.             short textWidth = ::TextWidth(text, 0, byteCount);
  1820.             if (hAlign == FW_kTextAlignRight)
  1821.                 plfmPos.h -= textWidth;
  1822.             else
  1823.                 plfmPos.h -= (textWidth / 2);
  1824.         }
  1825.     }
  1826.     
  1827.     // ----- In both cases we need to adjust the vertical position
  1828.     FW_TextAlignment vAlign = textAlignment & FW_kPrivTextAlignVertAlignMask;
  1829.     if (vAlign != FW_kTextAlignBaseLine)
  1830.     {
  1831.         FontInfo fi;
  1832.         ::GetFontInfo(&fi);
  1833.         switch (vAlign)
  1834.         {
  1835.             case FW_kTextAlignTop:
  1836.                 plfmPos.v += fi.ascent;
  1837.                 break;
  1838.                 
  1839.             case FW_kTextAlignBottom:
  1840.                 plfmPos.v -= fi.descent;
  1841.                 break;
  1842.                 
  1843.             case FW_kTextAlignVCenter:
  1844.                 plfmPos.v += fi.ascent - ((fi.descent + fi.ascent) / 2);
  1845.                 break;
  1846.         }
  1847.     }
  1848.  
  1849.     return plfmPos;
  1850. }
  1851.  
  1852. //----------------------------------------------------------------------------------------
  1853. //    MacStrikeOut
  1854. //----------------------------------------------------------------------------------------
  1855.  
  1856. static void MacStrikeOut(
  1857.         FW_CPrivGraphicsDevice* device,
  1858.         short beforePosX, short beforePosY)
  1859. {
  1860.     // ----- Get the pen position before drawing -----
  1861.     FW_CPlatformPoint afterPoint;
  1862.     ::GetPen(&afterPoint);
  1863.  
  1864.     FontInfo fi;
  1865.     ::GetFontInfo(&fi);
  1866.     
  1867.     short strikeHeight = (fi.ascent * 2) / 5;
  1868.     
  1869.     device->SetPenSize(1,1);
  1870.     device->SetInGrafPort();
  1871.     
  1872.     ::MoveTo(beforePosX, beforePosY - strikeHeight);
  1873.     ::Line(afterPoint.h - beforePosX - 1, 0);
  1874.     
  1875.     // ----- Restore the pen position -----
  1876.     ::MoveTo(afterPoint.h, afterPoint.v);
  1877. }
  1878.  
  1879. #endif
  1880.  
  1881.