Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Documents / RtfToXamlReader.cs / 1305600 / RtfToXamlReader.cs
//----------------------------------------------------------------------------
//
// File: RtfToXamlReader.cs
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// Description: Rtf reader to convert the rtf content into Xaml content.
//
//---------------------------------------------------------------------------
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using System.IO;
using System.Windows.Media; // Color
using Microsoft.Win32; // Registry for font substitutes
using MS.Internal; // Invariant
namespace System.Windows.Documents
{
///
/// Horizontal alignment
///
internal enum HAlign
{
AlignLeft,
AlignRight,
AlignCenter,
AlignJustify,
AlignDefault
};
///
/// Horizontal alignment
///
internal enum VAlign
{
AlignTop,
AlignCenter,
AlignBottom,
};
///
/// Flow direction
///
internal enum DirState
{
DirDefault,
DirLTR,
DirRTL
};
internal enum FontSlot
{
LOCH = 0,
DBCH = 1,
HICH = 2
};
///
/// Underline state
///
internal enum ULState
{
ULNone,
ULNormal,
ULDot,
ULDash,
ULDashDot,
ULDashDotDot,
ULDouble,
ULHeavyWave,
ULLongDash,
ULThick,
ULThickDot,
ULThickDash,
ULThickDashDot,
ULThickDashDotDot,
ULThickLongDash,
ULDoubleWave,
ULWord,
ULWave
};
///
/// Strikethrough state
///
internal enum StrikeState
{
StrikeNone,
StrikeNormal,
StrikeDouble
};
///
/// Document node type
/// WARNING: Keep in [....] with array used by GetTagName
///
internal enum DocumentNodeType
{
dnUnknown = 0,
dnText,
dnInline,
dnLineBreak,
dnHyperlink,
dnParagraph,
dnInlineUIContainer,
dnBlockUIContainer,
dnImage,
dnList,
dnListItem,
dnTable,
dnTableBody,
dnRow,
dnCell,
dnSection,
dnFigure,
dnFloater,
dnFieldBegin,
dnFieldEnd,
dnShape,
dnListText
};
///
/// MarkerStyle
///
internal enum MarkerStyle
{
MarkerNone = -1,
MarkerArabic = 0,
MarkerUpperRoman = 1,
MarkerLowerRoman = 2,
MarkerUpperAlpha = 3,
MarkerLowerAlpha = 4,
MarkerOrdinal = 5,
MarkerCardinal = 6,
MarkerBullet = 23,
MarkerHidden = 255 // pseudo-value for no list text
};
///
/// Converters
///
internal static class Converters
{
internal static double TwipToPx(double twip)
{
return (twip / 1440f) * 96f;
}
internal static double TwipToPositivePx(double twip)
{
double px = (twip / 1440f) * 96f;
if (px < 0)
{
px = 0;
}
return px;
}
internal static double TwipToPositiveVisiblePx(double twip)
{
double px = (twip / 1440f) * 96f;
if (px < 0)
{
px = 0;
}
if (twip > 0.0 && px < 1.0)
{
px = 1.0;
}
return px;
}
internal static string TwipToPxString(double twip)
{
double px = TwipToPx(twip);
return px.ToString("f2", CultureInfo.InvariantCulture);
}
internal static string TwipToPositivePxString(double twip)
{
double px = TwipToPositivePx(twip);
return px.ToString("f2", CultureInfo.InvariantCulture);
}
internal static string TwipToPositiveVisiblePxString(double twip)
{
double px = TwipToPositiveVisiblePx(twip);
return px.ToString("f2", CultureInfo.InvariantCulture);
}
internal static double PxToPt(double px)
{
return (px / 96) * 72f;
}
internal static long PxToTwipRounded(double px)
{
double twip = (px / 96f) * 1440f;
if (twip < 0)
{
return (long)(twip - 0.5);
}
else
{
return (long)(twip + 0.5);
}
}
internal static bool StringToDouble(string s, ref double d)
{
bool ret = true;
d = 0.0;
try
{
d = System.Convert.ToDouble(s, CultureInfo.InvariantCulture);
}
catch (System.OverflowException)
{
ret = false;
}
catch (System.FormatException)
{
ret = false;
}
return ret;
}
internal static bool StringToInt(string s, ref int i)
{
bool ret = true;
i = 0;
try
{
i = System.Convert.ToInt32(s, CultureInfo.InvariantCulture);
}
catch (System.OverflowException)
{
ret = false;
}
catch (System.FormatException)
{
ret = false;
}
return ret;
}
internal static string StringToXMLAttribute(string s)
{
if (s.IndexOf('"') == -1)
{
return s;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
if (s[i] == '"')
{
sb.Append(""");
}
else
{
sb.Append(s[i]);
}
}
return sb.ToString();
}
internal static bool HexStringToInt(string s, ref int i)
{
bool ret = true;
i = 0;
try
{
i = System.Int32.Parse(s, System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture);
}
catch (System.OverflowException)
{
ret = false;
}
catch (System.FormatException)
{
ret = false;
}
return ret;
}
internal static string MarkerStyleToString(MarkerStyle ms)
{
switch (ms)
{
case MarkerStyle.MarkerArabic:
return "Decimal";
case MarkerStyle.MarkerUpperRoman:
return "UpperRoman";
case MarkerStyle.MarkerLowerRoman:
return "LowerRoman";
case MarkerStyle.MarkerUpperAlpha:
return "UpperLatin";
case MarkerStyle.MarkerLowerAlpha:
return "LowerLatin";
case MarkerStyle.MarkerOrdinal:
return "Decimal"; // Note no XAML support
case MarkerStyle.MarkerCardinal:
return "Decimal"; // Note no XAML support
case MarkerStyle.MarkerHidden:
return "None";
case MarkerStyle.MarkerBullet:
return "Disc";
default:
return "Decimal";
}
}
internal static string MarkerStyleToOldRTFString(MarkerStyle ms)
{
switch (ms)
{
case MarkerStyle.MarkerBullet:
// return "\\pnbidia";
// return "\\pnbidib";
return "\\pnlvlblt";
default:
case MarkerStyle.MarkerArabic:
// return "\\pndec";
return "\\pnlvlbody\\pndec";
case MarkerStyle.MarkerCardinal:
return "\\pnlvlbody\\pncard";
case MarkerStyle.MarkerUpperAlpha:
return "\\pnlvlbody\\pnucltr";
case MarkerStyle.MarkerUpperRoman:
return "\\pnlvlbody\\pnucrm";
case MarkerStyle.MarkerLowerAlpha:
return "\\pnlvlbody\\pnlcltr";
case MarkerStyle.MarkerLowerRoman:
return "\\pnlvlbody\\pnlcrm";
case MarkerStyle.MarkerOrdinal:
//return "\\pnlvlbody\\pnordt";
return "\\pnlvlbody\\pnord";
}
}
// Convert FG, BG and shading to produce color to fill with.
// Shading is in 100'ths of a percent (ie, 10000 is 100%)
// A value of zero for shading means use all CB.
// A value of 10000 for shading means use all CF.
// Intermediate values mean some combination of
internal static bool ColorToUse(ConverterState converterState, long cb, long cf, long shade, ref Color c)
{
ColorTableEntry entryCB = cb >= 0 ? converterState.ColorTable.EntryAt((int)cb) : null;
ColorTableEntry entryCF = cf >= 0 ? converterState.ColorTable.EntryAt((int)cf) : null;
// No shading
if (shade < 0)
{
if (entryCB == null)
{
return false;
}
else
{
c = entryCB.Color;
return true;
}
}
// Shading
else
{
Color cCB = entryCB != null ? entryCB.Color : Color.FromArgb(0xFF, 0, 0, 0);
Color cCF = entryCF != null ? entryCF.Color : Color.FromArgb(0xFF, 255, 255, 255);
// No color specifies means shading is treated as a grey intensity.
if (entryCF == null && entryCB == null)
{
c = Color.FromArgb(0xff,
(byte)(255 - (255 * shade / 10000)),
(byte)(255 - (255 * shade / 10000)),
(byte)(255 - (255 * shade / 10000)));
return true;
}
// Only CF means CF fades as shading goes from 10,000 to 0
else if (entryCB == null)
{
c = Color.FromArgb(0xff,
(byte)(cCF.R + ((255 - cCF.R) * (10000 - shade) / 10000)),
(byte)(cCF.G + ((255 - cCF.G) * (10000 - shade) / 10000)),
(byte)(cCF.B + ((255 - cCF.B) * (10000 - shade) / 10000)));
return true;
}
// Only CB means CB gets larger impact (from black ) as shading goes from 10000 to 0
else if (entryCF == null)
{
c = Color.FromArgb(0xff,
(byte)(cCB.R - (cCB.R * shade / 10000)),
(byte)(cCB.G - (cCB.G * shade / 10000)),
(byte)(cCB.B - (cCB.B * shade / 10000)));
return true;
}
// Both - need to mix colors
else
{
c = Color.FromArgb(0xff,
(byte)((cCB.R * (10000 - shade) / 10000) +
(cCF.R * shade / 10000)),
(byte)((cCB.G * (10000 - shade) / 10000) +
(cCF.G * shade / 10000)),
(byte)((cCB.B * (10000 - shade) / 10000) +
(cCF.B * shade / 10000)));
return true;
}
}
}
internal static string AlignmentToString(HAlign a, DirState ds)
{
switch (a)
{
case HAlign.AlignLeft:
return (ds != DirState.DirRTL) ? "Left" : "Right";
case HAlign.AlignRight:
return (ds != DirState.DirRTL) ? "Right" : "Left";
case HAlign.AlignCenter:
return "Center";
case HAlign.AlignJustify:
return "Justify";
case HAlign.AlignDefault:
default:
return "";
}
}
internal static string MarkerCountToString(MarkerStyle ms, long nCount)
{
StringBuilder sb = new StringBuilder();
if (nCount < 0)
{
nCount = 0;
}
switch (ms)
{
case MarkerStyle.MarkerUpperRoman:
case MarkerStyle.MarkerLowerRoman:
{
return MarkerRomanCountToString(sb, ms, nCount);
}
case MarkerStyle.MarkerLowerAlpha:
case MarkerStyle.MarkerUpperAlpha:
{
return MarkerAlphaCountToString(sb, ms, nCount);
}
case MarkerStyle.MarkerArabic:
case MarkerStyle.MarkerOrdinal:
case MarkerStyle.MarkerCardinal:
return nCount.ToString(CultureInfo.InvariantCulture);
case MarkerStyle.MarkerHidden:
case MarkerStyle.MarkerNone:
return "";
case MarkerStyle.MarkerBullet:
default:
return "\\'B7";
}
}
private static string MarkerRomanCountToString(StringBuilder sb, MarkerStyle ms, long nCount)
{
while (nCount >= 1000)
{
sb.Append("M");
nCount -= 1000;
}
// 100's
switch (nCount / 100)
{
case 9:
sb.Append("CM"); break;
case 8:
sb.Append("DCCC"); break;
case 7:
sb.Append("DCC"); break;
case 6:
sb.Append("DC"); break;
case 5:
sb.Append("D"); break;
case 4:
sb.Append("CD"); break;
case 3:
sb.Append("CCC"); break;
case 2:
sb.Append("CC"); break;
case 1:
sb.Append("C"); break;
case 0:
break;
}
nCount = nCount % 100;
// 10's
switch (nCount / 10)
{
case 9:
sb.Append("XC"); break;
case 8:
sb.Append("LXXX"); break;
case 7:
sb.Append("LXX"); break;
case 6:
sb.Append("LX"); break;
case 5:
sb.Append("L"); break;
case 4:
sb.Append("XL"); break;
case 3:
sb.Append("XXX"); break;
case 2:
sb.Append("XX"); break;
case 1:
sb.Append("X"); break;
case 0:
break;
}
nCount = nCount % 10;
// 1's
switch (nCount)
{
case 9:
sb.Append("IX"); break;
case 8:
sb.Append("VIII"); break;
case 7:
sb.Append("VII"); break;
case 6:
sb.Append("VI"); break;
case 5:
sb.Append("V"); break;
case 4:
sb.Append("IV"); break;
case 3:
sb.Append("III"); break;
case 2:
sb.Append("II"); break;
case 1:
sb.Append("I"); break;
case 0:
break;
}
if (ms == MarkerStyle.MarkerUpperRoman)
{
return sb.ToString();
}
else
{
return sb.ToString().ToLower(CultureInfo.InvariantCulture);
}
}
private static string MarkerAlphaCountToString(StringBuilder sb, MarkerStyle ms, long nCount)
{
int toThe1 = 26;
int toThe2 = 676;
int toThe3 = 17576;
int toThe4 = 456976;
char[] ca = new char[1];
int temp;
temp = 0;
while (nCount > toThe4 + toThe3 + toThe2 + toThe1)
{
temp++;
nCount -= toThe4;
}
if (temp > 0)
{
if (temp > 26) temp = 26;
ca[0] = (char)('A' + (temp - 1));
sb.Append(ca);
}
temp = 0;
while (nCount > toThe3 + toThe2 + toThe1)
{
temp++;
nCount -= toThe3;
}
if (temp > 0)
{
ca[0] = (char)('A' + (temp - 1));
sb.Append(ca);
}
temp = 0;
while (nCount > toThe2 + toThe1)
{
temp++;
nCount -= toThe2;
}
if (temp > 0)
{
ca[0] = (char)('A' + (temp - 1));
sb.Append(ca);
}
temp = 0;
while (nCount > toThe1)
{
temp++;
nCount -= toThe1;
}
if (temp > 0)
{
ca[0] = (char)('A' + (temp - 1));
sb.Append(ca);
}
ca[0] = (char)('A' + (nCount - 1));
sb.Append(ca);
if (ms == MarkerStyle.MarkerUpperAlpha)
{
return sb.ToString();
}
else
{
return sb.ToString().ToLower(CultureInfo.InvariantCulture);
}
}
// Convert byte to the hex data(0x3a ==> 0x33 and 0x61)
internal static void ByteToHex(byte byteData, out byte firstHexByte, out byte secondHexByte)
{
firstHexByte = (byte)((byteData >> 4) & 0x0f);
secondHexByte = (byte)(byteData & 0x0f);
// First hex digit
if (firstHexByte >= 0x00 && firstHexByte <= 0x09)
{
firstHexByte += 0x30;
}
else if (firstHexByte >= 0xa && firstHexByte <= 0xf)
{
firstHexByte += 'a' - 0xa;
}
// Second hex digit
if (secondHexByte >= 0x00 && secondHexByte <= 0x09)
{
secondHexByte += 0x30;
}
else if (secondHexByte >= 0xa && secondHexByte <= 0xf)
{
secondHexByte += 'a' - 0xa;
}
}
};
internal static class Validators
{
internal static bool IsValidFontSize(long fs)
{
return fs >= 0 && fs <= 0x7FFF;
}
internal static bool IsValidWidthType(long wt)
{
return wt >= 0 && wt <= 3;
}
internal static long MakeValidShading(long s)
{
if (s > 10000) s = 10000;
return s;
}
internal static long MakeValidBorderWidth(long w)
{
// Word's UI only supports values from 0 to 120. But it will actually render larger
// values, so let's maintain them through the converter (but still have some kind of limit).
if (w < 0)
{
w = 0;
}
if (w > 1440)
{
w = 1440;
}
return w;
}
};
///
/// FormatState
///
internal class FormatState
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
internal FormatState()
{
// Other settings
_dest = RtfDestination.DestNormal;
_stateSkip = 1;
// Font settings
SetCharDefaults();
// Para settings
SetParaDefaults();
// Row settings
SetRowDefaults();
}
internal FormatState(FormatState formatState)
{
// Font settings
Bold = formatState.Bold;
Italic = formatState.Italic;
Engrave = formatState.Engrave;
Shadow = formatState.Shadow;
SCaps = formatState.SCaps;
Outline = formatState.Outline;
Super = formatState.Super;
Sub = formatState.Sub;
SuperOffset = formatState.SuperOffset;
FontSize = formatState.FontSize;
Font = formatState.Font;
CodePage = formatState.CodePage;
CF = formatState.CF;
CB = formatState.CB;
DirChar = formatState.DirChar;
UL = formatState.UL;
Strike = formatState.Strike;
Expand = formatState.Expand;
Lang = formatState.Lang;
LangFE = formatState.LangFE;
LangCur = formatState.LangCur;
FontSlot = formatState.FontSlot;
// Para settings
SB = formatState.SB;
SA = formatState.SA;
FI = formatState.FI;
RI = formatState.RI;
LI = formatState.LI;
SL = formatState.SL;
SLMult = formatState.SLMult;
HAlign = formatState.HAlign;
ILVL = formatState.ILVL;
ITAP = formatState.ITAP;
ILS = formatState.ILS;
DirPara = formatState.DirPara;
CFPara = formatState.CFPara;
CBPara = formatState.CBPara;
ParaShading = formatState.ParaShading;
Marker = formatState.Marker;
IsContinue = formatState.IsContinue;
StartIndex = formatState.StartIndex;
StartIndexDefault = formatState.StartIndexDefault;
IsInTable = formatState.IsInTable;
_pb = formatState.HasParaBorder ? new ParaBorder(formatState.ParaBorder) : null;
// Row settings
// For performance reasons, we don't make a full copy of the Row format information. The implication
// of this is that changes to row format data will propagate back up from nested scopes, which is not
// according to the strict semantics. But in practice, all new rows are explicitly cleared with the
// \trowd keyword, which clears this, so this should be fine.
RowFormat = formatState._rowFormat;
// Other
RtfDestination = formatState.RtfDestination;
IsHidden = formatState.IsHidden;
_stateSkip = formatState.UnicodeSkip;
}
#endregion Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
internal void SetCharDefaults()
{
_fBold = false;
_fItalic = false;
_fEngrave = false;
_fShadow = false;
_fScaps = false;
_fOutline = false;
_fSub = false;
_fSuper = false;
_superOffset = 0;
_fs = 24; // Default for RTF
_font = -1;
_codePage = -1;
_cf = -1;
_cb = -1;
_dirChar = DirState.DirLTR;
_ul = ULState.ULNone;
_strike = StrikeState.StrikeNone;
_expand = 0;
_fHidden = false;
_lang = -1;
_langFE = -1;
_langCur = -1;
_fontSlot = FontSlot.LOCH;
}
internal void SetParaDefaults()
{
_sb = 0;
_sa = 0;
_fi = 0;
_ri = 0;
_li = 0;
_align = HAlign.AlignDefault;
_ilvl = 0;
_pnlvl = 0;
_itap = 0;
_ils = -1;
_dirPara = DirState.DirLTR;
_cbPara = -1;
_nParaShading = -1;
_cfPara = -1;
_marker = MarkerStyle.MarkerNone;
_fContinue = false;
_nStartIndex = -1;
_nStartIndexDefault = -1;
_sl = 0;
_slMult = false;
_pb = null;
_fInTable = false;
}
internal void SetRowDefaults()
{
// Just toss old info
RowFormat = null;
}
internal bool IsEqual(FormatState formatState)
{
return
// Font Settings
Bold == formatState.Bold
&& Italic == formatState.Italic
&& Engrave == formatState.Engrave
&& Shadow == formatState.Shadow
&& SCaps == formatState.SCaps
&& Outline == formatState.Outline
&& Super == formatState.Super
&& Sub == formatState.Sub
&& SuperOffset == formatState.SuperOffset
&& FontSize == formatState.FontSize
&& Font == formatState.Font
&& CodePage == formatState.CodePage
&& CF == formatState.CF
&& CB == formatState.CB
&& DirChar == formatState.DirChar
&& UL == formatState.UL
&& Strike == formatState.Strike
&& Expand == formatState.Expand
&& Lang == formatState.Lang
&& LangFE == formatState.LangFE
&& LangCur == formatState.LangCur
&& FontSlot == formatState.FontSlot
// Para settings
&& SB == formatState.SB
&& SA == formatState.SA
&& FI == formatState.FI
&& RI == formatState.RI
&& LI == formatState.LI
&& HAlign == formatState.HAlign
&& ILVL == formatState.ILVL
&& ITAP == formatState.ITAP
&& ILS == formatState.ILS
&& DirPara == formatState.DirPara
&& CFPara == formatState.CFPara
&& CBPara == formatState.CBPara
&& ParaShading == formatState.ParaShading
&& Marker == formatState.Marker
&& IsContinue == formatState.IsContinue
&& StartIndex == formatState.StartIndex
&& StartIndexDefault == formatState.StartIndexDefault
&& SL == formatState.SL
&& SLMult == formatState.SLMult
&& IsInTable == formatState.IsInTable
// Don't include para borders in this test
// Row Settings
// Don't include row settings in this test.
// Other
&& RtfDestination == formatState.RtfDestination
&& IsHidden == formatState.IsHidden
&& UnicodeSkip == formatState.UnicodeSkip;
}
static internal FormatState EmptyFormatState
{
get
{
if (_fsEmptyState == null)
{
_fsEmptyState = new FormatState();
_fsEmptyState.FontSize = -1;
}
return _fsEmptyState;
}
}
internal string GetBorderAttributeString(ConverterState converterState)
{
if (HasParaBorder)
{
return ParaBorder.GetBorderAttributeString(converterState);
}
else
{
return string.Empty;
}
}
#endregion Internal Methods
//------------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
// Random Stacked Properties
internal RtfDestination RtfDestination
{
get
{
return _dest;
}
set
{
_dest = value;
}
}
internal bool IsHidden
{
get
{
return _fHidden;
}
set
{
_fHidden = value;
}
}
internal bool IsContentDestination
{
get
{
return _dest == RtfDestination.DestNormal
|| _dest == RtfDestination.DestFieldResult
|| _dest == RtfDestination.DestShapeResult
|| _dest == RtfDestination.DestShape
|| _dest == RtfDestination.DestListText;
}
}
// Character Style
internal bool Bold
{
get
{
return _fBold;
}
set
{
_fBold = value;
}
}
internal bool Italic
{
get
{
return _fItalic;
}
set
{
_fItalic = value;
}
}
internal bool Engrave
{
get
{
return _fEngrave;
}
set
{
_fEngrave = value;
}
}
internal bool Shadow
{
get
{
return _fShadow;
}
set
{
_fShadow = value;
}
}
internal bool SCaps
{
get
{
return _fScaps;
}
set
{
_fScaps = value;
}
}
internal bool Outline
{
get
{
return _fOutline;
}
set
{
_fOutline = value;
}
}
internal bool Sub
{
get
{
return _fSub;
}
set
{
_fSub = value;
}
}
internal bool Super
{
get
{
return _fSuper;
}
set
{
_fSuper = value;
}
}
internal long SuperOffset
{
get
{
return _superOffset;
}
set
{
_superOffset = value;
}
}
internal long FontSize
{
get
{
return _fs;
}
set
{
_fs = value;
}
}
internal long Font
{
get
{
return _font;
}
set
{
_font = value;
}
}
internal int CodePage
{
get
{
return _codePage;
}
set
{
_codePage = value;
}
}
internal long CF
{
get
{
return _cf;
}
set
{
_cf = value;
}
}
internal long CB
{
get
{
return _cb;
}
set
{
_cb = value;
}
}
internal DirState DirChar
{
get
{
return _dirChar;
}
set
{
_dirChar = value;
}
}
internal ULState UL
{
get
{
return _ul;
}
set
{
_ul = value;
}
}
internal StrikeState Strike
{
get
{
return _strike;
}
set
{
_strike = value;
}
}
internal long Expand
{
get
{
return _expand;
}
set
{
_expand = value;
}
}
internal long Lang
{
get
{
return _lang;
}
set
{
_lang = value;
}
}
internal long LangFE
{
get
{
return _langFE;
}
set
{
_langFE = value;
}
}
internal long LangCur
{
get
{
return _langCur;
}
set
{
_langCur = value;
}
}
internal FontSlot FontSlot
{
get
{
return _fontSlot;
}
set
{
_fontSlot = value;
}
}
// Paragraph Style
internal long SB
{
get
{
return _sb;
}
set
{
_sb = value;
}
}
internal long SA
{
get
{
return _sa;
}
set
{
_sa = value;
}
}
internal long FI
{
get
{
return _fi;
}
set
{
_fi = value;
}
}
internal long RI
{
get
{
return _ri;
}
set
{
_ri = value;
}
}
internal long LI
{
get
{
return _li;
}
set
{
_li = value;
}
}
internal HAlign HAlign
{
get
{
return _align;
}
set
{
_align = value;
}
}
internal long ILVL
{
get
{
return _ilvl;
}
set
{
if (value >= 0 && value <= MAX_LIST_DEPTH)
{
_ilvl = value;
}
}
}
internal long PNLVL
{
get
{
return _pnlvl;
}
set
{
_pnlvl = value;
}
}
internal long ITAP
{
get
{
return _itap;
}
set
{
if (value >= 0 && value <= MAX_TABLE_DEPTH)
{
_itap = value;
}
}
}
internal long ILS
{
get
{
return _ils;
}
set
{
_ils = value;
}
}
internal DirState DirPara
{
get
{
return _dirPara;
}
set
{
_dirPara = value;
}
}
internal long CFPara
{
get
{
return _cfPara;
}
set
{
_cfPara = value;
}
}
internal long CBPara
{
get
{
return _cbPara;
}
set
{
_cbPara = value;
}
}
internal long ParaShading
{
get
{
return _nParaShading;
}
set
{
_nParaShading = Validators.MakeValidShading(value);
}
}
internal MarkerStyle Marker
{
get
{
return _marker;
}
set
{
_marker = value;
}
}
internal bool IsContinue
{
get
{
return _fContinue;
}
set
{
_fContinue = value;
}
}
internal long StartIndex
{
get
{
return _nStartIndex;
}
set
{
_nStartIndex = value;
}
}
internal long StartIndexDefault
{
get
{
return _nStartIndexDefault;
}
set
{
_nStartIndexDefault = value;
}
}
internal long SL
{
get
{
return _sl;
}
set
{
_sl = value;
}
}
internal bool SLMult
{
get
{
return _slMult;
}
set
{
_slMult = value;
}
}
internal bool IsInTable
{
get
{
return _fInTable;
}
set
{
_fInTable = value;
}
}
internal long TableLevel
{
get
{
if (_fInTable || _itap > 0)
{
return _itap > 0 ? _itap : 1;
}
else
{
return 0;
}
}
}
internal long ListLevel
{
get
{
if (_ils >= 0 || _ilvl > 0)
{
return _ilvl > 0 ? _ilvl + 1 : 1;
}
else if (PNLVL > 0)
{
return PNLVL;
}
else if (_marker != MarkerStyle.MarkerNone)
{
return 1;
}
else
{
return 0;
}
}
}
internal int UnicodeSkip
{
get
{
return _stateSkip;
}
set
{
if (value >= 0 && value < 0xffff)
{
_stateSkip = value;
}
}
}
internal RowFormat RowFormat
{
get
{
// Allocate on access.
if (_rowFormat == null)
{
_rowFormat = new RowFormat();
}
return _rowFormat;
}
set
{
_rowFormat = value;
}
}
internal bool HasRowFormat
{
get
{
return _rowFormat != null;
}
}
internal ParaBorder ParaBorder
{
get
{
if (_pb == null)
{
_pb = new ParaBorder();
}
return _pb;
}
}
internal bool HasParaBorder
{
get
{
return _pb != null && !_pb.IsNone;
}
}
// Image type property
internal RtfImageFormat ImageFormat
{
get
{
return _imageFormat;
}
set
{
_imageFormat = value;
}
}
// Image source name property
internal string ImageSource
{
get
{
return _imageSource;
}
set
{
_imageSource = value;
}
}
// Image width property
internal double ImageWidth
{
get
{
return _imageWidth;
}
set
{
_imageWidth = value;
}
}
// Image height property
internal double ImageHeight
{
get
{
return _imageHeight;
}
set
{
_imageHeight = value;
}
}
// Image width property
internal double ImageScaleWidth
{
get
{
return _imageScaleWidth;
}
set
{
_imageScaleWidth = value;
}
}
// Image height property
internal double ImageScaleHeight
{
get
{
return _imageScaleHeight;
}
set
{
_imageScaleHeight = value;
}
}
// IsImageDataBinary: The default is false that is hex data for image
internal bool IsImageDataBinary
{
get
{
return _isImageDataBinary;
}
set
{
_isImageDataBinary = value;
}
}
// Image stretch property to apply scale factor
internal string ImageStretch
{
get
{
return _imageStretch;
}
set
{
_imageStretch = value;
}
}
// Image stretch direction property to apply scale factor
internal string ImageStretchDirection
{
get
{
return _imageStretchDirection;
}
set
{
_imageStretchDirection = value;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
#region Private Fields
private RtfDestination _dest;
private bool _fBold;
private bool _fItalic;
private bool _fSuper;
private bool _fSub;
private bool _fOutline;
private bool _fEngrave;
private bool _fShadow;
private bool _fScaps;
private long _fs; // Font size in half points
private long _font; // Index into font table
private int _codePage; // Cache of code page from font
private long _superOffset; // Sub/super offset
private long _cf; // Foreground color index
private long _cb; // Background color index
private DirState _dirChar; // Character level direction
private ULState _ul;
private StrikeState _strike;
private long _expand;
private long _lang;
private long _langFE;
private long _langCur;
private FontSlot _fontSlot;
// Para style flags and values
private long _sa; // Space After
private long _sb; // Space Before
private long _li; // Left Indent
private long _ri; // Right Indent
private long _fi; // First Indent
private HAlign _align; // Paragraph alignment
private long _ils; // List override index
private long _ilvl; // 0-based List level
private long _pnlvl; // 1-based old style List level
private long _itap; // Table level
private DirState _dirPara; // Paragraph level direction
private long _cfPara; // Paragraph fill color
private long _cbPara; // Paragraph pattern background color
private long _nParaShading; // Paragraph shading in 100's of a percent
private MarkerStyle _marker; // Type of bullet for old-style RTF
private bool _fContinue; // Continue list numbering? (without number)
private long _nStartIndex; // List start index
private long _nStartIndexDefault; // List start index default value
private long _sl;
private bool _slMult;
private ParaBorder _pb;
private bool _fInTable; // Paragraph is in table
private bool _fHidden; // Hidden text
private int _stateSkip;
private RowFormat _rowFormat;
private static FormatState _fsEmptyState = null;
// Image property fields
private RtfImageFormat _imageFormat;
private string _imageSource;
private double _imageWidth;
private double _imageHeight;
private double _imageScaleWidth;
private double _imageScaleHeight;
private bool _isImageDataBinary;
private string _imageStretch;
private string _imageStretchDirection;
#endregion Private Fields
//-----------------------------------------------------
//
// Private Const
//
//-----------------------------------------------------
#region Private Const
private const int MAX_LIST_DEPTH = 32;
private const int MAX_TABLE_DEPTH = 32;
#endregion Private Const
}
internal enum BorderType
{
BorderNone,
BorderSingle,
BorderDouble
// ... lots more
}
internal class BorderFormat
{
internal BorderFormat()
{
SetDefaults();
}
internal BorderFormat(BorderFormat cb)
{
CF = cb.CF;
Width = cb.Width;
Type = cb.Type;
}
//-----------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
internal long CF
{
get
{
return _cf;
}
set
{
_cf = value;
}
}
internal long Width
{
get
{
return _width;
}
set
{
_width = Validators.MakeValidBorderWidth(value);
}
}
internal long EffectiveWidth
{
get
{
switch (Type)
{
case BorderType.BorderNone: return 0;
case BorderType.BorderDouble: return Width * 2;
default:
case BorderType.BorderSingle: return Width;
}
}
}
internal BorderType Type
{
get
{
return _type;
}
set
{
_type = value;
}
}
internal bool IsNone
{
get
{
return EffectiveWidth <= 0 || Type == BorderType.BorderNone;
}
}
internal string RTFEncoding
{
get
{
StringBuilder sb = new StringBuilder();
if (IsNone)
{
sb.Append("\\brdrnone");
}
else
{
sb.Append("\\brdrs\\brdrw");
sb.Append(EffectiveWidth.ToString(CultureInfo.InvariantCulture));
if (CF >= 0)
{
sb.Append("\\brdrcf");
sb.Append(CF.ToString(CultureInfo.InvariantCulture));
}
}
return sb.ToString();
}
}
static internal BorderFormat EmptyBorderFormat
{
get
{
if (_emptyBorderFormat == null)
{
_emptyBorderFormat = new BorderFormat();
}
return _emptyBorderFormat;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
internal void SetDefaults()
{
_cf = -1;
_width = 0;
_type = BorderType.BorderNone;
}
#endregion Internal Methods
private long _cf;
private long _width;
private BorderType _type;
static private BorderFormat _emptyBorderFormat = null;
}
internal class ParaBorder
{
internal ParaBorder()
{
BorderLeft = new BorderFormat();
BorderTop = new BorderFormat();
BorderRight = new BorderFormat();
BorderBottom = new BorderFormat();
BorderAll = new BorderFormat();
Spacing = 0;
}
internal ParaBorder(ParaBorder pb)
{
BorderLeft = new BorderFormat(pb.BorderLeft);
BorderTop = new BorderFormat(pb.BorderTop);
BorderRight = new BorderFormat(pb.BorderRight);
BorderBottom = new BorderFormat(pb.BorderBottom);
BorderAll = new BorderFormat(pb.BorderAll);
Spacing = pb.Spacing;
}
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal BorderFormat BorderLeft
{
get
{
return _bfLeft;
}
set
{
_bfLeft = value;
}
}
internal BorderFormat BorderTop
{
get
{
return _bfTop;
}
set
{
_bfTop = value;
}
}
internal BorderFormat BorderRight
{
get
{
return _bfRight;
}
set
{
_bfRight = value;
}
}
internal BorderFormat BorderBottom
{
get
{
return _bfBottom;
}
set
{
_bfBottom = value;
}
}
internal BorderFormat BorderAll
{
get
{
return _bfAll;
}
set
{
_bfAll = value;
}
}
internal long Spacing
{
get
{
return _nSpacing;
}
set
{
_nSpacing = value;
}
}
internal long CF
{
get
{
return BorderLeft.CF;
}
set
{
BorderLeft.CF = value;
BorderTop.CF = value;
BorderRight.CF = value;
BorderBottom.CF = value;
BorderAll.CF = value;
}
}
internal bool IsNone
{
get
{
return BorderLeft.IsNone && BorderTop.IsNone
&& BorderRight.IsNone && BorderBottom.IsNone
&& BorderAll.IsNone;
}
}
internal string GetBorderAttributeString(ConverterState converterState)
{
if (IsNone)
{
return string.Empty;
}
// Build the border attribute string based on border values
StringBuilder sb = new StringBuilder();
// Left,Top,Right,Bottom
sb.Append(" BorderThickness=\"");
if (!BorderAll.IsNone)
{
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderAll.EffectiveWidth));
}
else
{
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderLeft.EffectiveWidth));
sb.Append(",");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderTop.EffectiveWidth));
sb.Append(",");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderRight.EffectiveWidth));
sb.Append(",");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderBottom.EffectiveWidth));
}
sb.Append("\"");
ColorTableEntry entry = null;
if (CF >= 0)
{
entry = converterState.ColorTable.EntryAt((int)CF);
}
if (entry != null)
{
sb.Append(" BorderBrush=\"");
sb.Append(entry.Color.ToString());
sb.Append("\"");
}
else
{
sb.Append(" BorderBrush=\"#FF000000\"");
}
if (Spacing != 0)
{
sb.Append(" Padding=\"");
sb.Append(Converters.TwipToPositivePxString(Spacing));
sb.Append("\"");
}
return sb.ToString();
}
internal string RTFEncoding
{
get
{
StringBuilder sb = new StringBuilder();
if (IsNone)
{
sb.Append("\\brdrnil");
}
else
{
sb.Append("\\brdrl");
sb.Append(BorderLeft.RTFEncoding);
if (BorderLeft.CF >= 0)
{
sb.Append("\\brdrcf");
sb.Append(BorderLeft.CF.ToString(CultureInfo.InvariantCulture));
}
sb.Append("\\brdrt");
sb.Append(BorderTop.RTFEncoding);
if (BorderTop.CF >= 0)
{
sb.Append("\\brdrcf");
sb.Append(BorderTop.CF.ToString(CultureInfo.InvariantCulture));
}
sb.Append("\\brdrr");
sb.Append(BorderRight.RTFEncoding);
if (BorderRight.CF >= 0)
{
sb.Append("\\brdrcf");
sb.Append(BorderRight.CF.ToString(CultureInfo.InvariantCulture));
}
sb.Append("\\brdrb");
sb.Append(BorderBottom.RTFEncoding);
if (BorderBottom.CF >= 0)
{
sb.Append("\\brdrcf");
sb.Append(BorderBottom.CF.ToString(CultureInfo.InvariantCulture));
}
sb.Append("\\brsp");
sb.Append(Spacing.ToString(CultureInfo.InvariantCulture));
}
return sb.ToString();
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private BorderFormat _bfLeft;
private BorderFormat _bfTop;
private BorderFormat _bfRight;
private BorderFormat _bfBottom;
private BorderFormat _bfAll;
private long _nSpacing;
#endregion Private Fields
}
internal enum WidthType
{
WidthIgnore = 0,
WidthAuto = 1,
WidthPercent = 2, // Actually 50ths
WidthTwips = 3
}
internal class CellWidth
{
internal CellWidth()
{
Type = WidthType.WidthAuto;
Value = 0;
}
internal CellWidth(CellWidth cw)
{
Type = cw.Type;
Value = cw.Value;
}
internal WidthType Type
{
get
{
return _type;
}
set
{
_type = value;
}
}
internal long Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
internal void SetDefaults()
{
Type = WidthType.WidthAuto;
Value = 0;
}
private WidthType _type;
private long _value;
}
internal class CellFormat
{
internal CellFormat()
{
BorderLeft = new BorderFormat();
BorderRight = new BorderFormat();
BorderBottom = new BorderFormat();
BorderTop = new BorderFormat();
Width = new CellWidth();
SetDefaults();
IsPending = true;
}
internal CellFormat(CellFormat cf)
{
CellX = cf.CellX;
IsCellXSet = cf.IsCellXSet;
Width = new CellWidth(cf.Width);
CB = cf.CB;
CF = cf.CF;
Shading = cf.Shading;
PaddingTop = cf.PaddingTop;
PaddingBottom = cf.PaddingBottom;
PaddingRight = cf.PaddingRight;
PaddingLeft = cf.PaddingLeft;
BorderLeft = new BorderFormat(cf.BorderLeft);
BorderRight = new BorderFormat(cf.BorderRight);
BorderBottom = new BorderFormat(cf.BorderBottom);
BorderTop = new BorderFormat(cf.BorderTop);
SpacingTop = cf.SpacingTop;
SpacingBottom = cf.SpacingBottom;
SpacingRight = cf.SpacingRight;
SpacingLeft = cf.SpacingLeft;
VAlign = VAlign.AlignTop;
IsPending = true;
IsHMerge = cf.IsHMerge;
IsHMergeFirst = cf.IsHMergeFirst;
IsVMerge = cf.IsVMerge;
IsVMergeFirst = cf.IsVMergeFirst;
}
//-----------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal long CB
{
get
{
return _cb;
}
set
{
_cb = value;
}
}
internal long CF
{
get
{
return _cf;
}
set
{
_cf = value;
}
}
internal long Shading
{
get
{
return _nShading;
}
set
{
_nShading = Validators.MakeValidShading(value);
}
}
internal long PaddingLeft
{
get
{
return _padL;
}
set
{
_padL = value;
}
}
internal long PaddingRight
{
get
{
return _padR;
}
set
{
_padR = value;
}
}
internal long PaddingTop
{
get
{
return _padT;
}
set
{
_padT = value;
}
}
internal long PaddingBottom
{
get
{
return _padB;
}
set
{
_padB = value;
}
}
internal BorderFormat BorderTop
{
get
{
return _brdT;
}
set
{
_brdT = value;
}
}
internal BorderFormat BorderBottom
{
get
{
return _brdB;
}
set
{
_brdB = value;
}
}
internal BorderFormat BorderLeft
{
get
{
return _brdL;
}
set
{
_brdL = value;
}
}
internal BorderFormat BorderRight
{
get
{
return _brdR;
}
set
{
_brdR = value;
}
}
internal CellWidth Width
{
get
{
return _width;
}
set
{
_width = value;
}
}
internal long CellX
{
get
{
return _nCellX;
}
set
{
_nCellX = value;
_fCellXSet = true;
}
}
internal bool IsCellXSet
{
get
{
return _fCellXSet;
}
set
{
_fCellXSet = value;
}
}
internal VAlign VAlign
{
set
{
_valign = value;
}
}
internal long SpacingTop
{
get
{
return _spaceT;
}
set
{
_spaceT = value;
}
}
internal long SpacingLeft
{
get
{
return _spaceL;
}
set
{
_spaceL = value;
}
}
internal long SpacingBottom
{
get
{
return _spaceB;
}
set
{
_spaceB = value;
}
}
internal long SpacingRight
{
get
{
return _spaceR;
}
set
{
_spaceR = value;
}
}
internal bool IsPending
{
get
{
return _fPending;
}
set
{
_fPending = value;
}
}
internal bool IsHMerge
{
get
{
return _fHMerge;
}
set
{
_fHMerge = value;
}
}
internal bool IsHMergeFirst
{
get
{
return _fHMergeFirst;
}
set
{
_fHMergeFirst = value;
}
}
internal bool IsVMerge
{
get
{
return _fVMerge;
}
set
{
_fVMerge = value;
}
}
internal bool IsVMergeFirst
{
get
{
return _fVMergeFirst;
}
set
{
_fVMergeFirst = value;
}
}
internal bool HasBorder
{
get
{
return BorderLeft.EffectiveWidth > 0
|| BorderRight.EffectiveWidth > 0
|| BorderTop.EffectiveWidth > 0
|| BorderBottom.EffectiveWidth > 0;
}
}
internal string RTFEncodingForWidth
{
get
{
StringBuilder sb = new StringBuilder();
sb.Append("\\clftsWidth");
int t = (int)Width.Type;
sb.Append(t.ToString(CultureInfo.InvariantCulture));
sb.Append("\\clwWidth");
sb.Append(Width.Value.ToString(CultureInfo.InvariantCulture));
sb.Append("\\cellx");
sb.Append(CellX.ToString(CultureInfo.InvariantCulture));
return sb.ToString();
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
internal void SetDefaults()
{
CellX = -1;
IsCellXSet = false;
Width.SetDefaults();
CB = -1;
CF = -1;
Shading = -1;
PaddingTop = 0;
PaddingBottom = 0;
PaddingRight = 0;
PaddingLeft = 0;
BorderLeft.SetDefaults();
BorderRight.SetDefaults();
BorderBottom.SetDefaults();
BorderTop.SetDefaults();
SpacingTop = 0;
SpacingBottom = 0;
SpacingRight = 0;
SpacingLeft = 0;
VAlign = VAlign.AlignTop;
IsHMerge = false;
IsHMergeFirst = false;
IsVMerge = false;
IsVMergeFirst = false;
}
internal string GetBorderAttributeString(ConverterState converterState)
{
Debug.Assert(HasBorder);
// Build the border attribute string based on border values
StringBuilder sb = new StringBuilder();
// Left,Top,Right,Bottom
sb.Append(" BorderThickness=\"");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderLeft.EffectiveWidth));
sb.Append(",");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderTop.EffectiveWidth));
sb.Append(",");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderRight.EffectiveWidth));
sb.Append(",");
sb.Append(Converters.TwipToPositiveVisiblePxString(BorderBottom.EffectiveWidth));
sb.Append("\"");
// Only grab one color
ColorTableEntry entry = null;
if (BorderLeft.CF >= 0)
{
entry = converterState.ColorTable.EntryAt((int)BorderLeft.CF);
}
if (entry != null)
{
sb.Append(" BorderBrush=\"");
sb.Append(entry.Color.ToString(CultureInfo.InvariantCulture));
sb.Append("\"");
}
else
{
sb.Append(" BorderBrush=\"#FF000000\"");
}
return sb.ToString();
}
internal string GetPaddingAttributeString()
{
// Build the padding attribute string based on padding values
StringBuilder sb = new StringBuilder();
// Left,Top,Right,Bottom
sb.Append(" Padding=\"");
sb.Append(Converters.TwipToPositivePxString(PaddingLeft));
sb.Append(",");
sb.Append(Converters.TwipToPositivePxString(PaddingTop));
sb.Append(",");
sb.Append(Converters.TwipToPositivePxString(PaddingRight));
sb.Append(",");
sb.Append(Converters.TwipToPositivePxString(PaddingBottom));
sb.Append("\"");
return sb.ToString();
}
#endregion Internal Methods
private long _cb;
private long _cf;
private long _nShading;
private long _padT;
private long _padB;
private long _padR;
private long _padL;
private long _spaceT;
private long _spaceB;
private long _spaceR;
private long _spaceL;
private long _nCellX;
private CellWidth _width;
private VAlign _valign;
private BorderFormat _brdL;
private BorderFormat _brdR;
private BorderFormat _brdT;
private BorderFormat _brdB;
private bool _fPending;
private bool _fHMerge;
private bool _fHMergeFirst;
private bool _fVMerge;
private bool _fVMergeFirst;
private bool _fCellXSet;
}
internal class RowFormat
{
internal RowFormat()
{
_rowCellFormat = new CellFormat();
_widthA = new CellWidth();
_widthB = new CellWidth();
_widthRow = new CellWidth();
_cellFormats = new ArrayList();
_dir = DirState.DirLTR;
_nTrgaph = -1;
_nTrleft = 0;
}
internal RowFormat(RowFormat ri)
{
_rowCellFormat = new CellFormat(ri.RowCellFormat);
_cellFormats = new ArrayList();
_widthA = new CellWidth(ri.WidthA);
_widthB = new CellWidth(ri.WidthB);
_widthRow = new CellWidth(ri.WidthRow);
_nTrgaph = ri.Trgaph;
_dir = ri.Dir;
_nTrleft = ri._nTrleft;
for (int i = 0; i < ri.CellCount; i++)
{
_cellFormats.Add(new CellFormat(ri.NthCellFormat(i)));
}
}
//------------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
internal CellFormat RowCellFormat
{
get
{
return _rowCellFormat;
}
}
internal int CellCount
{
get
{
return _cellFormats.Count;
}
}
internal CellFormat TopCellFormat
{
get
{
return CellCount > 0 ? NthCellFormat(CellCount - 1) : null;
}
}
internal CellWidth WidthA
{
get
{
return _widthA;
}
}
internal CellWidth WidthB
{
get
{
return _widthB;
}
}
internal CellWidth WidthRow
{
get
{
return _widthRow;
}
}
internal long Trgaph
{
get
{
return _nTrgaph;
}
set
{
_nTrgaph = value;
}
}
internal long Trleft
{
get
{
return _nTrleft;
}
set
{
_nTrleft = value;
}
}
internal DirState Dir
{
get
{
return _dir;
}
set
{
_dir = value;
}
}
internal bool IsVMerge
{
get
{
for (int i = 0; i < CellCount; i++)
{
if (NthCellFormat(i).IsVMerge)
{
return true;
}
}
return false;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
internal CellFormat NthCellFormat(int n)
{
// If asked for a cell format beyond the bounds specified, just use row defaults.
// This probably indicates malformed content, but makes reading more robust.
if (n < 0 || n >= CellCount)
{
return RowCellFormat;
}
return (CellFormat)_cellFormats[n];
}
internal CellFormat NextCellFormat()
{
_cellFormats.Add(new CellFormat(RowCellFormat));
return TopCellFormat;
}
internal CellFormat CurrentCellFormat()
{
if (CellCount == 0 || !TopCellFormat.IsPending)
{
return NextCellFormat();
}
else
{
return TopCellFormat;
}
}
internal void CanonicalizeWidthsFromRTF()
{
if (CellCount == 0)
{
return;
}
CellFormat cfPrev = null;
long cellx = Trleft;
// Make sure widths and cellx are set up. For merged cells, the first cell in the merged set has
// the real width while the last cell in the merged set has the real CellX. I put the real CellX
// in the first merged cell so I can just use that one.
for (int i = 0; i < CellCount; i++)
{
CellFormat cf = NthCellFormat(i);
// Ignore HMerge Cells
if (cf.IsHMerge)
{
continue;
}
// Grab CellX from last cell in range of merged cells
if (cf.IsHMergeFirst)
{
for (int k = i + 1; k < CellCount; k++)
{
CellFormat cf1 = NthCellFormat(k);
if (cf1.IsHMerge)
{
cf.CellX = cf1.CellX;
}
else
{
break;
}
}
}
if (cf.Width.Value == 0 && cf.IsCellXSet)
{
cf.Width.Type = WidthType.WidthTwips;
cf.Width.Value = (cfPrev == null) ? cf.CellX - Trleft : cf.CellX - cfPrev.CellX;
}
else if (cf.Width.Value > 0 && !cf.IsCellXSet)
{
cellx += cf.Width.Value;
cf.CellX = cellx;
}
cfPrev = cf;
}
// It's also important that CellX be monotonic.
cellx = NthCellFormat(0).CellX;
for (int i = 1; i < CellCount; i++)
{
CellFormat cf = NthCellFormat(i);
if (cf.CellX < cellx)
{
cf.CellX = cellx + 1;
}
cellx = cf.CellX;
}
}
internal void CanonicalizeWidthsFromXaml()
{
long nCellX = Trleft;
for (int i = 0; i < CellCount; i++)
{
CellFormat cf = NthCellFormat(i);
if (cf.Width.Type == WidthType.WidthTwips)
{
nCellX += cf.Width.Value;
}
else
{
nCellX += 1440; // arbitrary - one inch.
}
cf.CellX = nCellX;
}
}
#endregion Internal Methods
private CellFormat _rowCellFormat;
private CellWidth _widthA;
private CellWidth _widthB;
private CellWidth _widthRow;
private ArrayList _cellFormats;
private long _nTrgaph;
private long _nTrleft;
private DirState _dir;
}
internal class MarkerListEntry
{
internal MarkerListEntry()
{
_marker = MarkerStyle.MarkerBullet;
_nILS = -1;
_nStartIndexOverride = -1;
_nStartIndexDefault = -1;
_nVirtualListLevel = -1;
}
internal MarkerStyle Marker
{
get
{
return _marker;
}
set
{
_marker = value;
}
}
internal long StartIndexOverride
{
get
{
return _nStartIndexOverride;
}
set
{
_nStartIndexOverride = value;
}
}
internal long StartIndexDefault
{
get
{
return _nStartIndexDefault;
}
set
{
_nStartIndexDefault = value;
}
}
internal long VirtualListLevel
{
get
{
return _nVirtualListLevel;
}
set
{
_nVirtualListLevel = value;
}
}
internal long StartIndexToUse
{
get
{
return _nStartIndexOverride > 0 ? _nStartIndexOverride : _nStartIndexDefault;
}
}
internal long ILS
{
get
{
return _nILS;
}
set
{
_nILS = value;
}
}
private MarkerStyle _marker;
private long _nStartIndexOverride;
private long _nStartIndexDefault;
private long _nVirtualListLevel;
private long _nILS;
}
internal class MarkerList : ArrayList
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
internal MarkerList()
: base(5)
{
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
internal MarkerListEntry EntryAt(int index)
{
return (MarkerListEntry)this[index];
}
internal void AddEntry(MarkerStyle m, long nILS, long nStartIndexOverride, long nStartIndexDefault, long nLevel)
{
MarkerListEntry entry = new MarkerListEntry();
entry.Marker = m;
entry.StartIndexOverride = nStartIndexOverride;
entry.StartIndexDefault = nStartIndexDefault;
entry.VirtualListLevel = nLevel;
entry.ILS = nILS;
Add(entry);
}
#endregion Internal Methods
}
///
/// FontTableEntry
///
internal class FontTableEntry
{
//-----------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal FontTableEntry()
{
_index = -1;
_codePage = -1;
_charSet = 0;
_bNameSealed = false;
_bPending = true;
}
#endregion Constructors
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal int Index
{
get
{
return _index;
}
set
{
_index = value;
}
}
internal string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
internal bool IsNameSealed
{
get
{
return _bNameSealed;
}
set
{
_bNameSealed = value;
}
}
internal bool IsPending
{
get
{
return _bPending;
}
set
{
_bPending = value;
}
}
internal int CodePage
{
get
{
return _codePage;
}
set
{
_codePage = value;
}
}
internal int CodePageFromCharSet
{
set
{
int cp = CharSetToCodePage(value);
if (cp != 0)
{
CodePage = cp;
}
}
}
internal int CharSet
{
get
{
return _charSet;
}
set
{
_charSet = value;
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
internal static int CharSetToCodePage(int cs)
{
switch (cs)
{
case 0: // ANSI
return 1252; // ANSI means use 1252
case 1: // DEFAULT
return -1; // -1 means use default code page
case 2: // Symbol
return 1252; // Symbol isn't a charset
case 3: // Invalid
return -1; // -1 means use ansicpg
case 77: // Mac
return 10000;
case 78: // Shift JIS - bug in MacWord98J
case 128: // Shift JIS
return 932;
case 129: // Hangul
return 949;
case 130: // Johab
return 1361;
case 134: // GB2312
return 936;
case 136: // Big5
return 950;
case 161: // Greek
return 1253;
case 162: // Turkish
return 1254;
case 163: // Vietnamese
return 1258;
case 177: // Hebrew
return 1255;
case 178: // Arabic
return 1256;
case 179: // Arabic Traditional
return 1256;
case 180: // Arabic user
return 1256;
case 181: // Hebrew user
return 1255;
case 186: // Baltic
return 1257;
case 204: // Russian
return 1251;
case 222: // Thai
return 874;
case 238: // Eastern European
return 1250;
case 254: // PC 437
return 437;
case 255: // OEM
return 850;
default:
return 0;
}
}
internal void ComputePreferredCodePage()
{
int[] CodePageList = {
1252, 932, 949, 1361, 936, 950, 1253, 1254, 1258, 1255, 1256, 1257, 1251, 874, 1250, 437, 850 };
CodePage = 1252;
CharSet = 0;
if (Name != null && Name.Length > 0)
{
byte[] rgBytes = new byte[Name.Length * 6];
char[] rgChars = new char[Name.Length * 6];
for (int i = 0; i < CodePageList.Length; i++)
{
Encoding e = Encoding.GetEncoding(CodePageList[i]);
int cb = e.GetBytes(Name, 0, Name.Length, rgBytes, 0);
int cch = e.GetChars(rgBytes, 0, cb, rgChars, 0);
if (cch == Name.Length)
{
int k = 0;
for (k = 0; k < cch; k++)
{
if (rgChars[k] != Name[k])
{
break;
}
}
// This code page can encode this font name.
if (k == cch)
{
CodePage = CodePageList[i];
CharSet = CodePageToCharSet(CodePage);
break;
}
}
}
// Set the symbol charset for symbol font
if (IsSymbolFont(Name))
{
CharSet = 2 /* Symbol Charset */;
}
}
}
#endregion Internal Methods
//-----------------------------------------------------
//
// Private Methods
//
//-----------------------------------------------------
#region Private Methods
private static int CodePageToCharSet(int cp)
{
switch (cp)
{
case 1252: // ANSI
return 0; // ANSI means use 1252
case 10000: // Mac
return 77;
case 932: // Shift JIS
return 128;
case 949: // Hangul
return 129;
case 1361: // Johab
return 130;
case 936: // GB2312
return 134;
case 950: // Big5
return 136;
case 1253: // Greek
return 161;
case 1254: // Turkish
return 162;
case 1258: // Vietnamese
return 163;
case 1255: // Hebrew
return 177;
case 1256: // Arabic
return 178;
case 1257: // Baltic
return 186;
case 1251: // Russian
return 204;
case 874: // Thai
return 222;
case 1250: // Eastern European
return 238;
case 437: // PC 437
return 254;
case 850: // OEM
return 255;
default:
return 0;
}
}
///
/// Return true if the specified typeface name is the symbol font.
///
private static bool IsSymbolFont(string typefaceName)
{
bool isSymbolFont = false;
Typeface typeface = new Typeface(typefaceName);
if (typeface != null)
{
GlyphTypeface glyphTypeface = typeface.TryGetGlyphTypeface();
if (glyphTypeface != null && glyphTypeface.Symbol)
{
isSymbolFont = true;
}
}
return isSymbolFont;
}
#endregion Private Methods
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private string _name;
private int _index;
private int _codePage;
private int _charSet;
private bool _bNameSealed;
private bool _bPending;
#endregion Private Fields
}
///
/// FontTable that includes the font table.
///
internal class FontTable : ArrayList
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal FontTable()
: base(20)
{
_fontMappings = null;
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
internal FontTableEntry DefineEntry(int index)
{
// Might happen with bad input
FontTableEntry entry = FindEntryByIndex(index);
if (entry != null)
{
// Re-open it
entry.IsPending = true;
entry.Name = null;
return entry;
}
entry = new FontTableEntry();
entry.Index = index;
Add(entry);
return entry;
}
internal FontTableEntry FindEntryByIndex(int index)
{
for (int i = 0; i < Count; i++)
{
FontTableEntry entry = EntryAt(i);
if (entry.Index == index)
{
return entry;
}
}
return null;
}
internal FontTableEntry FindEntryByName(string name)
{
for (int i = 0; i < Count; i++)
{
FontTableEntry entry = EntryAt(i);
if (name.Equals(entry.Name))
{
return entry;
}
}
return null;
}
internal FontTableEntry EntryAt(int index)
{
return (FontTableEntry)this[index];
}
internal int DefineEntryByName(string name)
{
int maxIndex = -1;
for (int i = 0; i < Count; i++)
{
FontTableEntry entry = EntryAt(i);
if (name.Equals(entry.Name))
{
return entry.Index;
}
if (entry.Index > maxIndex)
{
maxIndex = entry.Index;
}
}
// Not there - define one.
FontTableEntry newEntry = new FontTableEntry();
newEntry.Index = maxIndex + 1;
Add(newEntry);
newEntry.Name = name;
return maxIndex + 1;
}
internal void MapFonts()
{
Hashtable map = FontMappings;
for (int i = 0; i < Count; i++)
{
FontTableEntry entry = EntryAt(i);
if (entry.Name != null)
{
string mappedName = (string)map[entry.Name.ToLower(CultureInfo.InvariantCulture)];
if (mappedName != null)
{
entry.Name = mappedName;
}
else
{
int iCP = entry.Name.IndexOf('(');
if (iCP >= 0)
{
while (iCP > 0 && entry.Name[iCP - 1] == ' ')
iCP--;
entry.Name = entry.Name.Substring(0, iCP);
}
}
}
}
}
#endregion Internal Methods
//-----------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal FontTableEntry CurrentEntry
{
get
{
if (Count == 0)
{
return null;
}
// Find Pending Entry
for (int i = Count - 1; i >= 0; i--)
{
FontTableEntry entry = EntryAt(i);
if (entry.IsPending)
{
return entry;
}
}
return EntryAt(Count - 1);
}
}
internal Hashtable FontMappings
{
get
{
if (_fontMappings == null)
{
_fontMappings = new Hashtable();
RegistryKey rk = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
if (rk != null)
{
string[] names = rk.GetValueNames();
foreach (string name in names)
{
string value = (string)rk.GetValue(name);
if (name.Length > 0 && value.Length > 0)
{
string lhs_name = name;
string lhs_tag = string.Empty;
string rhs_name = value;
string rhs_tag = string.Empty;
int i;
i = name.IndexOf(',');
if (i >= 0)
{
lhs_name = name.Substring(0, i);
lhs_tag = name.Substring(i + 1, name.Length - i - 1);
}
i = value.IndexOf(',');
if (i >= 0)
{
rhs_name = value.Substring(0, i);
rhs_tag = value.Substring(i + 1, value.Length - i - 1);
}
if (lhs_name.Length > 0 && rhs_name.Length > 0)
{
bool bAdd = false;
// If both entries specify charset, they must match.
if (lhs_tag.Length > 0 && rhs_tag.Length > 0)
{
if (string.Compare(lhs_tag, rhs_tag, StringComparison.OrdinalIgnoreCase) == 0)
{
bAdd = true;
}
}
// If neither specifies a charset, the tagged (left) entry must be a substring.
else if (lhs_tag.Length == 0 && rhs_tag.Length == 0)
{
if (lhs_name.Length > rhs_name.Length)
{
string s = lhs_name.Substring(0, rhs_name.Length);
if (string.Compare(s, rhs_name, StringComparison.OrdinalIgnoreCase) == 0)
{
bAdd = true;
}
}
}
// If just the name specifies the charset, use it.
else if (lhs_tag.Length > 0 && rhs_tag.Length == 0)
{
bAdd = true;
}
// OK, actually add the mapping.
if (bAdd)
{
// Don't add a new mapping if one exists
string keyname = lhs_name.ToLower(CultureInfo.InvariantCulture);
if (_fontMappings[keyname] == null)
{
_fontMappings.Add(keyname, rhs_name);
}
}
}
}
}
}
}
return _fontMappings;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------
#region Private Fields
Hashtable _fontMappings;
#endregion Private Fields
}
///
/// ColorTableEntry that includes color.
///
internal class ColorTableEntry
{
//-----------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal ColorTableEntry()
{
_color = Color.FromArgb(0xff, 0, 0, 0);
_bAuto = false;
}
#endregion Constructors
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal Color Color
{
get
{
return _color;
}
set
{
_color = value;
}
}
internal bool IsAuto
{
get
{
return _bAuto;
}
set
{
_bAuto = value;
}
}
internal byte Red
{
set
{
_color = Color.FromArgb(0xff, value, _color.G, _color.B);
}
}
internal byte Green
{
set
{
_color = Color.FromArgb(0xff, _color.R, value, _color.B);
}
}
internal byte Blue
{
set
{
_color = Color.FromArgb(0xff, _color.R, _color.G, value);
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private Color _color;
private bool _bAuto;
#endregion Private Fields
}
///
/// ColorTableEntry that includes color table.
///
internal class ColorTable : ArrayList
{
//-----------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
internal ColorTable()
: base(20)
{
_inProgress = false;
}
#endregion Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
internal Color ColorAt(int index)
{
if (index >= 0 && index < Count)
{
return EntryAt(index).Color;
}
else
{
return Color.FromArgb(0xff, 0, 0, 0);
}
}
internal void FinishColor()
{
if (_inProgress)
{
_inProgress = false;
}
else
{
int i = AddColor(Color.FromArgb(0xff, 0, 0, 0));
// Initial unspecified color value is treated as "auto".
EntryAt(i).IsAuto = true;
}
}
internal int AddColor(Color color)
{
// First return existing one
for (int i = 0; i < Count; i++)
{
if (ColorAt(i) == color)
{
return i;
}
}
// OK, need to add one
ColorTableEntry entry = new ColorTableEntry();
entry.Color = color;
Add(entry);
return Count - 1;
}
internal ColorTableEntry EntryAt(int index)
{
if (index >= 0 && index < Count)
{
return (ColorTableEntry)this[index];
}
else
{
return null;
}
}
#endregion Internal Methods
//------------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
internal byte NewRed
{
set
{
ColorTableEntry entry = GetInProgressEntry();
if (entry != null)
{
entry.Red = value;
}
}
}
internal byte NewGreen
{
set
{
ColorTableEntry entry = GetInProgressEntry();
if (entry != null)
{
entry.Green = value;
}
}
}
internal byte NewBlue
{
set
{
ColorTableEntry entry = GetInProgressEntry();
if (entry != null)
{
entry.Blue = value;
}
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Private Methods
//
//------------------------------------------------------
#region Private Methods
private ColorTableEntry GetInProgressEntry()
{
if (_inProgress)
{
return EntryAt(Count - 1);
}
else
{
_inProgress = true;
ColorTableEntry entry = new ColorTableEntry();
Add(entry);
return entry;
}
}
#endregion Private Methods
//-----------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private bool _inProgress;
#endregion Private Fields
}
///
/// ListLevel
///
internal class ListLevel
{
//-----------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal ListLevel()
{
_nStartIndex = 1;
_numberType = MarkerStyle.MarkerArabic;
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
internal long StartIndex
{
get
{
return _nStartIndex;
}
set
{
_nStartIndex = value;
}
}
internal MarkerStyle Marker
{
get
{
return _numberType;
}
set
{
_numberType = value;
}
}
internal FormatState FormatState
{
set
{
_formatState = value;
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private long _nStartIndex;
private MarkerStyle _numberType;
private FormatState _formatState;
#endregion Private Fields
}
///
/// ListLevelTable
///
internal class ListLevelTable : ArrayList
{
//------------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
internal ListLevelTable()
: base(1)
{
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
internal ListLevel EntryAt(int index)
{
// Note - we silently handle out of range index values here since the lookup
// might have been based on the structure of the file or the content of some
// keyword parameter.
if (index > Count)
{
index = Count - 1;
}
return (ListLevel)(Count > index && index >= 0 ? this[index] : null);
}
internal ListLevel AddEntry()
{
ListLevel entry = new ListLevel();
Add(entry);
return entry;
}
#endregion Internal Methods
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal ListLevel CurrentEntry
{
get
{
return Count > 0 ? EntryAt(Count - 1) : null;
}
}
#endregion Internal Properties
}
///
/// ListTableEntry
///
internal class ListTableEntry
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal ListTableEntry()
{
_id = 0;
_templateID = 0;
_levels = new ListLevelTable();
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Properties
//
//------------------------------------------------------
#region Internal Properties
internal long ID
{
get
{
return _id;
}
set
{
_id = value;
}
}
internal long TemplateID
{
set
{
_templateID = value;
}
}
internal bool Simple
{
set
{
_simple = value;
}
}
internal ListLevelTable Levels
{
get
{
return _levels;
}
}
#endregion Internal Properties
//-----------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private long _id;
private long _templateID;
private bool _simple;
private ListLevelTable _levels;
#endregion Private Fields
}
///
/// ListTable
///
internal class ListTable : ArrayList
{
//-----------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal ListTable()
: base(20)
{
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
internal ListTableEntry EntryAt(int index)
{
return (ListTableEntry)this[index];
}
internal ListTableEntry FindEntry(long id)
{
for (int i = 0; i < Count; i++)
{
ListTableEntry entry = EntryAt(i);
if (entry.ID == id)
{
return entry;
}
}
return null;
}
internal ListTableEntry AddEntry()
{
ListTableEntry entry = new ListTableEntry();
Add(entry);
return entry;
}
#endregion Internal Methods
//------------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal ListTableEntry CurrentEntry
{
get
{
return Count > 0 ? EntryAt(Count - 1) : null;
}
}
#endregion Internal Properties
}
///
/// ListOverride
///
internal class ListOverride
{
//------------------------------------------------------
//
// Constructors
//
//-----------------------------------------------------
#region Constructors
internal ListOverride()
{
_id = 0;
_index = 0;
_levels = null;
_nStartIndex = -1;
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal long ID
{
get
{
return _id;
}
set
{
_id = value;
}
}
internal long Index
{
get
{
return _index;
}
set
{
_index = value;
}
}
internal ListLevelTable Levels
{
get
{
return _levels;
}
set
{
_levels = value;
}
}
internal long StartIndex
{
get
{
return _nStartIndex;
}
set
{
_nStartIndex = value;
}
}
#endregion Internal Properties
//------------------------------------------------------
//
// Private Fields
//
//-----------------------------------------------------
#region Private Fields
private long _id;
private long _index;
private long _nStartIndex;
private ListLevelTable _levels;
#endregion Private Fields
}
///
/// ListOverrideTable
///
internal class ListOverrideTable : ArrayList
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal ListOverrideTable()
: base(20)
{
}
#endregion Constructors
//-----------------------------------------------------
//
// Internal Methods
//
//------------------------------------------------------
#region Internal Methods
internal ListOverride EntryAt(int index)
{
return (ListOverride)this[index];
}
internal ListOverride FindEntry(int index)
{
for (int i = 0; i < Count; i++)
{
ListOverride entry = EntryAt(i);
if (entry.Index == index)
{
return entry;
}
}
return null;
}
internal ListOverride AddEntry()
{
ListOverride entry = new ListOverride();
Add(entry);
return entry;
}
#endregion Internal Methods
//-----------------------------------------------------
//
// Internal Properties
//
//-----------------------------------------------------
#region Internal Properties
internal ListOverride CurrentEntry
{
get
{
return Count > 0 ? EntryAt(Count - 1) : null;
}
}
#endregion Internal Properties
}
///
/// DocumentNode
///
internal class DocumentNode
{
//-----------------------------------------------------
//
// Consts
//
//------------------------------------------------------
#region Consts
internal static string[] HtmlNames = new string[]
{
"",
"",
"span",
"br",
"a",
"p",
"ul",
"li",
"table",
"tbody",
"tr",
"td"
};
internal static int[] HtmlLengths = new int[]
{
0, // unknown
0, // text
4, // span
2, // br
1, // a
1, // p
2, // ul
2, // li
5, // table
6, // tbody
2, // tr
2 // td
};
internal static string[] XamlNames = new string[]
{
"",
"",
"Span",
"LineBreak",
"Hyperlink",
"Paragraph",
"InlineUIContainer",
"BlockUIContainer",
"Image",
"List",
"ListItem",
"Table",
"TableRowGroup",
"TableRow",
"TableCell",
"Section",
"Figure",
"Floater",
"Field",
"ListText"
};
#endregion Consts
//-----------------------------------------------------
//
// Constructors
//
//------------------------------------------------------
#region Constructors
internal DocumentNode(DocumentNodeType documentNodeType)
{
_type = documentNodeType;
_bPending = true;
_childCount = 0;
_index = -1;
_dna = null;
_parent = null;
_bTerminated = false;
_bMatched = false;
_bHasMarkerContent = false;
_sCustom = null;
_nRowSpan = 1;
_nColSpan = 1;
_nVirtualListLevel = -1;
_csa = null;
_formatState = new FormatState();
_contentBuilder = new StringBuilder();
}
#endregion Constructors
//------------------------------------------------------
//
// Internal Methods
//
//-----------------------------------------------------
#region Internal Methods
internal void InheritFormatState(FormatState formatState)
{
_formatState = new FormatState(formatState);
// Reset non-inherited properties
_formatState.LI = 0;
_formatState.RI = 0;
_formatState.SB = 0;
_formatState.SA = 0;
_formatState.FI = 0;
_formatState.Marker = MarkerStyle.MarkerNone;
_formatState.CBPara = -1;
}
internal string GetTagName()
{
return XamlNames[(int)Type];
}
internal DocumentNode GetParentOfType(DocumentNodeType parentType)
{
DocumentNode dn = Parent;
while (dn != null && dn.Type != parentType)
{
dn = dn.Parent;
}
return dn;
}
internal int GetTableDepth()
{
DocumentNode dn = Parent;
int nDepth = 0;
while (dn != null)
{
if (dn.Type == DocumentNodeType.dnTable)
{
nDepth++;
}
dn = dn.Parent;
}
return nDepth;
}
internal int GetListDepth()
{
DocumentNode dn = Parent;
int nDepth = 0;
while (dn != null)
{
if (dn.Type == DocumentNodeType.dnList)
{
nDepth++;
}
else if (dn.Type == DocumentNodeType.dnCell)
{
break;
}
dn = dn.Parent;
}
return nDepth;
}
internal void Terminate(ConverterState converterState)
{
if (!IsTerminated)
{
string plaintext = StripInvalidChars(Xaml);
AppendXamlPrefix(converterState);
StringBuilder xamlBuilder = new StringBuilder(Xaml);
xamlBuilder.Append(plaintext);
Xaml = xamlBuilder.ToString();
AppendXamlPostfix(converterState);
IsTerminated = true;
}
}
internal void ConstrainFontPropagation(FormatState fsOrig)
{
// We only output certain font properties at the paragraph level. Ensure the paragraph's formatstate
// only records those properties that are actually written there, so that inline nodes properly
// generate the result.
FormatState.SetCharDefaults();
FormatState.Font = fsOrig.Font;
FormatState.FontSize = fsOrig.FontSize;
FormatState.Bold = fsOrig.Bold;
FormatState.Italic = fsOrig.Italic;
// No, lang can't be written at paragraph level since I have no way of turning it "off", e.g. if
// \lang specified for \par but not for inline text.
// FormatState.LangCur = fsOrig.LangCur;
// No, font color can't be written at paragraph level since I have no way of turning it "off" once
// I've turned it on, so "automatic" color values can't be encoded. I'll just have to skip it here.
// FormatState.CF = fsOrig.CF;
// No, text decorations can't be written at paragraph level since they don't propagate.
// FormatState.UL = fsOrig.UL;
// FormatState.Strike = fsOrig.Strike;
}
internal bool RequiresXamlFontProperties()
{
FormatState fsThis = FormatState;
FormatState fsParent = ParentFormatStateForFont;
return (fsThis.Strike != fsParent.Strike)
|| (fsThis.UL != fsParent.UL)
|| (fsThis.Font != fsParent.Font && fsThis.Font >= 0)
|| (fsThis.FontSize != fsParent.FontSize && fsThis.FontSize >= 0)
|| (fsThis.CF != fsParent.CF)
|| (fsThis.Bold != fsParent.Bold)
|| (fsThis.Italic != fsParent.Italic)
|| (fsThis.LangCur != fsParent.LangCur);
}
internal void AppendXamlFontProperties(ConverterState converterState, StringBuilder sb)
{
FormatState fsThis = FormatState;
FormatState fsParent = ParentFormatStateForFont;
bool bStrike = fsThis.Strike != fsParent.Strike;
bool bUL = fsThis.UL != fsParent.UL;
if (bStrike || bUL)
{
sb.Append(" TextDecorations=\"");
if (bUL)
{
sb.Append("Underline");
}
if (bUL && bStrike)
{
sb.Append(", ");
}
if (bStrike)
{
sb.Append("Strikethrough");
}
sb.Append("\"");
}
if (fsThis.Font != fsParent.Font && fsThis.Font >= 0)
{
FontTableEntry entry = converterState.FontTable.FindEntryByIndex((int)fsThis.Font);
if (entry != null && entry.Name != null && !(entry.Name.Equals(string.Empty)))
{
sb.Append(" FontFamily=\"");
// FontFamily should be limited with LF_FACESIZE(32) characters,
// because GDI doesn't support fonts that have the name with more than
// LF_FACESIZE characters.
if (entry.Name.Length > 32)
{
sb.Append(entry.Name, 0, 32);
}
else
{
sb.Append(entry.Name);
}
sb.Append("\"");
}
}
if (fsThis.FontSize != fsParent.FontSize && fsThis.FontSize >= 0)
{
sb.Append(" FontSize=\"");
double fs = (double)fsThis.FontSize;
if (fs <= 1f)
{
fs = 2f;
}
sb.Append((fs / 2).ToString(CultureInfo.InvariantCulture));
sb.Append("pt\"");
}
if (fsThis.Bold != fsParent.Bold)
{
if (fsThis.Bold)
{
sb.Append(" FontWeight=\"Bold\"");
}
else
{
sb.Append(" FontWeight=\"Normal\"");
}
}
if (fsThis.Italic != fsParent.Italic)
{
if (fsThis.Italic)
{
sb.Append(" FontStyle=\"Italic\"");
}
else
{
sb.Append(" FontStyle=\"Normal\"");
}
}
if (fsThis.CF != fsParent.CF)
{
ColorTableEntry entry = converterState.ColorTable.EntryAt((int)fsThis.CF);
if (entry != null && !entry.IsAuto)
{
sb.Append(" Foreground=\"");
sb.Append(entry.Color.ToString());
sb.Append("\"");
}
}
// NB: 0x400 (1024) is reserved value for "lidNoProof" - not a real language code.
if (fsThis.LangCur != fsParent.LangCur && fsThis.LangCur > 0 && fsThis.LangCur != 0x400)
{
try
{
CultureInfo ci = new CultureInfo((int)fsThis.LangCur);
sb.Append(" xml:lang=\"");
sb.Append(ci.Name);
sb.Append("\"");
}
catch (System.ArgumentException)
{
// Just omit xml:lang tag if this is not a valid value.
}
}
}
internal string StripInvalidChars(string text)
{
if (text == null || text.Length == 0)
{
return text;
}
StringBuilder sb = null;
int i = 0;
for (; i < text.Length; i++)
{
int iStart = i;
for (; i < text.Length; i++)
{
if ((text[i] & 0xF800) == 0xD800) // if surrogate
{
if ((i + 1 == text.Length) // and no trail char
|| ((text[i] & 0xFC00) == 0xDC00) // or low surrogate occurs before high
|| ((text[i + 1] & 0xFC00) != 0xDC00) // or high not followed by low
)
{
break; // then cull this
}
else
{
i++; // move past first word of surrogate, then second at top of loop`
}
}
}
if (iStart != 0 || i != text.Length)
{
if (sb == null)
{
sb = new StringBuilder();
}
if (i != iStart)
{
sb.Append(text, iStart, i - iStart);
}
}
}
if (sb != null)
{
return sb.ToString();
}
else
{
return text;
}
}
internal void AppendXamlEncoded(string text)
{
StringBuilder xamlStringBuilder = new StringBuilder(Xaml);
int index = 0;
while (index < text.Length)
{
int currentIndex = index;
while (currentIndex < text.Length)
{
if (text[currentIndex] < 32
&& text[currentIndex] != '\t')
{
break;
}
if (text[currentIndex] == '&'
|| text[currentIndex] == '>'
|| text[currentIndex] == '<'
|| text[currentIndex] == 0)
{
break;
}
currentIndex++;
}
if (currentIndex != index)
{
string substring = text.Substring(index, currentIndex - index);
xamlStringBuilder.Append(substring);
}
if (currentIndex < text.Length)
{
if (text[currentIndex] < 32 && text[currentIndex] != '\t')
{
switch (text[currentIndex])
{
case '\f': // formfeed
xamlStringBuilder.Append("");
int ic = (int)text[currentIndex];
xamlStringBuilder.Append(ic.ToString("x", CultureInfo.InvariantCulture));
xamlStringBuilder.Append(";");
break;
default:
// don't care about low ANSI values - not supported by XAML
break;
}
}
else
{
switch (text[currentIndex])
{
case '&': xamlStringBuilder.Append("&"); break;
case '<': xamlStringBuilder.Append("<"); break;
case '>': xamlStringBuilder.Append(">"); break;
case (char)0: break;
}
}
}
index = currentIndex + 1;
}
Xaml = xamlStringBuilder.ToString();
}
internal void AppendXamlPrefix(ConverterState converterState)
{
DocumentNodeArray dna = converterState.DocumentNodeArray;
if (IsHidden)
{
return;
}
if (Type == DocumentNodeType.dnImage)
{
// Append image xaml prefix
AppendImageXamlPrefix();
return;
}
if (Type == DocumentNodeType.dnText || Type == DocumentNodeType.dnInline)
{
AppendInlineXamlPrefix(converterState);
return;
}
StringBuilder xamlStringBuilder = new StringBuilder();
// Do I need to wrap a font around this?
if (IsEmptyNode && RequiresXamlFontProperties())
{
xamlStringBuilder.Append("<");
xamlStringBuilder.Append(XamlNames[(int)DocumentNodeType.dnInline]);
AppendXamlFontProperties(converterState, xamlStringBuilder);
xamlStringBuilder.Append(">");
}
xamlStringBuilder.Append("<");
xamlStringBuilder.Append(GetTagName());
switch (Type)
{
case DocumentNodeType.dnTable:
// See below for writing out table column information
AppendXamlPrefixTableProperties(xamlStringBuilder);
break;
case DocumentNodeType.dnCell:
// Row stores cell properties.
AppendXamlPrefixCellProperties(xamlStringBuilder, dna, converterState);
break;
case DocumentNodeType.dnParagraph:
AppendXamlPrefixParagraphProperties(xamlStringBuilder, converterState);
break;
case DocumentNodeType.dnListItem:
// List margins are handled at the paragraph level
AppendXamlPrefixListItemProperties(xamlStringBuilder);
break;
case DocumentNodeType.dnList:
// List margins are handled at the listitem level
AppendXamlPrefixListProperties(xamlStringBuilder);
break;
case DocumentNodeType.dnHyperlink:
AppendXamlPrefixHyperlinkProperties(xamlStringBuilder);
break;
}
if (IsEmptyNode)
{
xamlStringBuilder.Append(" /");
}
xamlStringBuilder.Append(">");
// Do I need to wrap a font around this?
if (IsEmptyNode && RequiresXamlFontProperties())
{
xamlStringBuilder.Append("");
xamlStringBuilder.Append(XamlNames[(int)DocumentNodeType.dnInline]);
xamlStringBuilder.Append(">");
}
// Anything after the start tag?
switch (Type)
{
case DocumentNodeType.dnTable:
AppendXamlTableColumnsAfterStartTag(xamlStringBuilder);
break;
}
Xaml = xamlStringBuilder.ToString();
}
private void AppendXamlPrefixTableProperties(StringBuilder xamlStringBuilder)
{
// See below for writing out table column information
if (FormatState.HasRowFormat)
{
if (FormatState.RowFormat.Dir == DirState.DirRTL)
{
xamlStringBuilder.Append(" FlowDirection=\"RightToLeft\"");
}
RowFormat rf = FormatState.RowFormat;
CellFormat cf = rf.RowCellFormat;
xamlStringBuilder.Append(" CellSpacing=\"");
xamlStringBuilder.Append(Converters.TwipToPositiveVisiblePxString(cf.SpacingLeft));
xamlStringBuilder.Append("\"");
xamlStringBuilder.Append(" Margin=\"");
xamlStringBuilder.Append(Converters.TwipToPositivePxString(rf.Trleft));
xamlStringBuilder.Append(",0,0,0\"");
}
else
{
xamlStringBuilder.Append(" CellSpacing=\"0\" Margin=\"0,0,0,0\"");
}
}
private void AppendXamlPrefixCellProperties(StringBuilder xamlStringBuilder, DocumentNodeArray dna, ConverterState converterState)
{
Color cToUse = Color.FromArgb(0xff, 0, 0, 0);
// Row stores cell properties.
DocumentNode dnRow = GetParentOfType(DocumentNodeType.dnRow);
Debug.Assert(dnRow != null); // Need row
Debug.Assert(dnRow != null && !dnRow.IsPending); // Row props attached when row is closed
Debug.Assert(dnRow != null && dnRow.FormatState.RowFormat != null);
if (dnRow != null && dnRow.FormatState.HasRowFormat)
{
int nCol = GetCellColumn();
CellFormat cf = dnRow.FormatState.RowFormat.NthCellFormat(nCol);
if (Converters.ColorToUse(converterState, cf.CB, cf.CF, cf.Shading, ref cToUse))
{
xamlStringBuilder.Append(" Background=\"");
xamlStringBuilder.Append(cToUse.ToString(CultureInfo.InvariantCulture));
xamlStringBuilder.Append("\"");
}
if (cf.HasBorder)
{
xamlStringBuilder.Append(cf.GetBorderAttributeString(converterState));
}
xamlStringBuilder.Append(cf.GetPaddingAttributeString());
}
else
xamlStringBuilder.Append(" BorderBrush=\"#FF000000\" BorderThickness=\"1,1,1,1\"");
if (ColSpan > 1)
{
xamlStringBuilder.Append(" ColumnSpan=\"");
xamlStringBuilder.Append(ColSpan.ToString(CultureInfo.InvariantCulture));
xamlStringBuilder.Append("\"");
}
if (RowSpan > 1)
{
xamlStringBuilder.Append(" RowSpan=\"");
xamlStringBuilder.Append(RowSpan.ToString(CultureInfo.InvariantCulture));
xamlStringBuilder.Append("\"");
}
}
private void AppendXamlDir(StringBuilder xamlStringBuilder)
{
if (RequiresXamlDir)
{
if (XamlDir == DirState.DirLTR)
{
xamlStringBuilder.Append(" FlowDirection=\"LeftToRight\"");
}
else
{
xamlStringBuilder.Append(" FlowDirection=\"RightToLeft\"");
}
}
}
private void AppendXamlPrefixParagraphProperties(StringBuilder xamlStringBuilder, ConverterState converterState)
{
Color cToUse = Color.FromArgb(0xff, 0, 0, 0);
FormatState fsThis = FormatState;
if (Converters.ColorToUse(converterState, fsThis.CBPara, fsThis.CFPara, fsThis.ParaShading, ref cToUse))
{
xamlStringBuilder.Append(" Background=\"");
xamlStringBuilder.Append(cToUse.ToString(CultureInfo.InvariantCulture));
xamlStringBuilder.Append("\"");
}
// Handle paragraph direction
AppendXamlDir(xamlStringBuilder);
// Handle paragraph margins
xamlStringBuilder.Append(" Margin=\"");
xamlStringBuilder.Append(Converters.TwipToPositivePxString(NearMargin));
xamlStringBuilder.Append(",");
xamlStringBuilder.Append(Converters.TwipToPositivePxString(fsThis.SB));
xamlStringBuilder.Append(",");
xamlStringBuilder.Append(Converters.TwipToPositivePxString(FarMargin));
xamlStringBuilder.Append(",");
xamlStringBuilder.Append(Converters.TwipToPositivePxString(fsThis.SA));
xamlStringBuilder.Append("\"");
// FontFamily, Size, Bold, Italic
AppendXamlFontProperties(converterState, xamlStringBuilder);
// Lineheight
// NB: Avalon only supports "lineheight exact" - we're just not going to output it.
//if (fsThis.SL != 0)
//{
// double px = (float)fsThis.SL;
// if (px < 0) px = -px;
// Whether SLMult is on or not is really moot. The value is always defined in twips,
// the UI is the only thing that then interprets this as "multiple", probably when the
// paragraph font is reset.
// xamlStringBuilder.Append(" LineHeight=\"");
// xamlStringBuilder.Append(Converters.TwipToPxString(px));
// xamlStringBuilder.Append("\"");
//}
// Indent
if (fsThis.FI != 0)
{
xamlStringBuilder.Append(" TextIndent=\"");
xamlStringBuilder.Append(Converters.TwipToPxString(fsThis.FI));
xamlStringBuilder.Append("\"");
}
// Handle paragraph alignment
if (fsThis.HAlign != HAlign.AlignDefault)
{
xamlStringBuilder.Append(" TextAlignment=\"");
xamlStringBuilder.Append(Converters.AlignmentToString(fsThis.HAlign, fsThis.DirPara));
xamlStringBuilder.Append("\"");
}
// Handle paragraph borders
if (fsThis.HasParaBorder)
{
xamlStringBuilder.Append(fsThis.GetBorderAttributeString(converterState));
}
}
private void AppendXamlPrefixListItemProperties(StringBuilder xamlStringBuilder)
{
// List margins are handled here normally.
// NB: Avalon doesn't render list markers if margin is zero. Enforce a minimum indent in order
// to ensure the marker is visible.
long lMargin = NearMargin;
if (lMargin < 360 && this.GetListDepth() == 1)
{
DocumentNode dnList = Parent;
if (dnList != null && dnList.FormatState.Marker != MarkerStyle.MarkerHidden)
{
lMargin = 360;
}
}
xamlStringBuilder.Append(" Margin=\"");
xamlStringBuilder.Append(Converters.TwipToPositivePxString(lMargin));
xamlStringBuilder.Append(",0,0,0\"");
// Handle direction
AppendXamlDir(xamlStringBuilder);
}
private void AppendXamlPrefixListProperties(StringBuilder xamlStringBuilder)
{
// List margins are handled at the listitem level
xamlStringBuilder.Append(" Margin=\"0,0,0,0\"");
xamlStringBuilder.Append(" Padding=\"0,0,0,0\"");
// Marker style
xamlStringBuilder.Append(" MarkerStyle=\"");
xamlStringBuilder.Append(Converters.MarkerStyleToString(FormatState.Marker));
xamlStringBuilder.Append("\"");
// Note that we don't allow a value of zero here, since XAML doesn't support it.
if (FormatState.StartIndex > 0 && FormatState.StartIndex != 1)
{
xamlStringBuilder.Append(" StartIndex=\"");
xamlStringBuilder.Append(FormatState.StartIndex.ToString(CultureInfo.InvariantCulture));
xamlStringBuilder.Append("\"");
}
// Handle direction
AppendXamlDir(xamlStringBuilder);
}
private void AppendXamlPrefixHyperlinkProperties(StringBuilder xamlStringBuilder)
{
if (NavigateUri != null && NavigateUri.Length > 0)
{
xamlStringBuilder.Append(" NavigateUri=\"");
xamlStringBuilder.Append(Converters.StringToXMLAttribute(NavigateUri));
xamlStringBuilder.Append("\"");
}
}
private void AppendXamlTableColumnsAfterStartTag(StringBuilder xamlStringBuilder)
{
if (ColumnStateArray != null && ColumnStateArray.Count > 0)
{
xamlStringBuilder.Append("Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- OpacityConverter.cs
- MsmqSecureHashAlgorithm.cs
- SortFieldComparer.cs
- CompiledQueryCacheKey.cs
- AccessibilityHelperForXpWin2k3.cs
- SqlCrossApplyToCrossJoin.cs
- Location.cs
- RadioButtonStandardAdapter.cs
- CommandID.cs
- UIPermission.cs
- WebUtil.cs
- BuildProviderAppliesToAttribute.cs
- SourceFileBuildProvider.cs
- AppDomain.cs
- UrlPath.cs
- DataServiceExpressionVisitor.cs
- Thumb.cs
- SpecialNameAttribute.cs
- FileDialog_Vista.cs
- ResourcePool.cs
- KeyedQueue.cs
- GridViewColumn.cs
- KeyValueSerializer.cs
- TemplatePropertyEntry.cs
- RepeatBehavior.cs
- ClientData.cs
- SafeRightsManagementHandle.cs
- QueryStack.cs
- TextRenderer.cs
- ColorInterpolationModeValidation.cs
- DataGridViewButtonCell.cs
- GPPOINT.cs
- AlgoModule.cs
- LongCountAggregationOperator.cs
- StandardCommandToolStripMenuItem.cs
- ClientType.cs
- UITypeEditor.cs
- EdmComplexPropertyAttribute.cs
- SafeArrayTypeMismatchException.cs
- ItemsControlAutomationPeer.cs
- HwndKeyboardInputProvider.cs
- LocatorManager.cs
- PreviewPageInfo.cs
- OdbcParameterCollection.cs
- ScrollPattern.cs
- RoleManagerModule.cs
- SafeBuffer.cs
- Trace.cs
- SID.cs
- StaticResourceExtension.cs
- QilValidationVisitor.cs
- ErrorFormatterPage.cs
- ListParagraph.cs
- Documentation.cs
- PartialCachingControl.cs
- DrawingCollection.cs
- WmiEventSink.cs
- DisplayMemberTemplateSelector.cs
- ExtensionWindowHeader.cs
- TogglePattern.cs
- UIElementParaClient.cs
- InheritedPropertyChangedEventArgs.cs
- GraphicsPathIterator.cs
- DeferredReference.cs
- UIInitializationException.cs
- EnumConverter.cs
- DependencyPropertyConverter.cs
- EditingCommands.cs
- errorpatternmatcher.cs
- COMException.cs
- TaskCanceledException.cs
- SvcMapFile.cs
- OleTxTransaction.cs
- IntSecurity.cs
- HandleCollector.cs
- SystemIPInterfaceProperties.cs
- ScrollViewerAutomationPeer.cs
- AsyncResult.cs
- SqlUtils.cs
- FileLogRecordStream.cs
- UnionQueryOperator.cs
- DataSourceCacheDurationConverter.cs
- VersionConverter.cs
- XmlObjectSerializerReadContextComplexJson.cs
- PrintPageEvent.cs
- FileStream.cs
- DataControlFieldCell.cs
- X509DefaultServiceCertificateElement.cs
- TextBox.cs
- TimeZone.cs
- SynchronizedInputPattern.cs
- FlowSwitch.cs
- GcHandle.cs
- DoWorkEventArgs.cs
- TextTrailingCharacterEllipsis.cs
- ProfilePropertyNameValidator.cs
- _KerberosClient.cs
- ActivityTypeCodeDomSerializer.cs
- ISFClipboardData.cs
- Mappings.cs