Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions
nsRenderingContextOS2.cpp File Reference
#include "nsGfxDefs.h"
#include "nsRenderingContextOS2.h"
#include "nsFontMetricsOS2.h"
#include "nsRegionOS2.h"
#include "nsDeviceContextOS2.h"
#include "prprf.h"
#include "nsGfxCIID.h"
#include "nsUnicharUtils.h"

Go to the source code of this file.

Classes

class  GraphicsState
struct  GetWidthData
struct  BreakGetTextDimensionsData
struct  GetTextDimensionsData
struct  DrawStringData

Defines

#define OS2_SetClipRegion(hps, hrgn)   OS2_CombineClipRegion(hps, hrgn, CRGN_COPY)
#define FLAG_CLIP_VALID   0x0001
#define FLAG_CLIP_CHANGED   0x0002
#define FLAG_LOCAL_CLIP_VALID   0x0004
#define FLAGS_ALL   (FLAG_CLIP_VALID | FLAG_CLIP_CHANGED | FLAG_LOCAL_CLIP_VALID)

Functions

LONG OS2_CombineClipRegion (HPS hps, HRGN hrgnCombine, LONG lMode)
HRGN OS2_CopyClipRegion (HPS hps)
static PRBool PR_CALLBACK do_GetWidth (const nsFontSwitch *aFontSwitch, const PRUnichar *aSubstring, PRUint32 aSubstringLength, void *aData)
static PRBool PR_CALLBACK do_BreakGetTextDimensions (const nsFontSwitch *aFontSwitch, const PRUnichar *aSubstring, PRUint32 aSubstringLength, void *aData)
static PRBool PR_CALLBACK do_GetTextDimensions (const nsFontSwitch *aFontSwitch, const PRUnichar *aSubstring, PRUint32 aSubstringLength, void *aData)
static PRBool PR_CALLBACK do_DrawString (const nsFontSwitch *aFontSwitch, const PRUnichar *aSubstring, PRUint32 aSubstringLength, void *aData)

Class Documentation

struct GetWidthData

Definition at line 1241 of file nsRenderingContextOS2.cpp.

Collaboration diagram for GetWidthData:
Class Members
HDC mDC
nsFontOS2 * mFont
HFONT mFont
HPS mPS
nsDrawingSurfaceOS2 * mSurface
LONG mWidth
struct BreakGetTextDimensionsData

Definition at line 4322 of file nsFontMetricsGTK.cpp.

Collaboration diagram for BreakGetTextDimensionsData:
Class Members
PRInt32 mAvailWidth
nscoord mAveCharWidth
PRInt32 * mBreaks
HDC mDC
PRInt32 mEstimatedNumChars
nsFontOS2 * mFont
HFONT mFont
nsVoidArray * mFonts
PRInt32 mNumBreaks
PRInt32 mNumCharsFit
nsVoidArray * mOffsets
float mP2T
PRInt32 mPrevBreakState_BreakIndex
nscoord mPrevBreakState_Width
HPS mPS
nscoord mSpaceWidth
nsDrawingSurfaceOS2 * mSurface
nscoord mWidth
struct GetTextDimensionsData

Definition at line 1915 of file nsRenderingContextOS2.cpp.

Collaboration diagram for GetTextDimensionsData:
Class Members
nscoord mAscent
HDC mDC
nscoord mDescent
nsFontOS2 * mFont
HFONT mFont
float mP2T
HPS mPS
nsDrawingSurfaceOS2 * mSurface
LONG mWidth
struct DrawStringData

Definition at line 201 of file nsFontMetricsXft.cpp.

Collaboration diagram for DrawStringData:
Class Members
XftColor color
nsRenderingContextGTK * context
nsCairoRenderingContext * context
XftDraw * draw
nsAutoDrawSpecBuffer * drawBuffer
HDC mDC
nsFontOS2 * mFont
HFONT mFont
nscoord mLength
nscoord mMaxLength
HPS mPS
const nscoord * mSpacing
nsDrawingSurfaceOS2 * mSurface
nsTransform2D * mTranMatrix
nscoord mX
nscoord mY
float p2t
const nscoord * spacing
nscoord x
nscoord xOffset
nscoord y

Define Documentation

#define FLAG_CLIP_CHANGED   0x0002

Definition at line 71 of file nsRenderingContextOS2.cpp.

#define FLAG_CLIP_VALID   0x0001

Definition at line 70 of file nsRenderingContextOS2.cpp.

Definition at line 72 of file nsRenderingContextOS2.cpp.

Definition at line 74 of file nsRenderingContextOS2.cpp.

#define OS2_SetClipRegion (   hps,
  hrgn 
)    OS2_CombineClipRegion(hps, hrgn, CRGN_COPY)

Definition at line 68 of file nsRenderingContextOS2.cpp.


Function Documentation

static PRBool PR_CALLBACK do_BreakGetTextDimensions ( const nsFontSwitch aFontSwitch,
const PRUnichar aSubstring,
PRUint32  aSubstringLength,
void aData 
) [static]

Definition at line 1472 of file nsRenderingContextOS2.cpp.

{
  nsFontOS2* font = aFontSwitch->mFont;

  // Make sure the font is selected
  BreakGetTextDimensionsData* data = (BreakGetTextDimensionsData*)aData;
  if (data->mFont != font) {
    // the desired font is not the current font in the PS
    data->mFont = font;
    data->mSurface->SelectFont(data->mFont);
  }

   // set mMaxAscent & mMaxDescent if not already set in nsFontOS2 struct
  if (font->mMaxAscent == 0)
  {
    FONTMETRICS fm;
    GFX (::GpiQueryFontMetrics(data->mPS, sizeof (fm), &fm), FALSE);
    
    font->mMaxAscent  = NSToCoordRound( (fm.lMaxAscender-1) * data->mP2T );
    font->mMaxDescent = NSToCoordRound( (fm.lMaxDescender+1) * data->mP2T );
  }

  // Our current state relative to the _full_ string...
  // This allows emulation of the previous code...
  const PRUnichar* pstr = (const PRUnichar*)data->mOffsets->ElementAt(0);
  PRInt32 numCharsFit = data->mNumCharsFit;
  nscoord width = data->mWidth;
  PRInt32 start = (PRInt32)(aSubstring - pstr);
  PRInt32 end = start + aSubstringLength;
  PRBool allDone = PR_FALSE;

  while (start < end) {
    // Estimate how many characters will fit. Do that by dividing the
    // available space by the average character width
    PRInt32 estimatedNumChars = data->mEstimatedNumChars;
    if (!estimatedNumChars && data->mAveCharWidth > 0) {
      estimatedNumChars = (data->mAvailWidth - width) / data->mAveCharWidth;
    }
    // Make sure the estimated number of characters is at least 1
    if (estimatedNumChars < 1) {
      estimatedNumChars = 1;
    }

    // Find the nearest break offset
    PRInt32 estimatedBreakOffset = start + estimatedNumChars;
    PRInt32 breakIndex = -1; // not yet computed
    PRBool  inMiddleOfSegment = PR_FALSE;
    nscoord numChars;

    // Avoid scanning the break array in the case where we think all
    // the text should fit
    if (end <= estimatedBreakOffset) {
      // Everything should fit
      numChars = end - start;
    }
    else {
      // Find the nearest place to break that is less than or equal to
      // the estimated break offset
      breakIndex = data->mPrevBreakState_BreakIndex;
      while (breakIndex + 1 < data->mNumBreaks &&
             data->mBreaks[breakIndex + 1] <= estimatedBreakOffset) {
        ++breakIndex;
      }

      if (breakIndex == -1)
        breakIndex = 0;

      // We found a place to break that is before the estimated break
      // offset. Where we break depends on whether the text crosses a
      // segment boundary
      if (start < data->mBreaks[breakIndex]) {
        // The text crosses at least one segment boundary so measure to the
        // break point just before the estimated break offset
        numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
      } 
      else {
        // See whether there is another segment boundary between this one
        // and the end of the text
        if ((breakIndex < (data->mNumBreaks - 1)) && (data->mBreaks[breakIndex] < end)) {
          ++breakIndex;
          numChars = PR_MIN(data->mBreaks[breakIndex], end) - start;
        }
        else {
          NS_ASSERTION(end != data->mBreaks[breakIndex], "don't expect to be at segment boundary");

          // The text is all within the same segment
          numChars = end - start;

          // Remember we're in the middle of a segment and not between
          // two segments
          inMiddleOfSegment = PR_TRUE;
        }
      }
    }

    // Measure the text
    nscoord twWidth, pxWidth;
    if ((1 == numChars) && (pstr[start] == ' ')) {
      twWidth = data->mSpaceWidth;
    }
    else {
      pxWidth = font->GetWidth(data->mPS, &pstr[start], numChars);
      twWidth = NSToCoordRound(float(pxWidth) * data->mP2T);
    }

    // See if the text fits
    PRBool textFits = (twWidth + width) <= data->mAvailWidth;

    // If the text fits then update the width and the number of
    // characters that fit
    if (textFits) {
      numCharsFit += numChars;
      width += twWidth;

      // If we computed the break index and we're not in the middle
      // of a segment then this is a spot that we can back up to if
      // we need to, so remember this state
      if ((breakIndex != -1) && !inMiddleOfSegment) {
        data->mPrevBreakState_BreakIndex = breakIndex;
        data->mPrevBreakState_Width = width;
      }
    }
    else {
      // The text didn't fit. If we're out of room then we're all done
      allDone = PR_TRUE;

      // See if we can just back up to the previous saved state and not
      // have to measure any text
      if (data->mPrevBreakState_BreakIndex != -1) {
        PRBool canBackup;

        // If we're in the middle of a word then the break index
        // must be the same if we can use it. If we're at a segment
        // boundary, then if the saved state is for the previous
        // break index then we can use it
        if (inMiddleOfSegment) {
          canBackup = data->mPrevBreakState_BreakIndex == breakIndex;
        } else {
          canBackup = data->mPrevBreakState_BreakIndex == (breakIndex - 1);
        }

        if (canBackup) {
          numCharsFit = data->mBreaks[data->mPrevBreakState_BreakIndex];
          width = data->mPrevBreakState_Width;
          break;
        }
      }

      // We can't just revert to the previous break state. Find the break
      // index just before the end of the text
      end = start + numChars;
      breakIndex = 0;
      if (data->mBreaks[breakIndex] < end) {
        while ((breakIndex + 1 < data->mNumBreaks) && (data->mBreaks[breakIndex + 1] < end)) {
          ++breakIndex;
        }
      }

      if ((0 == breakIndex) && (end <= data->mBreaks[0])) {
        // There's no place to back up to, so even though the text doesn't fit
        // return it anyway
        numCharsFit += numChars;
        width += twWidth;

        // Edge case of one word: it could be that we just measured a fragment of the
        // first word and its remainder involves other fonts, so we want to keep going
        // until we at least measure the entire first word
        if (numCharsFit < data->mBreaks[0]) {
          allDone = PR_FALSE;
          // From now on we don't care anymore what is the _real_ estimated
          // number of characters that fits. Rather, we have no where to break
          // and have to measure one word fully, but the real estimate is less
          // than that one word. However, since the other bits of code rely on
          // what is in "data->mEstimatedNumChars", we want to override
          // "data->mEstimatedNumChars" and pass in what _has_ to be measured
          // so that it is transparent to the other bits that depend on it.
          data->mEstimatedNumChars = data->mBreaks[0] - numCharsFit;
          start += numChars;
        }

        break;
      }

      // Repeatedly back up until we get to where the text fits or we're
      // all the way back to the first word
      width += twWidth;
      while ((breakIndex >= 0) && (width > data->mAvailWidth)) {
        start = data->mBreaks[breakIndex];
        numChars = end - start;
        numCharsFit = start;
        if ((1 == numChars) && (pstr[start] == ' ')) {
          width -= data->mSpaceWidth;
        }
        else if (pstr + start >= aSubstring) {
          // The entire fragment to chop is within the current font.
          pxWidth = font->GetWidth(data->mPS, &pstr[start], numChars);
          width -= NSToCoordRound(float(pxWidth) * data->mP2T);
        }
        else {
          // The fragment that we want to chop extends back into previous fonts.
          // We need to reverse into previous fonts. Fortunately,
          // data->mFonts[] and data->mOffsets[] tell us which fonts are used
          // and when. 
          end = data->mNumCharsFit; // same as aSubstring - pstr
          data->mNumCharsFit = numCharsFit; // has got shorter...
          PRInt32 k = data->mFonts->Count() - 1;
          for ( ; k >= 0 && start < end; --k, end -= numChars) {
            font = (nsFontOS2*)data->mFonts->ElementAt(k);
            const PRUnichar* ps = (const PRUnichar*)data->mOffsets->ElementAt(k);
            if (ps < pstr + start)
              ps = pstr + start;

            numChars = pstr + end - ps;
            NS_ASSERTION(numChars > 0, "empty string");

            data->mFont = font;
            data->mSurface->SelectFont(data->mFont);
            pxWidth = font->GetWidth(data->mPS, ps, numChars);
            data->mWidth -= NSToCoordRound(float(pxWidth) * data->mP2T);

            // By construction, mFonts[k] is the last font, and
            // mOffsets[k+1] is the last offset.
            data->mFonts->RemoveElementAt(k);
            data->mOffsets->RemoveElementAt(k+1);
          }

          // We are done, update the data now because we won't do it later.
          // The |if (data->mNumCharsFit != numCharsFit)| won't apply below
          data->mFonts->AppendElement(font);
          data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
          break;
        }

        --breakIndex;
        end = start;
      }
    }

    start += numChars;
  }

#ifdef DEBUG_rbs
  NS_ASSERTION(allDone || start == end, "internal error");
  NS_ASSERTION(allDone || data->mNumCharsFit != numCharsFit, "internal error");
#endif /* DEBUG_rbs */

  if (data->mNumCharsFit != numCharsFit) {
    // some text was actually retained
    data->mWidth = width;
    data->mNumCharsFit = numCharsFit;
    data->mFonts->AppendElement(font);
    data->mOffsets->AppendElement((void*)&pstr[numCharsFit]);
  }

  if (allDone) {
    // stop now
    return PR_FALSE;
  }

  return PR_TRUE; // don't stop if we still need to measure more characters
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool PR_CALLBACK do_DrawString ( const nsFontSwitch aFontSwitch,
const PRUnichar aSubstring,
PRUint32  aSubstringLength,
void aData 
) [static]

Definition at line 2035 of file nsRenderingContextOS2.cpp.

{
  nsFontOS2* font = aFontSwitch->mFont;

  PRInt32 x, y;
  DrawStringData* data = (DrawStringData*)aData;
  if (data->mFont != font) {
    // the desired font is not the current font in the PS
    data->mFont = font;
    data->mSurface->SelectFont(data->mFont);
  }

  data->mLength += aSubstringLength;
  if (data->mSpacing) {
    // XXX Fix path to use a twips transform in the DC and use the
    // spacing values directly and let windows deal with the sub-pixel
    // positioning.

    // Slow, but accurate rendering
    const PRUnichar* str = aSubstring;
    const PRUnichar* end = aSubstring + aSubstringLength;
    while (str < end) {
      // XXX can shave some cycles by inlining a version of transform
      // coord where y is constant and transformed once
      x = data->mX;
      y = data->mY;
      data->mTranMatrix->TransformCoord(&x, &y);
      if (IS_HIGH_SURROGATE(*str) && 
          ((str+1)<end) && 
          IS_LOW_SURROGATE(*(str+1))) 
      {
        // special case for surrogate pair
        font->DrawString(data->mPS, data->mSurface, x, y, str, 2);
        // we need to advance data->mX and str twice
        data->mX += *data->mSpacing++;
        ++str;
      } else {
        font->DrawString(data->mPS, data->mSurface, x, y, str, 1);
      }
      data->mX += *data->mSpacing++;
      ++str;
    }
  }
  else {
    font->DrawString(data->mPS, data->mSurface, data->mX, data->mY, aSubstring,
                     aSubstringLength);
    // be ready if there is more to come
    if (data->mLength < data->mMaxLength) {
      data->mX += font->GetWidth(data->mPS, aSubstring, aSubstringLength);
    }
  }
  return PR_TRUE; // don't stop till the end
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool PR_CALLBACK do_GetTextDimensions ( const nsFontSwitch aFontSwitch,
const PRUnichar aSubstring,
PRUint32  aSubstringLength,
void aData 
) [static]

Definition at line 1926 of file nsRenderingContextOS2.cpp.

{
  nsFontOS2* font = aFontSwitch->mFont;
  
  GetTextDimensionsData* data = (GetTextDimensionsData*)aData;
  if (data->mFont != font) {
    // the desired font is not the current font in the PS
    data->mFont = font;
    data->mSurface->SelectFont(data->mFont);
  }

  data->mWidth += font->GetWidth(data->mPS, aSubstring, aSubstringLength);

   // set mMaxAscent & mMaxDescent if not already set in nsFontOS2 struct
  if (font->mMaxAscent == 0) {
    FONTMETRICS fm;
    GFX (::GpiQueryFontMetrics(data->mPS, sizeof (fm), &fm), FALSE);
    font->mMaxAscent  = NSToCoordRound( (fm.lMaxAscender-1) * data->mP2T );
    font->mMaxDescent = NSToCoordRound( (fm.lMaxDescender+1) * data->mP2T );
  }

  if (data->mAscent < font->mMaxAscent) {
    data->mAscent = font->mMaxAscent;
  }
  if (data->mDescent < font->mMaxDescent) {
    data->mDescent = font->mMaxDescent;
  }

  return PR_TRUE; // don't stop till the end
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool PR_CALLBACK do_GetWidth ( const nsFontSwitch aFontSwitch,
const PRUnichar aSubstring,
PRUint32  aSubstringLength,
void aData 
) [static]

Definition at line 1249 of file nsRenderingContextOS2.cpp.

{
  nsFontOS2* font = aFontSwitch->mFont;

  GetWidthData* data = (GetWidthData*)aData;
  if (data->mFont != font) {
    // the desired font is not the current font in the PS
    data->mFont = font;
    data->mSurface->SelectFont(data->mFont);
  }
  data->mWidth += font->GetWidth(data->mPS, aSubstring, aSubstringLength);
  return PR_TRUE; // don't stop till the end
}

Here is the call graph for this function:

Here is the caller graph for this function:

LONG OS2_CombineClipRegion ( HPS  hps,
HRGN  hrgnCombine,
LONG  lMode 
)

Definition at line 2417 of file nsRenderingContextOS2.cpp.

{
   if (!hps) return RGN_ERROR;

   HRGN hrgnClip = 0;
   LONG rc = RGN_NULL;

   GFX (::GpiSetClipRegion (hps, 0, &hrgnClip), RGN_ERROR); // Get the current clip region and deselect it

   if (hrgnClip && hrgnClip != HRGN_ERROR)
   {
      if (lMode != CRGN_COPY)    // If necessarry combine with previous clip region
         GFX (::GpiCombineRegion (hps, hrgnCombine, hrgnClip, hrgnCombine, lMode), RGN_ERROR);
      
      GFX (::GpiDestroyRegion (hps, hrgnClip), FALSE);
   }

   if (hrgnCombine)
      rc = GFX (::GpiSetClipRegion (hps, hrgnCombine, NULL), RGN_ERROR);  // Set new clip region

   return rc;
}

Here is the caller graph for this function:

HRGN OS2_CopyClipRegion ( HPS  hps)

Definition at line 2441 of file nsRenderingContextOS2.cpp.

{
  if (!hps) return HRGN_ERROR;

  HRGN hrgn = 0, hrgnClip;

  // Get current clip region
  GFX (::GpiSetClipRegion (hps, 0, &hrgnClip), RGN_ERROR);

  if (hrgnClip && hrgnClip != HRGN_ERROR)
  {
     hrgn = GFX (::GpiCreateRegion (hps, 0, NULL), RGN_ERROR);     // Create empty region and combine with current
     GFX (::GpiCombineRegion (hps, hrgn, hrgnClip, 0, CRGN_COPY), RGN_ERROR);
     GFX (::GpiSetClipRegion (hps, hrgnClip, NULL), RGN_ERROR);    // restore current clip region
  }

  return hrgn;
}

Here is the caller graph for this function: