зеркало из https://github.com/mozilla/gecko-dev.git
[not part of default build] Added support for rowalign and columnalign attributes on <mtable>
This commit is contained in:
Родитель
e84aa8aed9
Коммит
d9c12baad9
|
@ -37,12 +37,223 @@
|
|||
#include "nsIFontMetrics.h"
|
||||
#include "nsStyleUtil.h"
|
||||
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsLayoutAtoms.h"
|
||||
#include "nsIFrameManager.h"
|
||||
#include "nsTableOuterFrame.h"
|
||||
#include "nsTableCellFrame.h"
|
||||
|
||||
#include "nsMathMLmtableFrame.h"
|
||||
|
||||
//
|
||||
// <mtable> -- table or matrix - implementation
|
||||
//
|
||||
|
||||
// helper function to perform an in-place split of a space-delimited string,
|
||||
// and return an array of pointers for the beginning of each segment, i.e.,
|
||||
// aOffset[0] is the first string, aOffset[1] is the second string, etc.
|
||||
// Used to parse attributes like columnalign='left right', rowalign='top bottom'
|
||||
static void
|
||||
SplitString(nsString& aString, // [IN/OUT]
|
||||
nsVoidArray& aOffset) // [OUT]
|
||||
{
|
||||
static const PRUnichar kNullCh = PRUnichar('\0');
|
||||
|
||||
aString.Append(kNullCh); // put an extra null at the end
|
||||
|
||||
PRUnichar* start = (PRUnichar*)(const PRUnichar*)aString.GetUnicode();
|
||||
PRUnichar* end = start;
|
||||
|
||||
while (kNullCh != *start) {
|
||||
while ((kNullCh != *start) && nsCRT::IsAsciiSpace(*start)) { // skip leading space
|
||||
start++;
|
||||
}
|
||||
end = start;
|
||||
|
||||
while ((kNullCh != *end) && (PR_FALSE == nsCRT::IsAsciiSpace(*end))) { // look for space or end
|
||||
end++;
|
||||
}
|
||||
*end = kNullCh; // end string here
|
||||
|
||||
if (start < end) {
|
||||
aOffset.AppendElement(start); // record the beginning of this segment
|
||||
}
|
||||
|
||||
start = ++end;
|
||||
}
|
||||
}
|
||||
|
||||
struct nsValueList
|
||||
{
|
||||
nsString mData;
|
||||
nsVoidArray mArray;
|
||||
|
||||
nsValueList(nsString& aData)
|
||||
{
|
||||
mData.Assign(aData);
|
||||
SplitString(mData, mArray);
|
||||
}
|
||||
};
|
||||
|
||||
// Each rowalign='top bottom' or columnalign='left right center' (from
|
||||
// <mtable> or <mtr>) is split once (lazily) into a nsValueList which is
|
||||
// stored in the frame manager. Cell frames query the frame manager
|
||||
// to see what values apply to them.
|
||||
|
||||
// XXX these are essentially temporary hacks until the content model
|
||||
// caters for MathML and the Style System has some provisions for MathML.
|
||||
// This code is not suitable for dynamic updates, for example when the
|
||||
// rowalign and columalign attributes are changed with JavaScript.
|
||||
// The code doesn't include hooks for AttributeChanged() notifications.
|
||||
|
||||
static void
|
||||
DestroyValueListFunc(nsIPresContext* aPresContext,
|
||||
nsIFrame* aFrame,
|
||||
nsIAtom* aPropertyName,
|
||||
void* aPropertyValue)
|
||||
{
|
||||
if (aPropertyValue)
|
||||
{
|
||||
delete (nsValueList *)aPropertyValue;
|
||||
}
|
||||
}
|
||||
|
||||
static PRUnichar*
|
||||
GetAlignValueAt(nsIPresContext* aPresContext,
|
||||
nsIFrame* aTableOrRowFrame,
|
||||
nsIAtom* aAttributeAtom,
|
||||
PRInt32 aIndex)
|
||||
{
|
||||
PRUnichar* result = nsnull;
|
||||
nsValueList* valueList = nsnull;
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
aPresContext->GetShell(getter_AddRefs(presShell));
|
||||
if (presShell)
|
||||
{
|
||||
nsCOMPtr<nsIFrameManager> frameManager;
|
||||
presShell->GetFrameManager(getter_AddRefs(frameManager));
|
||||
if (frameManager)
|
||||
{
|
||||
frameManager->GetFrameProperty(aTableOrRowFrame, aAttributeAtom,
|
||||
0, (void**)&valueList);
|
||||
if (!valueList)
|
||||
{
|
||||
// The property isn't there yet, so set it
|
||||
nsAutoString values;
|
||||
nsCOMPtr<nsIContent> content;
|
||||
aTableOrRowFrame->GetContent(getter_AddRefs(content));
|
||||
if (NS_CONTENT_ATTR_HAS_VALUE == content->GetAttribute(kNameSpaceID_None, aAttributeAtom, values))
|
||||
{
|
||||
valueList = new nsValueList(values);
|
||||
if (valueList)
|
||||
{
|
||||
frameManager->SetFrameProperty(aTableOrRowFrame, aAttributeAtom,
|
||||
valueList, DestroyValueListFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (valueList)
|
||||
{
|
||||
PRInt32 count = valueList->mArray.Count();
|
||||
result = (aIndex < count)
|
||||
? (PRUnichar*)(valueList->mArray[aIndex])
|
||||
: (PRUnichar*)(valueList->mArray[count-1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
MapAlignAttributesInto(nsIPresContext* aPresContext,
|
||||
nsIFrame* aCellFrame,
|
||||
nsIContent* aCellContent)
|
||||
{
|
||||
nsresult rv;
|
||||
PRInt32 index;
|
||||
nsAutoString value;
|
||||
|
||||
nsTableCellFrame* cellFrame;
|
||||
cellFrame = NS_STATIC_CAST(nsTableCellFrame*, aCellFrame);
|
||||
|
||||
nsIFrame* tableFrame;
|
||||
nsIFrame* rowgroupFrame;
|
||||
nsIFrame* rowFrame;
|
||||
|
||||
cellFrame->GetParent(&rowFrame);
|
||||
rowFrame->GetParent(&rowgroupFrame);
|
||||
rowgroupFrame->GetParent(&tableFrame);
|
||||
|
||||
//////////////////////////////////////
|
||||
// update rowalign on the cell
|
||||
|
||||
PRUnichar* rowalign = nsnull;
|
||||
rv = cellFrame->GetRowIndex(index);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// see if the rowalign attribute is not already set
|
||||
nsIAtom* atom = nsMathMLAtoms::rowalign_;
|
||||
rv = aCellContent->GetAttribute(kNameSpaceID_None, atom, value);
|
||||
if (NS_CONTENT_ATTR_NOT_THERE == rv)
|
||||
{
|
||||
// see if the rowalign attribute is specified on the row
|
||||
rowalign = GetAlignValueAt(aPresContext, rowFrame, atom, index);
|
||||
if (!rowalign)
|
||||
{
|
||||
// see if the rowalign attribute is specified on the table
|
||||
rowalign = GetAlignValueAt(aPresContext, tableFrame, atom, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
// update column on the cell
|
||||
|
||||
PRUnichar* columnalign = nsnull;
|
||||
rv = cellFrame->GetColIndex(index);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// see if the columnalign attribute is not already set
|
||||
nsIAtom* atom = nsMathMLAtoms::columnalign_;
|
||||
rv = aCellContent->GetAttribute(kNameSpaceID_None, atom, value);
|
||||
if (NS_CONTENT_ATTR_NOT_THERE == rv)
|
||||
{
|
||||
// see if the columnalign attribute is specified on the row
|
||||
columnalign = GetAlignValueAt(aPresContext, rowFrame, atom, index);
|
||||
if (!columnalign)
|
||||
{
|
||||
// see if the columnalign attribute is specified on the table
|
||||
columnalign = GetAlignValueAt(aPresContext, tableFrame, atom, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// coalesce notifications
|
||||
if (rowalign && columnalign)
|
||||
{
|
||||
value.Assign(rowalign);
|
||||
aCellContent->SetAttribute(kNameSpaceID_None, nsMathMLAtoms::rowalign_,
|
||||
value, PR_FALSE);
|
||||
value.Assign(columnalign);
|
||||
aCellContent->SetAttribute(kNameSpaceID_None, nsMathMLAtoms::columnalign_,
|
||||
value, PR_TRUE);
|
||||
}
|
||||
else if (rowalign)
|
||||
{
|
||||
value.Assign(rowalign);
|
||||
aCellContent->SetAttribute(kNameSpaceID_None, nsMathMLAtoms::rowalign_,
|
||||
value, PR_TRUE);
|
||||
}
|
||||
else if (columnalign)
|
||||
{
|
||||
value.Assign(columnalign);
|
||||
aCellContent->SetAttribute(kNameSpaceID_None, nsMathMLAtoms::columnalign_,
|
||||
value, PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// --------
|
||||
// implementation of nsMathMLmtableOuterFrame
|
||||
|
||||
|
@ -105,11 +316,11 @@ nsMathMLmtableOuterFrame::Reflow(nsIPresContext* aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
// we want to return a table that is centered acoording to the align attribute
|
||||
// we want to return a table that is centered according to the align attribute
|
||||
nsresult rv = nsTableOuterFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
|
||||
// see if the user has set the align attribute on the <mtable>
|
||||
// should we also check <mstyle>
|
||||
// XXX should we also check <mstyle> ?
|
||||
nsAutoString value;
|
||||
PRBool alignAttribute = PR_FALSE;
|
||||
|
||||
|
@ -157,9 +368,24 @@ nsMathMLmtableOuterFrame::Reflow(nsIPresContext* aPresContext,
|
|||
mBoundingMetrics.rightBearing = aDesiredSize.width;
|
||||
|
||||
aDesiredSize.mBoundingMetrics = mBoundingMetrics;
|
||||
|
||||
if ((eReflowReason_Initial == aReflowState.reason) &&
|
||||
(NS_UNCONSTRAINEDSIZE == aReflowState.availableWidth))
|
||||
{
|
||||
// XXX Temporary hack! We are going to reflow again because
|
||||
// the table frame code is skipping the Pass 2 reflow when,
|
||||
// at the Pass 1 reflow, the available size is unconstrained.
|
||||
// Skipping the Pass2 messes the alignments...
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
aPresContext->GetShell(getter_AddRefs(presShell));
|
||||
// ReflowDirtyChild(presShell, mFrames.FirstChild());
|
||||
mParent->ReflowDirtyChild(presShell, this);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// --------
|
||||
// implementation of nsMathMLmtdFrame
|
||||
|
||||
|
@ -192,6 +418,11 @@ nsMathMLmtdFrame::Reflow(nsIPresContext* aPresContext,
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus)
|
||||
{
|
||||
// XXX temp. hack.
|
||||
if (NS_FRAME_FIRST_REFLOW & mState) {
|
||||
MapAlignAttributesInto(aPresContext, mParent, mContent);
|
||||
}
|
||||
|
||||
// Let the base class do the reflow
|
||||
nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#define nsMathMLmtableFrame_h___
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTableOuterFrame.h"
|
||||
#include "nsMathMLContainerFrame.h"
|
||||
|
||||
//
|
||||
|
@ -183,7 +182,7 @@ public:
|
|||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus);
|
||||
|
||||
protected:
|
||||
protected:
|
||||
nsMathMLmtdFrame();
|
||||
virtual ~nsMathMLmtdFrame();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче