Back to index

lightning-sunbird  0.9+nobinonly
Public Member Functions | Protected Attributes | Private Member Functions | Static Private Member Functions | Private Attributes | Friends
nsMathMLChar Class Reference

#include <nsMathMLChar.h>

Collaboration diagram for nsMathMLChar:
Collaboration graph
[legend]

List of all members.

Public Member Functions

 nsMathMLChar (nsMathMLChar *aParent=nsnull)
 ~nsMathMLChar ()
nsresult Paint (nsPresContext *aPresContext, nsIRenderingContext &aRenderingContext, const nsRect &aDirtyRect, nsFramePaintLayer aWhichLayer, nsIFrame *aForFrame, const nsRect *aSelectedRect=nsnull)
nsresult Stretch (nsPresContext *aPresContext, nsIRenderingContext &aRenderingContext, nsStretchDirection aStretchDirection, nsBoundingMetrics &aContainerSize, nsBoundingMetrics &aDesiredStretchSize, PRUint32 aStretchHint=NS_STRETCH_NORMAL)
void SetData (nsPresContext *aPresContext, nsString &aData)
void GetData (nsString &aData)
PRInt32 Length ()
nsStretchDirection GetStretchDirection ()
const PRUnicharget ()
void GetRect (nsRect &aRect)
void SetRect (const nsRect &aRect)
void GetBoundingMetrics (nsBoundingMetrics &aBoundingMetrics)
void SetBoundingMetrics (nsBoundingMetrics &aBoundingMetrics)
nsStyleContextGetStyleContext () const
void SetStyleContext (nsStyleContext *aStyleContext)

Protected Attributes

nsString mData
nsMathMLCharmSibling
nsMathMLCharmParent

Private Member Functions

nsresult ComposeChildren (nsPresContext *aPresContext, nsIRenderingContext &aRenderingContext, nsGlyphTable *aGlyphTable, nsBoundingMetrics &aContainerSize, nsBoundingMetrics &aCompositeSize, PRUint32 aStretchHint)

Static Private Member Functions

static nsresult PaintVertically (nsPresContext *aPresContext, nsIRenderingContext &aRenderingContext, nsFont &aFont, nsStyleContext *aStyleContext, nsGlyphTable *aGlyphTable, nsMathMLChar *aChar, nsRect &aRect)
static nsresult PaintHorizontally (nsPresContext *aPresContext, nsIRenderingContext &aRenderingContext, nsFont &aFont, nsStyleContext *aStyleContext, nsGlyphTable *aGlyphTable, nsMathMLChar *aChar, nsRect &aRect)

Private Attributes

nsRect mRect
PRInt32 mOperator
nsStretchDirection mDirection
nsBoundingMetrics mBoundingMetrics
nsStyleContextmStyleContext
nsGlyphTablemGlyphTable
nsGlyphCode mGlyph

Friends

class nsGlyphTable

Detailed Description

Definition at line 78 of file nsMathMLChar.h.


Constructor & Destructor Documentation

nsMathMLChar::nsMathMLChar ( nsMathMLChar aParent = nsnull) [inline]

Definition at line 82 of file nsMathMLChar.h.

Here is the caller graph for this function:

Definition at line 89 of file nsMathMLChar.h.

                  { // not a virtual destructor: this class is not intended to be subclassed
    MOZ_COUNT_DTOR(nsMathMLChar);
    // there is only one style context owned by the "root" char
    // and it may be used by child chars as well
    if (!mParent && mStyleContext) { // only the "root" need to release it
      mStyleContext->Release();
    }
    if (mSibling) {
      delete mSibling;
    }
  }

Here is the call graph for this function:


Member Function Documentation

nsresult nsMathMLChar::ComposeChildren ( nsPresContext aPresContext,
nsIRenderingContext aRenderingContext,
nsGlyphTable aGlyphTable,
nsBoundingMetrics &  aContainerSize,
nsBoundingMetrics &  aCompositeSize,
PRUint32  aStretchHint 
) [private]

Definition at line 1848 of file nsMathMLChar.cpp.

{
  PRInt32 i = 0;
  nsMathMLChar* child;
  PRInt32 count = aGlyphTable->ChildCountOf(aPresContext, this);
  NS_ASSERTION(count, "something is wrong somewhere");
  if (!count) return NS_ERROR_FAILURE;
  // if we haven't been here before, create the linked list of children now
  // otherwise, use what we have, adding more children as needed or deleting the extra
  nsMathMLChar* last = this;
  while ((i < count) && last->mSibling) {
    i++;
    last = last->mSibling;
  }
  while (i < count) {
    child = new nsMathMLChar(this);
    if (!child) {
      if (mSibling) delete mSibling; // don't leave a dangling list ...
      mSibling = nsnull;
      return NS_ERROR_OUT_OF_MEMORY;
    }
    last->mSibling = child;
    last = child;
    i++;
  }
  if (last->mSibling) {
    delete last->mSibling;
    last->mSibling = nsnull;
  }
  // let children stretch in an equal space
  nsBoundingMetrics splitSize(aContainerSize);
  if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection)
    splitSize.width /= count;
  else {
    splitSize.ascent = ((splitSize.ascent + splitSize.descent) / count) / 2;
    splitSize.descent = splitSize.ascent;
  }
  nscoord dx = 0, dy = 0;
  for (i = 0, child = mSibling; child; child = child->mSibling, i++) {
    // child chars should just inherit our values - which may change between calls...
    child->mData = mData;
    child->mOperator = mOperator;
    child->mDirection = mDirection;
    child->mStyleContext = mStyleContext;
    child->mGlyphTable = aGlyphTable; // the child is associated to this table
    // there goes the Stretch() ...
    nsBoundingMetrics childSize;
    nsresult rv = child->Stretch(aPresContext, aRenderingContext, mDirection,
                                 splitSize, childSize, aStretchHint);
    // check if something went wrong or the child couldn't fit in the alloted space
    if (NS_FAILED(rv) || (NS_STRETCH_DIRECTION_UNSUPPORTED == child->mDirection)) {
      delete mSibling; // don't leave a dangling list behind ...
      mSibling = nsnull;
      return NS_ERROR_FAILURE;
    }
    child->SetRect(nsRect(dx, dy, childSize.width, childSize.ascent+childSize.descent));
    if (0 == i)
      aCompositeSize = childSize;
    else {
      if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection)
        aCompositeSize += childSize;
      else {
        aCompositeSize.descent += childSize.ascent + childSize.descent;
        if (aCompositeSize.leftBearing > childSize.leftBearing)
          aCompositeSize.leftBearing = childSize.leftBearing;
        if (aCompositeSize.rightBearing < childSize.rightBearing)
          aCompositeSize.rightBearing = childSize.rightBearing;
      }
    }
    if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection)
      dx += childSize.width;
    else
      dy += childSize.ascent + childSize.descent;
  }
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 142 of file nsMathMLChar.h.

        {
    return mData.get();
  }

Here is the call graph for this function:

void nsMathMLChar::GetBoundingMetrics ( nsBoundingMetrics &  aBoundingMetrics) [inline]

Definition at line 171 of file nsMathMLChar.h.

                                                          {
    aBoundingMetrics = mBoundingMetrics;
  }

Here is the caller graph for this function:

void nsMathMLChar::GetData ( nsString aData) [inline]

Definition at line 125 of file nsMathMLChar.h.

                           {
    aData = mData;
  }

Here is the caller graph for this function:

void nsMathMLChar::GetRect ( nsRect aRect) [inline]

Definition at line 147 of file nsMathMLChar.h.

                         {
    aRect = mRect;
  }

Here is the caller graph for this function:

Definition at line 135 of file nsMathMLChar.h.

                        {
    return mDirection;
  }

Here is the caller graph for this function:

Definition at line 1277 of file nsMathMLChar.cpp.

{
  NS_ASSERTION(!mParent, "invalid call - not allowed for child chars");
  NS_ASSERTION(mStyleContext, "chars shoud always have style context");
  return mStyleContext;
  return NS_OK;
}

Here is the caller graph for this function:

Definition at line 130 of file nsMathMLChar.h.

           {
    return mData.Length();
  }

Here is the caller graph for this function:

nsresult nsMathMLChar::Paint ( nsPresContext aPresContext,
nsIRenderingContext aRenderingContext,
const nsRect aDirtyRect,
nsFramePaintLayer  aWhichLayer,
nsIFrame aForFrame,
const nsRect aSelectedRect = nsnull 
)

Definition at line 1931 of file nsMathMLChar.cpp.

{
  nsresult rv = NS_OK;
  nsStyleContext* parentContext = mStyleContext->GetParent();
  nsStyleContext* styleContext = mStyleContext;

  if (NS_STRETCH_DIRECTION_UNSUPPORTED == mDirection) {
    // normal drawing if there is nothing special about this char
    // Set default context to the parent context
    styleContext = parentContext;
  }

  if (!styleContext->GetStyleVisibility()->IsVisible())
    return NS_OK;

  // if the leaf style context that we use for stretchy chars has a background
  // color we use it -- this feature is mostly used for testing and debugging
  // purposes. Normally, users will set the background on the container frame.
  if (NS_FRAME_PAINT_LAYER_BACKGROUND == aWhichLayer) {
    // paint the selection background -- beware MathML frames overlap a lot
    if (aSelectedRect && !aSelectedRect->IsEmpty()) {
      // get color to use for selection from the look&feel object
      nscolor bgColor = NS_RGB(0, 0, 0);
      aPresContext->LookAndFeel()->
       GetColor(nsILookAndFeel::eColor_TextSelectBackground, bgColor);
      aRenderingContext.SetColor(bgColor);
      aRenderingContext.FillRect(*aSelectedRect);
    }
    else if (mRect.width && mRect.height) {
      const nsStyleBorder* border = styleContext->GetStyleBorder();
      const nsStylePadding* padding = styleContext->GetStylePadding();
      const nsStyleBackground* backg = styleContext->GetStyleBackground();
      nsRect rect(mRect); //0, 0, mRect.width, mRect.height);
      if (styleContext != parentContext &&
          0 == (backg->mBackgroundFlags & NS_STYLE_BG_COLOR_TRANSPARENT))
        nsCSSRendering::PaintBackgroundWithSC(aPresContext, aRenderingContext, aForFrame,
                                              aDirtyRect, rect, *backg, *border, *padding,
                                              PR_TRUE);
      //else
      //  our container frame will take care of painting its background
      //  nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, aForFrame,
      //                                  aDirtyRect, rect, *border, *padding, PR_TRUE);
#if defined(NS_DEBUG) && defined(SHOW_BOUNDING_BOX)
      // for visual debug
      PRIntn skipSides = 0; //aForFrame->GetSkipSides();
      const nsStyleOutline* outline = styleContext->GetStyleOutline();
      nsCSSRendering::PaintBorder(aPresContext, aRenderingContext, aForFrame,
                                  aDirtyRect, rect, *border, styleContext, skipSides);
      nsCSSRendering::PaintOutline(aPresContext, aRenderingContext, aForFrame,
                                   aDirtyRect, rect, *border, *outline, styleContext, 0);
#endif
    }
  }

  if (NS_FRAME_PAINT_LAYER_FOREGROUND == aWhichLayer) {
    // Set color ...
    nscolor fgColor = styleContext->GetStyleColor()->mColor;
    if (aSelectedRect && !aSelectedRect->IsEmpty()) {
      // get color to use for selection from the look&feel object
      aPresContext->LookAndFeel()->
       GetColor(nsILookAndFeel::eColor_TextSelectForeground, fgColor);
    }
    aRenderingContext.SetColor(fgColor);

    nsAutoString fontName;
    nsFont theFont(styleContext->GetStyleFont()->mFont);

    if (NS_STRETCH_DIRECTION_UNSUPPORTED == mDirection) {
      // normal drawing if there is nothing special about this char ...
      // Set the default font and grab some metrics to adjust the placements ...
      PRUint32 len = PRUint32(mData.Length());
      if (1 == len) {
        SetBaseFamily(mData[0], theFont);
      }
      aRenderingContext.SetFont(theFont, nsnull);
//printf("Painting %04X like a normal char\n", mData[0]);
//aRenderingContext.SetColor(NS_RGB(255,0,0));
      aRenderingContext.DrawString(mData.get(), len, mRect.x, mRect.y + mBoundingMetrics.ascent);
    }
    else {
      // Set the stretchy font and grab some metrics to adjust the placements ...
      mGlyphTable->GetPrimaryFontName(fontName);
      SetFirstFamily(theFont, fontName);
      aRenderingContext.SetFont(theFont, nsnull);
      // if there is a glyph of appropriate size, paint that glyph
      if (mGlyph) {
//printf("Painting %04X with a glyph of appropriate size\n", mData[0]);
//aRenderingContext.SetColor(NS_RGB(0,0,255));
        mGlyphTable->DrawGlyph(aRenderingContext, theFont, mGlyph,
                               mRect.x, mRect.y + mBoundingMetrics.ascent);
      }
      else { // paint by parts
        // see if this is a composite char and let children paint themselves
        if (!mParent && mSibling) { // only a "root" having child chars can enter here
          for (nsMathMLChar* child = mSibling; child; child = child->mSibling) {
//if (!mStyleContext->Equals(child->mStyleContext))
//  printf("char contexts are out of sync\n");
            child->Paint(aPresContext, aRenderingContext,
                         aDirtyRect, aWhichLayer, aForFrame, aSelectedRect);
          }
          return NS_OK; // that's all folks
        }
//aRenderingContext.SetColor(NS_RGB(0,255,0));
        if (NS_STRETCH_DIRECTION_VERTICAL == mDirection)
          rv = PaintVertically(aPresContext, aRenderingContext, theFont, styleContext,
                               mGlyphTable, this, mRect);
        else if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection)
          rv = PaintHorizontally(aPresContext, aRenderingContext, theFont, styleContext,
                                 mGlyphTable, this, mRect);
      }
    }
  }
  return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsMathMLChar::PaintHorizontally ( nsPresContext aPresContext,
nsIRenderingContext aRenderingContext,
nsFont aFont,
nsStyleContext aStyleContext,
nsGlyphTable aGlyphTable,
nsMathMLChar aChar,
nsRect aRect 
) [static, private]

Definition at line 2251 of file nsMathMLChar.cpp.

{
  nsresult rv = NS_OK;
  nsRect clipRect;
  nscoord dx, dy;

  nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);

  // get metrics data to be re-used later
  PRInt32 i;
  nsGlyphCode ch, chdata[4];
  nsBoundingMetrics bm, bmdata[4];
  nscoord stride = 0, offset[3], start[3], end[3];
  dy = aRect.y;
  nsGlyphCode glue = aGlyphTable->GlueOf(aPresContext, aChar);
  for (i = 0; i < 4; i++) {
    switch (i) {
      case 0: ch = aGlyphTable->LeftOf(aPresContext, aChar);   break;
      case 1: ch = aGlyphTable->MiddleOf(aPresContext, aChar); break;
      case 2: ch = aGlyphTable->RightOf(aPresContext, aChar);  break;
      case 3: ch = glue;                                       break;
    }
    // empty slots are filled with the glue if it is not null
    if (!ch) ch = glue;
    if (!ch) {
      bm.Clear();  // glue is null, set bounding metrics to 0
    }
    else {
      rv = aGlyphTable->GetBoundingMetrics(aRenderingContext, aFont, ch, bm);
      if (NS_FAILED(rv)) {
        NS_WARNING("GetBoundingMetrics failed");
        return rv;
      }
      if (dy < aRect.y + bm.ascent) {
        dy = aRect.y + bm.ascent;
      }
    }
    chdata[i] = ch;
    bmdata[i] = bm;
  }
  for (i = 0; i < 3; i++) {
    ch = chdata[i];
    bm = bmdata[i];
    if (0 == i) { // left
      dx = aRect.x - bm.leftBearing;
    }
    else if (1 == i) { // middle
      dx = aRect.x + (aRect.width - bm.width)/2;
    }
    else { // right
      dx = aRect.x + aRect.width - bm.rightBearing;
    }
    // abcissa that DrawString used
    offset[i] = dx;
    // *exact* abcissa where the *left-most* pixel of the glyph is painted
    start[i] = dx + bm.leftBearing;
    // *exact* abcissa where the *right-most* pixel of the glyph is painted
    end[i] = dx + bm.rightBearing; // note: end = start + width
  }

  // draw left, middle, right
  for (i = 0; i < 3; i++) {
    ch = chdata[i];
    // glue can be null, and other parts could have been set to glue
    if (ch) {
#ifdef SHOW_BORDERS
      aRenderingContext.SetColor(NS_RGB(255,0,0));
      aRenderingContext.DrawRect(nsRect(start[i], dy - bmdata[i].ascent,
                                 end[i] - start[i], bmdata[i].ascent + bmdata[i].descent));
#endif
      dx = offset[i];
      if (0 == i) { // left
        clipRect.SetRect(dx, aRect.y, aRect.width, aRect.height);
      }
      else if (1 == i) { // middle
        clipRect.SetRect(end[0], aRect.y, start[2]-end[0], aRect.height);
      }
      else { // right
        clipRect.SetRect(start[2], aRect.y, end[2]-start[2], aRect.height);
      }
      if (!clipRect.IsEmpty()) {
        clipRect.Inflate(onePixel, onePixel);
        aGlyphTable->DrawGlyph(aRenderingContext, aFont, ch, dx, dy, &clipRect);
      }
    }
  }

  // fill the gap between left and middle, and between middle and right.
  if (!glue) { // null glue : draw a rule
    // figure out the dimensions of the rule to be drawn :
    // set ascent to lowest ascent among the two current successive parts.
    // set descent to highest descent among the two current successive parts.
    // this satisfies the convention used for over/underbraces, and helps
    // fix broken fonts.
    nscoord ascent, descent;
    PRInt32 first = 0, last = 2;
    if (chdata[1]) { // middle part exists
      last = 1;
    }
    while (last <= 2) {
      if (chdata[last]) {
        ascent = bmdata[last].ascent;
        descent = bmdata[last].descent;
        if (chdata[first]) {
          if (ascent > bmdata[first].ascent)
            ascent = bmdata[first].ascent;
          if (descent > bmdata[first].descent)
            descent = bmdata[first].descent;
        }
      }
      else if (chdata[first]) {
        ascent = bmdata[first].ascent;
        descent = bmdata[first].descent;
      }
      else {
        NS_ERROR("Cannot stretch - All parts missing");
        return NS_ERROR_UNEXPECTED;
      }
      // paint the rule between the parts
      nsRect rule(end[first] - onePixel, dy - ascent,
                  start[last] - end[first] + 2*onePixel, ascent + descent);
      if (!rule.IsEmpty())
        aRenderingContext.FillRect(rule);
      first = last;
      last++;
    }
  }
  else { // glue is present
    nscoord overlap;
    nsCOMPtr<nsIFontMetrics> fm;
    aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
    nsMathMLFrame::GetRuleThickness(fm, overlap);
    overlap = 2 * PR_MAX(overlap, onePixel);
    while (overlap > 0 && bmdata[3].rightBearing - bmdata[3].leftBearing <= 2*overlap + onePixel)
      overlap -= onePixel;

    if (overlap > 0) {
      // to protect against gaps, pretend the glue is smaller than 
      // it says to allow a small overlap when adjoining it
      bmdata[3].leftBearing += overlap;
      bmdata[3].rightBearing -= overlap;
    }
    nscoord edge = PR_MAX(overlap, onePixel);

    for (i = 0; i < 2; i++) {
      PRInt32 count = 0;
      dx = offset[i];
      clipRect.SetRect(end[i], aRect.y, start[i+1]-end[i], aRect.height);
      clipRect.Inflate(edge, edge);
#ifdef SHOW_BORDERS
      // rectangles in-between that are to be filled
      aRenderingContext.SetColor(NS_RGB(255,0,0));
      aRenderingContext.DrawRect(clipRect);
#endif
      aRenderingContext.PushState();
      aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect);
      bm = bmdata[i];
      while (dx + bm.rightBearing < start[i+1]) {
        if (count++ < 2) {
          stride = bm.rightBearing;
          bm = bmdata[3]; // glue
          stride -= bm.leftBearing;
        }
        // defensive code against odd things such as a smallish TextZoom...
        NS_ASSERTION(1000 != count, "something is probably wrong somewhere");
        if (stride < onePixel || 1000 == count) {
          aRenderingContext.PopState();
          return NS_ERROR_UNEXPECTED;
        }
        dx += stride;
        aGlyphTable->DrawGlyph(aRenderingContext, aFont, glue, dx, dy);
      }
      aRenderingContext.PopState();
#ifdef SHOW_BORDERS
      // last glyph that may cross past its boundary and collide with the next
      nscoord width = bm.rightBearing - bm.leftBearing;
      aRenderingContext.SetColor(NS_RGB(0,255,0));
      aRenderingContext.DrawRect(nsRect(dx + bm.leftBearing, aRect.y, width, aRect.height));
#endif
    }
  }
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsMathMLChar::PaintVertically ( nsPresContext aPresContext,
nsIRenderingContext aRenderingContext,
nsFont aFont,
nsStyleContext aStyleContext,
nsGlyphTable aGlyphTable,
nsMathMLChar aChar,
nsRect aRect 
) [static, private]

Definition at line 2057 of file nsMathMLChar.cpp.

{
  nsresult rv = NS_OK;
  nsRect clipRect;
  nscoord dx, dy;

  nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);

  // get metrics data to be re-used later
  PRInt32 i;
  nsGlyphCode ch, chdata[4];
  nsBoundingMetrics bm, bmdata[4];
  nscoord stride = 0, offset[3], start[3], end[3];
  nscoord width = aRect.width;
  nsGlyphCode glue = aGlyphTable->GlueOf(aPresContext, aChar);
  for (i = 0; i < 4; i++) {
    switch (i) {
      case 0: ch = aGlyphTable->TopOf(aPresContext, aChar);    break;
      case 1: ch = aGlyphTable->MiddleOf(aPresContext, aChar); break;
      case 2: ch = aGlyphTable->BottomOf(aPresContext, aChar); break;
      case 3: ch = glue;                                       break;
    }
    // empty slots are filled with the glue if it is not null
    if (!ch) ch = glue;
    if (!ch) {
      bm.Clear();  // glue is null, set bounding metrics to 0
    }
    else {
      rv = aGlyphTable->GetBoundingMetrics(aRenderingContext, aFont, ch, bm);
      if (NS_FAILED(rv)) {
        NS_WARNING("GetBoundingMetrics failed");
        return rv;
      }
      if (width < bm.rightBearing) width =  bm.rightBearing;
    }
    chdata[i] = ch;
    bmdata[i] = bm;
  }
  dx = aRect.x;
  for (i = 0; i < 3; i++) {
    ch = chdata[i];
    bm = bmdata[i];
    if (0 == i) { // top
      dy = aRect.y + bm.ascent;
    }
    else if (1 == i) { // middle
      dy = aRect.y + bm.ascent + (aRect.height - (bm.ascent + bm.descent))/2;
    }
    else { // bottom
      dy = aRect.y + aRect.height - bm.descent;
    }
    // abcissa passed to DrawString
    offset[i] = dy;
    // *exact* abcissa where the *top-most* pixel of the glyph is painted
    start[i] = dy - bm.ascent;
    // *exact* abcissa where the *bottom-most* pixel of the glyph is painted
    end[i] = dy + bm.descent; // end = start + height
  }

  // draw top, middle, bottom
  for (i = 0; i < 3; i++) {
    ch = chdata[i];
    // glue can be null, and other parts could have been set to glue
    if (ch) {
#ifdef SHOW_BORDERS
      // bounding box of the part
      aRenderingContext.SetColor(NS_RGB(0,0,0));
      aRenderingContext.DrawRect(nsRect(dx,start[i],width+30*(i+1),end[i]-start[i]));
#endif
      dy = offset[i];
      if (0 == i) { // top
        clipRect.SetRect(dx, aRect.y, width, aRect.height);
      }
      else if (1 == i) { // middle
        clipRect.SetRect(dx, end[0], width, start[2]-end[0]);
      }
      else { // bottom
        clipRect.SetRect(dx, start[2], width, end[2]-start[2]);
      }
      if (!clipRect.IsEmpty()) {
        clipRect.Inflate(onePixel, onePixel);
        aGlyphTable->DrawGlyph(aRenderingContext, aFont, ch, dx, dy, &clipRect);
      }
    }
  }

  // fill the gap between top and middle, and between middle and bottom.
  if (!glue) { // null glue : draw a rule
    // figure out the dimensions of the rule to be drawn :
    // set lbearing to rightmost lbearing among the two current successive parts.
    // set rbearing to leftmost rbearing among the two current successive parts.
    // this not only satisfies the convention used for over/underbraces
    // in TeX, but also takes care of broken fonts like the stretchy integral
    // in Symbol for small font sizes in unix.
    nscoord lbearing, rbearing;
    PRInt32 first = 0, last = 2;
    if (chdata[1]) { // middle part exists
      last = 1;
    }
    while (last <= 2) {
      if (chdata[last]) {
        lbearing = bmdata[last].leftBearing;
        rbearing = bmdata[last].rightBearing;
        if (chdata[first]) {
          if (lbearing < bmdata[first].leftBearing)
            lbearing = bmdata[first].leftBearing;
          if (rbearing > bmdata[first].rightBearing)
            rbearing = bmdata[first].rightBearing;
        }
      }
      else if (chdata[first]) {
        lbearing = bmdata[first].leftBearing;
        rbearing = bmdata[first].rightBearing;
      }
      else {
        NS_ERROR("Cannot stretch - All parts missing");
        return NS_ERROR_UNEXPECTED;
      }
      // paint the rule between the parts
      nsRect rule(aRect.x + lbearing, end[first] - onePixel,
                  rbearing - lbearing, start[last] - end[first] + 2*onePixel);
      if (!rule.IsEmpty())
        aRenderingContext.FillRect(rule);
      first = last;
      last++;
    }
  }
  else { // glue is present
    nscoord overlap;
    nsCOMPtr<nsIFontMetrics> fm;
    aRenderingContext.GetFontMetrics(*getter_AddRefs(fm));
    nsMathMLFrame::GetRuleThickness(fm, overlap);
    overlap = 2 * PR_MAX(overlap, onePixel);
    while (overlap > 0 && bmdata[3].ascent + bmdata[3].descent <= 2*overlap + onePixel)
      overlap -= onePixel;

    if (overlap > 0) {
      // to protect against gaps, pretend the glue is smaller than 
      // it says to allow a small overlap when adjoining it
      bmdata[3].ascent -= overlap;
      bmdata[3].descent -= overlap;
    }
    nscoord edge = PR_MAX(overlap, onePixel);

    for (i = 0; i < 2; i++) {
      PRInt32 count = 0;
      dy = offset[i];
      clipRect.SetRect(dx, end[i], width, start[i+1]-end[i]);
      clipRect.Inflate(edge, edge);
#ifdef SHOW_BORDERS
      // exact area to fill
      aRenderingContext.SetColor(NS_RGB(255,0,0));
      aRenderingContext.DrawRect(clipRect);
#endif
      aRenderingContext.PushState();
      aRenderingContext.SetClipRect(clipRect, nsClipCombine_kIntersect);
      bm = bmdata[i];
      while (dy + bm.descent < start[i+1]) {
        if (count++ < 2) {
          stride = bm.descent;
          bm = bmdata[3]; // glue
          stride += bm.ascent;
        }
        // defensive code against odd things such as a smallish TextZoom...
        NS_ASSERTION(1000 != count, "something is probably wrong somewhere");
        if (stride < onePixel || 1000 == count) {
          aRenderingContext.PopState();
          return NS_ERROR_UNEXPECTED;
        }
        dy += stride;
        aGlyphTable->DrawGlyph(aRenderingContext, aFont, glue, dx, dy);
      }
      aRenderingContext.PopState();
#ifdef SHOW_BORDERS
      // last glyph that may cross past its boundary and collide with the next
      nscoord height = bm.ascent + bm.descent;
      aRenderingContext.SetColor(NS_RGB(0,255,0));
      aRenderingContext.DrawRect(nsRect(dx, dy-bm.ascent, width, height));
#endif
    }
  }
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsMathMLChar::SetBoundingMetrics ( nsBoundingMetrics &  aBoundingMetrics) [inline]

Definition at line 176 of file nsMathMLChar.h.

                                                          {
    mBoundingMetrics = aBoundingMetrics;
  }

Here is the caller graph for this function:

void nsMathMLChar::SetData ( nsPresContext aPresContext,
nsString aData 
)

Definition at line 1308 of file nsMathMLChar.cpp.

{
  NS_ASSERTION(!mParent, "invalid call - not allowed for child chars");
  if (!gInitialized) {
    InitGlobals(aPresContext);
  }
  mData = aData;
  // some assumptions until proven otherwise
  // note that mGlyph is not initialized
  mOperator = -1;
  mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED;
  mBoundingMetrics.Clear();
  mGlyphTable = nsnull;
  // check if stretching is applicable ...
  if (gGlyphTableList && (1 == mData.Length())) {
    mOperator = nsMathMLOperators::FindStretchyOperator(mData[0]);
    if (mOperator >= 0) {
      mDirection = nsMathMLOperators::GetStretchyDirectionAt(mOperator);
      // default tentative table (not the one that is necessarily going to be used)
      mGlyphTable = gGlyphTableList->GetGlyphTableFor(aPresContext, this);
      // commom case: we won't bother with the stretching if there is
      // no glyph table for us...
      if (!mGlyphTable) {
        // never try to stretch this operator again
        nsMathMLOperators::DisableStretchyOperatorAt(mOperator);
        mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED;
        mOperator = -1;
      }
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void nsMathMLChar::SetRect ( const nsRect aRect) [inline]

Definition at line 152 of file nsMathMLChar.h.

                               {
    mRect = aRect;
    // shift the orgins of child chars if any 
    if (!mParent && mSibling) { // only a "root" having child chars can enter here
      for (nsMathMLChar* child = mSibling; child; child = child->mSibling) {
        nsRect rect; 
        child->GetRect(rect);
        rect.MoveBy(mRect.x, mRect.y);
        child->SetRect(rect);
      }
    }
  }

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1286 of file nsMathMLChar.cpp.

{
  NS_ASSERTION(!mParent, "invalid call - not allowed for child chars");
  NS_PRECONDITION(aStyleContext, "null ptr");
  if (aStyleContext != mStyleContext) {
    if (mStyleContext)
      mStyleContext->Release();
    if (aStyleContext) {
      mStyleContext = aStyleContext;
      aStyleContext->AddRef();

      // Sync the pointers of child chars.
      nsMathMLChar* child = mSibling;
      while (child) {
        child->mStyleContext = mStyleContext;
        child = child->mSibling;
      }
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult nsMathMLChar::Stretch ( nsPresContext aPresContext,
nsIRenderingContext aRenderingContext,
nsStretchDirection  aStretchDirection,
nsBoundingMetrics &  aContainerSize,
nsBoundingMetrics &  aDesiredStretchSize,
PRUint32  aStretchHint = NS_STRETCH_NORMAL 
)

Definition at line 1517 of file nsMathMLChar.cpp.

{
  nsresult rv = NS_OK;
  nsStretchDirection direction = aStretchDirection;

  // if we have been called before, and we didn't actually stretch, our
  // direction may have been set to NS_STRETCH_DIRECTION_UNSUPPORTED.
  // So first set our direction back to its instrinsic value
  if (mOperator >= 0) {
    // mOperator is initialized in SetData() and remains unchanged
    mDirection = nsMathMLOperators::GetStretchyDirectionAt(mOperator);
  }

  // if no specified direction, attempt to stretch in our preferred direction
  if (direction == NS_STRETCH_DIRECTION_DEFAULT) {
    direction = mDirection;
  }

  // Set default font and get the default bounding metrics
  // mStyleContext is a leaf context used only when stretching happens.
  // For the base size, the default font should come from the parent context
  nsAutoString fontName;
  nsFont theFont(mStyleContext->GetParent()->GetStyleFont()->mFont);

  // Override with specific fonts if applicable for this character
  PRUnichar uchar = mData[0];
  SetBaseFamily(uchar, theFont);
  aRenderingContext.SetFont(theFont, nsnull);
  rv = aRenderingContext.GetBoundingMetrics(mData.get(),
                                            PRUint32(mData.Length()),
                                            mBoundingMetrics);
  if (NS_FAILED(rv)) {
    NS_WARNING("GetBoundingMetrics failed");
    // ensure that the char later behaves like a normal char
    // (will be reset back to its intrinsic value in case of dynamic updates)
    mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED;
    return rv;
  }

  // set the default desired metrics in case stretching doesn't happen
  aDesiredStretchSize = mBoundingMetrics;

  // quick return if there is nothing special about this char
  if (!mGlyphTable || (mDirection != direction)) {
    // ensure that the char later behaves like a normal char
    // (will be reset back to its intrinsic value in case of dynamic updates)
    mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED;
    return NS_OK;
  }

  // see if this is a particular largeop or largeopOnly request
  PRBool largeop = (NS_STRETCH_LARGEOP & aStretchHint) != 0;
  PRBool largeopOnly = (NS_STRETCH_LARGEOP == aStretchHint); // (==, not mask!)

  // 1. Check the common situations where stretching is not actually needed

  nscoord targetSize, charSize;
  PRBool isVertical = (direction == NS_STRETCH_DIRECTION_VERTICAL);
  if (isVertical) {
    charSize = aDesiredStretchSize.ascent + aDesiredStretchSize.descent;
    targetSize = aContainerSize.ascent + aContainerSize.descent;
  }
  else {
    charSize = aDesiredStretchSize.width;
    targetSize = aContainerSize.width;
  }
  // if we are not a largeop in display mode, return if size fits
  if ((targetSize <= 0) || 
      (!largeop && ((isVertical && charSize >= targetSize) ||
                    IsSizeOK(charSize, targetSize, aStretchHint)))) {
    // ensure that the char later behaves like a normal char
    // (will be reset back to its intrinsic value in case of dynamic updates)
    mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED;
    return NS_OK;
  }

  // 2. Try to search if there is a glyph of appropriate size

  PRInt32 size;
  nsGlyphTable* glyphTable;
  nsBoundingMetrics bm;
  nsGlyphCode startingGlyph = {uchar, 0}; // code@font
  nsGlyphCode ch;

  // this will be the best glyph that we encounter during the search...
  nsGlyphCode bestGlyph = startingGlyph;
  nsGlyphTable* bestGlyphTable = mGlyphTable;
  nsBoundingMetrics bestbm = mBoundingMetrics;

  // use our stretchy style context now that stretching is in progress
  theFont = mStyleContext->GetStyleFont()->mFont;

  // initialize the search list for this char
  PRBool alreadyCSS = PR_FALSE;
  nsAutoVoidArray tableList;
  // see if there are user-specified preferred tables for the variants of this char
  PRInt32 count, t = nsGlyphTableList::gVariants[mOperator];
  gGlyphTableList->GetPreferredListAt(aPresContext, t, &tableList, &count);
  if (!count) {
    // get a list that attempts to honor the css font-family
    gGlyphTableList->GetListFor(aPresContext, this, &theFont, &tableList);
    alreadyCSS = PR_TRUE;
  }

#ifdef NOISY_SEARCH
  printf("Searching in %d fonts for a glyph of appropriate size for: 0x%04X:%c\n",
          tableList.Count(), uchar, uchar&0x00FF);
#endif

  count = tableList.Count();
  for (t = 0; t < count; t++) {
    // see if this table has a glyph that matches the container
    glyphTable = NS_STATIC_CAST(nsGlyphTable*, tableList.ElementAt(t));
    // figure out the starting size : if this is a largeop, start at 2 else 1
    size = 1; // size=0 is the char at its normal size
    if (largeop && glyphTable->BigOf(aPresContext, this, 2)) {
      size = 2;
    }
    glyphTable->GetPrimaryFontName(fontName);
    SetFirstFamily(theFont, fontName);
    aRenderingContext.SetFont(theFont, nsnull);
#ifdef NOISY_SEARCH
    char str[50];
    fontName.ToCString(str, sizeof(str));
    printf("  searching in %s ...\n", str);
#endif
    ch = glyphTable->BigOf(aPresContext, this, size++);
    while (ch) {
      NS_ASSERTION(ch != uchar, "glyph table incorrectly set -- duplicate found");
      rv = glyphTable->GetBoundingMetrics(aRenderingContext, theFont, ch, bm);
      if (NS_SUCCEEDED(rv)) {
        charSize = (isVertical)
                 ? bm.ascent + bm.descent
                 : bm.rightBearing - bm.leftBearing;
        // always break when largeopOnly is set
        if (largeopOnly || IsSizeOK(charSize, targetSize, aStretchHint)) {
#ifdef NOISY_SEARCH
          printf("    size:%d OK!\n", size-1);
#endif
          bestbm = bm;
          bestGlyphTable = glyphTable;
          bestGlyph = ch;
          goto done; // get out...
        }
        nscoord oldSize = (isVertical)
                        ? bestbm.ascent + bestbm.descent
                        : bestbm.rightBearing - bestbm.leftBearing;
        if (IsSizeBetter(charSize, oldSize, targetSize, aStretchHint)) {
          bestGlyphTable = glyphTable;
          bestGlyph = ch;
          bestbm = bm;
#ifdef NOISY_SEARCH
          printf("    size:%d Current best\n", size-1);
        }
        else {
          printf("    size:%d Rejected!\n", size-1);
#endif
        }
      }
      // if largeopOnly is set, break now
      if (largeopOnly) break;
      ch = glyphTable->BigOf(aPresContext, this, size++);
    }
  }
  if (largeopOnly) goto done; // the user doesn't want to stretch

  // Build by parts. If no glyph of appropriate size was found, see if we can
  // build the char by parts. If there are preferred tables, they are used. Otherwise,
  // search for the first table with suitable parts for this char

  // see if there are user-specified preferred tables for the parts of this char
  t = nsGlyphTableList::gParts[mOperator];
  gGlyphTableList->GetPreferredListAt(aPresContext, t, &tableList, &count);
  if (!count && !alreadyCSS) {
    // we didn't do this earlier... so we need to do it here:
    // get a list that attempts to honor the css font-family
    gGlyphTableList->GetListFor(aPresContext, this, &theFont, &tableList);
  }

#ifdef NOISY_SEARCH
  printf("Searching in %d fonts for the first font with suitable parts for: 0x%04X:%c\n",
          tableList.Count(), uchar, uchar&0x00FF);
#endif

  count = tableList.Count();
  for (t = 0; t < count; t++) {
    glyphTable = NS_STATIC_CAST(nsGlyphTable*, tableList.ElementAt(t));
    if (!glyphTable->HasPartsOf(aPresContext, this)) continue; // to next table

    // See if this is a composite character //////////////////////////////////////////
    if (glyphTable->IsComposite(aPresContext, this)) {
      // let the child chars do the job
      nsBoundingMetrics compositeSize;
      rv = ComposeChildren(aPresContext, aRenderingContext, glyphTable,
                           aContainerSize, compositeSize, aStretchHint);
#ifdef NOISY_SEARCH
      char str[50];
      fontName.ToCString(str, sizeof(str));
      printf("    Composing %d chars in font %s %s!\n",
             glyphTable->ChildCountOf(aPresContext, this), str,
             NS_SUCCEEDED(rv)? "OK" : "Rejected");
#endif
      if (NS_FAILED(rv)) continue; // to next table

      // all went well, painting will be delegated from now on to children
      mGlyph = kNullGlyph; // this will tell paint to build by parts
      mGlyphTable = glyphTable;
      mBoundingMetrics = compositeSize;
      aDesiredStretchSize = compositeSize;
      return NS_OK; // get out ...
    }

    // See if the parts of this table fit in the desired space ///////////////////////
    glyphTable->GetPrimaryFontName(fontName);
    SetFirstFamily(theFont, fontName);
    aRenderingContext.SetFont(theFont, nsnull);
    // Compute the bounding metrics of all partial glyphs
    PRInt32 i;
    nsGlyphCode chdata[4];
    nsBoundingMetrics bmdata[4];
    nscoord computedSize, sizedata[4];
    nsGlyphCode glue = glyphTable->GlueOf(aPresContext, this);
    for (i = 0; i < 4; i++) {
      switch (i) {
        case 0: ch = glyphTable->TopOf(aPresContext, this);    break;
        case 1: ch = glyphTable->MiddleOf(aPresContext, this); break;
        case 2: ch = glyphTable->BottomOf(aPresContext, this); break;
        case 3: ch = glue;                                     break;
      }
      // empty slots are filled with the glue if it is not null
      if (!ch) ch = glue;
      if (!ch) { // glue is null, set bounding metrics to 0
        bm.Clear();
      }
      else {
        rv = glyphTable->GetBoundingMetrics(aRenderingContext, theFont, ch, bm);
        if (NS_FAILED(rv)) {
          // stop if we failed to compute the bounding metrics of a part.
          NS_WARNING("GetBoundingMetrics failed");
          break;
        }
      }
      chdata[i] = ch;
      bmdata[i] = bm;
      sizedata[i] = (isVertical)
                  ? bm.ascent + bm.descent
                  : bm.rightBearing - bm.leftBearing;
    }
    if (NS_FAILED(rv)) continue; // to next table

    // Build by parts if we have successfully computed the
    // bounding metrics of all parts.
    computedSize = ComputeSizeFromParts(chdata, sizedata, targetSize, aStretchHint);
#ifdef NOISY_SEARCH
    char str[50];
    fontName.ToCString(str, sizeof(str));
    printf("    Font %s %s!\n", str, (computedSize) ? "OK" : "Rejected");
#endif
    if (!computedSize) continue; // to next table

    // the computed size is suitable for the available space...
    // now is the time to compute and cache our bounding metrics
    if (isVertical) {
      nscoord lbearing = bmdata[0].leftBearing;
      nscoord rbearing = bmdata[0].rightBearing;
      nscoord width = bmdata[0].width;
      for (i = 1; i < 4; i++) {
        bm = bmdata[i];
        if (width < bm.width) width = bm.width;
        if (lbearing > bm.leftBearing) lbearing = bm.leftBearing;
        if (rbearing < bm.rightBearing) rbearing = bm.rightBearing;
      }
      bestbm.width = width;
      bestbm.ascent = bmdata[0].ascent; // Yes top, so that it works with TeX sqrt!
      bestbm.descent = computedSize - bestbm.ascent;
      bestbm.leftBearing = lbearing;
      bestbm.rightBearing = rbearing;
    }
    else {
      nscoord ascent = bmdata[0].ascent;
      nscoord descent = bmdata[0].descent;
      for (i = 1; i < 4; i++) {
        bm = bmdata[i];
        if (ascent < bm.ascent) ascent = bm.ascent;
        if (descent < bm.descent) descent = bm.descent;
      }
      bestbm.width = computedSize;
      bestbm.ascent = ascent;
      bestbm.descent = descent;
      bestbm.leftBearing = 0;
      bestbm.rightBearing = computedSize;
    }
    // reset
    bestGlyph = kNullGlyph; // this will tell paint to build by parts
    bestGlyphTable = glyphTable;
    goto done; // get out...
  }
#ifdef NOISY_SEARCH
  printf("    No font with suitable parts found\n");
#endif
  // if sum of parts doesn't fit in the space... we will use a single
  // glyph -- the base size or the best glyph encountered during the search

done:
  if (bestGlyph == startingGlyph) { // nothing happened
    // ensure that the char behaves like a normal char
    // (will be reset back to its intrinsic value in case of dynamic updates)
    mDirection = NS_STRETCH_DIRECTION_UNSUPPORTED;
  }
  else {
    // will stretch
    mGlyph = bestGlyph; // note that this can be null to tell paint to build by parts
    mGlyphTable = bestGlyphTable;
    mBoundingMetrics = bestbm;
    aDesiredStretchSize = bestbm;
  }
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Friends And Related Function Documentation

friend class nsGlyphTable [friend]

Definition at line 189 of file nsMathMLChar.h.


Member Data Documentation

nsBoundingMetrics nsMathMLChar::mBoundingMetrics [private]

Definition at line 200 of file nsMathMLChar.h.

Definition at line 190 of file nsMathMLChar.h.

Definition at line 199 of file nsMathMLChar.h.

Definition at line 203 of file nsMathMLChar.h.

Definition at line 202 of file nsMathMLChar.h.

Definition at line 198 of file nsMathMLChar.h.

Definition at line 194 of file nsMathMLChar.h.

Definition at line 197 of file nsMathMLChar.h.

Definition at line 193 of file nsMathMLChar.h.

Definition at line 201 of file nsMathMLChar.h.


The documentation for this class was generated from the following files: