123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510 |
- // Copyright (c) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Xml.Linq;
- using DocumentFormat.OpenXml.Packaging;
- using System.Drawing;
- namespace OpenXmlPowerTools
- {
- public class FormattingAssemblerSettings
- {
- public bool RemoveStyleNamesFromParagraphAndRunProperties;
- public bool ClearStyles;
- public bool OrderElementsPerStandard;
- public bool CreateHtmlConverterAnnotationAttributes;
- public bool RestrictToSupportedNumberingFormats;
- public bool RestrictToSupportedLanguages;
- public ListItemRetrieverSettings ListItemRetrieverSettings;
- public FormattingAssemblerSettings()
- {
- RemoveStyleNamesFromParagraphAndRunProperties = true;
- ClearStyles = true;
- OrderElementsPerStandard = true;
- CreateHtmlConverterAnnotationAttributes = true;
- RestrictToSupportedNumberingFormats = false;
- RestrictToSupportedLanguages = false;
- ListItemRetrieverSettings = new ListItemRetrieverSettings();
- }
- }
- public static class FormattingAssembler
- {
- public static WmlDocument AssembleFormatting(WmlDocument document, FormattingAssemblerSettings settings)
- {
- using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(document))
- {
- using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
- {
- AssembleFormatting(doc, settings);
- }
- return streamDoc.GetModifiedWmlDocument();
- }
- }
- public static void AssembleFormatting(WordprocessingDocument wDoc, FormattingAssemblerSettings settings)
- {
- FormattingAssemblerInfo fai = new FormattingAssemblerInfo();
- XDocument sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- XElement defaultParagraphStyle = sXDoc
- .Root
- .Elements(W.style)
- .FirstOrDefault(st => st.Attribute(W._default).ToBoolean() == true &&
- (string)st.Attribute(W.type) == "paragraph");
- if (defaultParagraphStyle != null)
- fai.DefaultParagraphStyleName = (string)defaultParagraphStyle.Attribute(W.styleId);
- XElement defaultCharacterStyle = sXDoc
- .Root
- .Elements(W.style)
- .FirstOrDefault(st => st.Attribute(W._default).ToBoolean() == true &&
- (string)st.Attribute(W.type) == "character");
- if (defaultCharacterStyle != null)
- fai.DefaultCharacterStyleName = (string)defaultCharacterStyle.Attribute(W.styleId);
- XElement defaultTableStyle = sXDoc
- .Root
- .Elements(W.style)
- .FirstOrDefault(st => st.Attribute(W._default).ToBoolean() == true &&
- (string)st.Attribute(W.type) == "table");
- if (defaultTableStyle != null)
- fai.DefaultTableStyleName = (string)defaultTableStyle.Attribute(W.styleId);
- ListItemRetrieverSettings listItemRetrieverSettings = new ListItemRetrieverSettings();
- AssembleListItemInformation(wDoc, settings.ListItemRetrieverSettings);
- foreach (var part in wDoc.ContentParts())
- {
- var pxd = part.GetXDocument();
- FixNonconformantHexValues(pxd.Root);
- AnnotateWithGlobalDefaults(wDoc, pxd.Root, settings);
- AnnotateTablesWithTableStyles(wDoc, pxd.Root);
- AnnotateParagraphs(fai, wDoc, pxd.Root, settings);
- AnnotateRuns(fai, wDoc, pxd.Root, settings);
- }
- NormalizeListItems(fai, wDoc, settings);
- if (settings.ClearStyles)
- ClearStyles(wDoc);
- foreach (var part in wDoc.ContentParts())
- {
- var pxd = part.GetXDocument();
- pxd.Root.Descendants().Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
- FormattingAssembler.NormalizePropsForPart(pxd, settings);
- var newRoot = (XElement)CleanupTransform(pxd.Root);
- pxd.Root.ReplaceWith(newRoot);
- part.PutXDocument();
- }
- }
- private static void FixNonconformantHexValues(XElement root)
- {
- foreach (var tblLook in root.Descendants(W.tblLook))
- {
- if (tblLook.Attributes().Any(a => a.Name != W.val))
- continue;
- if (tblLook.Attribute(W.val) == null)
- continue;
- string hexValue = tblLook.Attribute(W.val).Value;
- int val = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);
- tblLook.Add(new XAttribute(W.firstRow, (val & 0x0020) != 0 ? "1" : "0"));
- tblLook.Add(new XAttribute(W.lastRow, (val & 0x0040) != 0 ? "1" : "0"));
- tblLook.Add(new XAttribute(W.firstColumn, (val & 0x0080) != 0 ? "1" : "0"));
- tblLook.Add(new XAttribute(W.lastColumn, (val & 0x0100) != 0 ? "1" : "0"));
- tblLook.Add(new XAttribute(W.noHBand, (val & 0x0200) != 0 ? "1" : "0"));
- tblLook.Add(new XAttribute(W.noVBand, (val & 0x0400) != 0 ? "1" : "0"));
- }
- foreach (var cnfStyle in root.Descendants(W.cnfStyle))
- {
- if (cnfStyle.Attributes().Any(a => a.Name != W.val))
- continue;
- if (cnfStyle.Attribute(W.val) == null)
- continue;
- var va = cnfStyle.Attribute(W.val).Value.ToArray();
- cnfStyle.Add(new XAttribute(W.firstRow, va[0]));
- cnfStyle.Add(new XAttribute(W.lastRow, va[1]));
- cnfStyle.Add(new XAttribute(W.firstColumn, va[2]));
- cnfStyle.Add(new XAttribute(W.lastColumn, va[3]));
- cnfStyle.Add(new XAttribute(W.oddVBand, va[4]));
- cnfStyle.Add(new XAttribute(W.evenVBand, va[5]));
- cnfStyle.Add(new XAttribute(W.oddHBand, va[6]));
- cnfStyle.Add(new XAttribute(W.evenHBand, va[7]));
- cnfStyle.Add(new XAttribute(W.firstRowLastColumn, va[8]));
- cnfStyle.Add(new XAttribute(W.firstRowFirstColumn, va[9]));
- cnfStyle.Add(new XAttribute(W.lastRowLastColumn, va[10]));
- cnfStyle.Add(new XAttribute(W.lastRowFirstColumn, va[11]));
- }
- }
- private static object CleanupTransform(XNode node)
- {
- XElement element = node as XElement;
- if (element != null)
- {
- if (element.Name == W.tabs && element.Element(W.tab) == null)
- return null;
- if (element.Name == W.tblStyleRowBandSize || element.Name == W.tblStyleColBandSize)
- return null;
- // a cleaner solution would be to not include the w:ins and w:del elements when rolling up the paragraph run properties into
- // the run properties.
- if ((element.Name == W.ins || element.Name == W.del) && element.Parent.Name == W.rPr)
- {
- if (element.Parent.Parent.Name == W.r || element.Parent.Parent.Name == W.rPrChange)
- return null;
- }
- return new XElement(element.Name,
- element.Attributes(),
- element.Nodes().Select(n => CleanupTransform(n)));
- }
- return node;
- }
- private static void ClearStyles(WordprocessingDocument wDoc)
- {
- var stylePart = wDoc.MainDocumentPart.StyleDefinitionsPart;
- var sXDoc = stylePart.GetXDocument();
- var newRoot = new XElement(sXDoc.Root.Name,
- sXDoc.Root.Attributes(),
- sXDoc.Root.Elements().Select(e =>
- {
- if (e.Name != W.style)
- return e;
- return new XElement(e.Name,
- e.Attributes(),
- e.Element(W.name),
- new XElement(W.pPr),
- new XElement(W.rPr));
- }));
- var globalrPr = newRoot
- .Elements(W.docDefaults)
- .Elements(W.rPrDefault)
- .Elements(W.rPr)
- .FirstOrDefault();
- if (globalrPr != null)
- globalrPr.ReplaceWith(new XElement(W.rPr));
- var globalpPr = newRoot
- .Elements(W.docDefaults)
- .Elements(W.pPrDefault)
- .Elements(W.pPr)
- .FirstOrDefault();
- if (globalpPr != null)
- globalpPr.ReplaceWith(new XElement(W.pPr));
- sXDoc.Root.ReplaceWith(newRoot);
- stylePart.PutXDocument();
- }
- private static void NormalizeListItems(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, FormattingAssemblerSettings settings)
- {
- foreach (var part in wDoc.ContentParts())
- {
- var pxd = part.GetXDocument();
- XElement newRoot = (XElement)NormalizeListItemsTransform(fai, wDoc, pxd.Root, settings);
- if (newRoot.Attribute(XNamespace.Xmlns + "pt14") == null)
- newRoot.Add(new XAttribute(XNamespace.Xmlns + "pt14", PtOpenXml.pt.NamespaceName));
- if (newRoot.Attribute(XNamespace.Xmlns + "mc") == null)
- newRoot.Add(new XAttribute(XNamespace.Xmlns + "mc", MC.mc.NamespaceName));
- pxd.Root.ReplaceWith(newRoot);
- }
- }
- private static object NormalizeListItemsTransform(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, XNode node, FormattingAssemblerSettings settings)
- {
- var element = node as XElement;
- if (element != null)
- {
- if (element.Name == W.p)
- {
- var li = ListItemRetriever.RetrieveListItem(wDoc, element, settings.ListItemRetrieverSettings);
- if (li != null)
- {
- ListItemRetriever.ListItemInfo listItemInfo = element.Annotation<ListItemRetriever.ListItemInfo>();
- var newParaProps = new XElement(W.pPr,
- element.Elements(W.pPr).Elements().Where(e => e.Name != W.numPr)
- );
- XElement listItemRunProps = null;
- int? abstractNumId = null;
- if (listItemInfo != null)
- {
- abstractNumId = listItemInfo.AbstractNumId;
- var paraStyleRunProps = CharStyleRollup(fai, wDoc, element);
- var paragraphStyleName = (string)element
- .Elements(W.pPr)
- .Elements(W.pStyle)
- .Attributes(W.val)
- .FirstOrDefault();
- string defaultStyleName = (string)wDoc
- .MainDocumentPart
- .StyleDefinitionsPart
- .GetXDocument()
- .Root
- .Elements(W.style)
- .Where(s => (string)s.Attribute(W.type) == "paragraph" && s.Attribute(W._default).ToBoolean() == true)
- .Attributes(W.styleId)
- .FirstOrDefault();
- if (paragraphStyleName == null)
- paragraphStyleName = defaultStyleName;
- XDocument stylesXDoc = wDoc
- .MainDocumentPart
- .StyleDefinitionsPart
- .GetXDocument();
- // put together run props for list item.
- XElement lvlStyleRpr = ParaStyleRunPropsStack(wDoc, paragraphStyleName)
- .Aggregate(new XElement(W.rPr),
- (r, s) =>
- {
- var newCharStyleRunProps = MergeStyleElement(s, r);
- return newCharStyleRunProps;
- });
- var mergedRunProps = MergeStyleElement(lvlStyleRpr, paraStyleRunProps);
- var accumulatedRunProps = element.Elements(PtOpenXml.pPr).Elements(W.rPr).FirstOrDefault();
- if (accumulatedRunProps != null)
- mergedRunProps = MergeStyleElement(accumulatedRunProps, mergedRunProps);
- var listItemLvl = listItemInfo.Lvl(ListItemRetriever.GetParagraphLevel(element));
- var listItemLvlRunProps = listItemLvl.Elements(W.rPr).FirstOrDefault();
- listItemRunProps = MergeStyleElement(listItemLvlRunProps, mergedRunProps);
- if ((string)listItemLvl.Elements(W.numFmt).Attributes(W.val).FirstOrDefault() == "bullet")
- {
- listItemRunProps.Elements(W.rtl).Remove();
- }
- else
- {
- var pPr = element.Element(PtOpenXml.pPr);
- if (pPr != null)
- {
- XElement bidiel = pPr.Element(W.bidi);
- bool bidi = bidiel != null && (bidiel.Attribute(W.val) == null || bidiel.Attribute(W.val).ToBoolean() == true);
- if (bidi)
- {
- listItemRunProps = MergeStyleElement(new XElement(W.rPr,
- new XElement(W.rtl)), listItemRunProps);
- }
- }
- }
- }
- var paragraphLevel = ListItemRetriever.GetParagraphLevel(element);
- ListItemRetriever.LevelNumbers levelNums = element.Annotation<ListItemRetriever.LevelNumbers>();
- string levelNumsString = levelNums
- .LevelNumbersArray
- .Take(paragraphLevel + 1)
- .Select(i => i.ToString() + ".")
- .StringConcatenate()
- .TrimEnd('.');
- var listItemRun = new XElement(W.r,
- new XAttribute(PtOpenXml.ListItemRun, levelNumsString),
- element.Attribute(PtOpenXml.FontName),
- element.Attribute(PtOpenXml.LanguageType),
- listItemRunProps,
- new XElement(W.t,
- new XAttribute(XNamespace.Xml + "space", "preserve"),
- li));
- AdjustFontAttributes(wDoc, listItemRun, null, listItemRunProps, settings);
- var lvl = listItemInfo.Lvl(ListItemRetriever.GetParagraphLevel(element));
- XElement suffix = new XElement(W.tab);
- var su = (string)lvl.Elements(W.suff).Attributes(W.val).FirstOrDefault();
- if (su == "space")
- suffix = new XElement(W.t,
- new XAttribute(XNamespace.Xml + "space", "preserve"),
- " ");
- else if (su == "nothing")
- suffix = null;
- var jc = (string)lvl.Elements(W.lvlJc).Attributes(W.val).FirstOrDefault();
- if (jc == "right")
- {
- var accumulatedParaProps = element.Element(PtOpenXml.pPr);
- var hangingAtt = accumulatedParaProps.Elements(W.ind).Attributes(W.hanging).FirstOrDefault();
- if (hangingAtt == null)
- {
- var listItemRunLength = WordprocessingMLUtil.CalcWidthOfRunInTwips(listItemRun);
- var ind = accumulatedParaProps.Element(W.ind);
- if (ind == null)
- {
- ind = new XElement(W.ind);
- accumulatedParaProps.Add(ind);
- }
- ind.Add(new XAttribute(W.hanging, listItemRunLength.ToString()));
- }
- else
- {
- var hanging = (int)hangingAtt;
- var listItemRunLength = WordprocessingMLUtil.CalcWidthOfRunInTwips(listItemRun);
- hanging += listItemRunLength; // should be width of list item, in twips
- hangingAtt.Value = hanging.ToString();
- }
- }
- else if (jc == "center")
- {
- var accumulatedParaProps = element.Element(PtOpenXml.pPr);
- var hangingAtt = accumulatedParaProps.Elements(W.ind).Attributes(W.hanging).FirstOrDefault();
- if (hangingAtt == null)
- {
- var listItemRunLength = WordprocessingMLUtil.CalcWidthOfRunInTwips(listItemRun);
- var ind = accumulatedParaProps.Element(W.ind);
- if (ind == null)
- {
- ind = new XElement(W.ind);
- accumulatedParaProps.Add(ind);
- }
- ind.Add(new XAttribute(W.hanging, (listItemRunLength / 2).ToString()));
- }
- else
- {
- var hanging = (int)hangingAtt;
- var listItemRunLength = WordprocessingMLUtil.CalcWidthOfRunInTwips(listItemRun);
- hanging += (listItemRunLength / 2); // should be half of width of list item, in twips
- hangingAtt.Value = hanging.ToString();
- }
- }
- AddTabAtLeftIndent(element.Element(PtOpenXml.pPr));
- XElement newPara = new XElement(W.p,
- element.Attribute(PtOpenXml.FontName),
- element.Attribute(PtOpenXml.LanguageType),
- element.Attribute(PtOpenXml.Unid),
- new XAttribute(PtOpenXml.AbstractNumId, abstractNumId),
- newParaProps,
- listItemRun,
- suffix != null ?
- new XElement(W.r,
- new XAttribute(PtOpenXml.ListItemRun, levelNumsString),
- listItemRunProps,
- suffix) : null,
- element.Elements().Where(e => e.Name != W.pPr).Select(n => NormalizeListItemsTransform(fai, wDoc, n, settings)));
- return newPara;
- }
- }
- return new XElement(element.Name,
- element.Attributes(),
- element.Nodes().Select(n => NormalizeListItemsTransform(fai, wDoc, n, settings)));
- }
- return node;
- }
- private static void AddTabAtLeftIndent(XElement pPr)
- {
- int left = 0;
- var ind = pPr.Element(W.ind);
- // todo need to handle W.start
- if (pPr.Attribute(W.left) != null)
- left = (int)pPr.Attribute(W.left);
- var tabs = pPr.Element(W.tabs);
- if (tabs == null)
- {
- tabs = new XElement(W.tabs);
- pPr.Add(tabs);
- }
- var tabAtLeft = tabs.Elements(W.tab).FirstOrDefault(t => (int)t.Attribute(W.pos) == left);
- if (tabAtLeft == null)
- {
- tabs.Add(
- new XElement(W.tab,
- new XAttribute(W.val, "left"),
- new XAttribute(W.pos, left)));
- }
- }
- public static XName[] PtNamesToKeep = new[] {
- PtOpenXml.FontName,
- PtOpenXml.AbstractNumId,
- PtOpenXml.StyleName,
- PtOpenXml.LanguageType,
- PtOpenXml.ListItemRun,
- PtOpenXml.Unid,
- };
- public static void NormalizePropsForPart(XDocument pxd, FormattingAssemblerSettings settings)
- {
- if (settings.CreateHtmlConverterAnnotationAttributes)
- {
- pxd.Root.Descendants().Attributes().Where(d => d.Name.Namespace == PtOpenXml.pt &&
- !PtNamesToKeep.Contains(d.Name)).Remove();
- if (pxd.Root.Attribute(XNamespace.Xmlns + "pt14") == null)
- pxd.Root.Add(new XAttribute(XNamespace.Xmlns + "pt14", PtOpenXml.pt.NamespaceName));
- if (pxd.Root.Attribute(XNamespace.Xmlns + "mc") == null)
- pxd.Root.Add(new XAttribute(XNamespace.Xmlns + "mc", MC.mc.NamespaceName));
- XAttribute mci = pxd.Root.Attribute(MC.Ignorable);
- if (mci != null)
- {
- if (!pxd.Root.Attribute(MC.Ignorable).Value.Contains("pt14"))
- {
- var ig = pxd.Root.Attribute(MC.Ignorable).Value + " pt14";
- mci.Value = ig;
- }
- }
- else
- {
- pxd.Root.Add(new XAttribute(MC.Ignorable, "pt14"));
- }
- }
- else
- {
- pxd.Root.Descendants().Attributes().Where(d => d.Name.Namespace == PtOpenXml.pt).Remove();
- }
- var runProps = pxd.Root.Descendants(PtOpenXml.rPr).ToList();
- foreach (var item in runProps)
- {
- XElement newRunProps = new XElement(W.rPr,
- item.Attributes(),
- item.Elements());
- XElement parent = item.Parent;
- if (parent.Name == W.p)
- {
- XElement existingParaProps = parent.Element(W.pPr);
- if (existingParaProps == null)
- {
- existingParaProps = new XElement(W.pPr);
- parent.Add(existingParaProps);
- }
- XElement existingRunProps = existingParaProps.Element(W.rPr);
- if (existingRunProps != null)
- {
- if (!settings.RemoveStyleNamesFromParagraphAndRunProperties)
- {
- if (newRunProps.Element(W.rStyle) == null)
- newRunProps.Add(existingRunProps.Element(W.rStyle));
- }
- existingRunProps.ReplaceWith(newRunProps);
- }
- else
- existingParaProps.Add(newRunProps);
- }
- else
- {
- XElement existingRunProps = parent.Element(W.rPr);
- if (existingRunProps != null)
- {
- if (!settings.RemoveStyleNamesFromParagraphAndRunProperties)
- {
- if (newRunProps.Element(W.rStyle) == null)
- newRunProps.Add(existingRunProps.Element(W.rStyle));
- }
- existingRunProps.ReplaceWith(newRunProps);
- }
- else
- parent.Add(newRunProps);
- }
- }
- var paraProps = pxd.Root.Descendants(PtOpenXml.pPr).ToList();
- foreach (var item in paraProps)
- {
- var paraRunProps = item.Parent.Elements(W.pPr).Elements(W.rPr).FirstOrDefault();
- var merged = MergeStyleElement(item.Element(W.rPr), paraRunProps);
- if (!settings.RemoveStyleNamesFromParagraphAndRunProperties)
- {
- if (merged.Element(W.rStyle) == null)
- {
- merged.Add(paraRunProps.Element(W.rStyle));
- }
- }
- XElement newParaProps = new XElement(W.pPr,
- item.Attributes(),
- item.Elements().Where(e => e.Name != W.rPr),
- merged);
- XElement para = item.Parent;
- XElement existingParaProps = para.Element(W.pPr);
- if (existingParaProps != null)
- {
- if (!settings.RemoveStyleNamesFromParagraphAndRunProperties)
- {
- if (newParaProps.Element(W.pStyle) == null)
- newParaProps.Add(existingParaProps.Element(W.pStyle));
- }
- existingParaProps.ReplaceWith(newParaProps);
- }
- else
- para.Add(newParaProps);
- }
- var tblProps = pxd.Root.Descendants(PtOpenXml.tblPr).ToList();
- foreach (var item in tblProps)
- {
- XElement newTblProps = new XElement(item);
- newTblProps.Name = W.tblPr;
- XElement table = item.Parent;
- XElement existingTableProps = table.Element(W.tblPr);
- if (existingTableProps != null)
- existingTableProps.ReplaceWith(newTblProps);
- else
- table.AddFirst(newTblProps);
- }
- var trProps = pxd.Root.Descendants(PtOpenXml.trPr).ToList();
- foreach (var item in trProps)
- {
- XElement newTrProps = new XElement(item);
- newTrProps.Name = W.trPr;
- XElement row = item.Parent;
- XElement existingRowProps = row.Element(W.trPr);
- if (existingRowProps != null)
- existingRowProps.ReplaceWith(newTrProps);
- else
- row.AddFirst(newTrProps);
- }
- var tcProps = pxd.Root.Descendants(PtOpenXml.tcPr).ToList();
- foreach (var item in tcProps)
- {
- XElement newTcProps = new XElement(item);
- newTcProps.Name = W.tcPr;
- XElement row = item.Parent;
- XElement existingRowProps = row.Element(W.tcPr);
- if (existingRowProps != null)
- existingRowProps.ReplaceWith(newTcProps);
- else
- row.AddFirst(newTcProps);
- }
- pxd.Root.Descendants(W.numPr).Remove();
- if (settings.RemoveStyleNamesFromParagraphAndRunProperties)
- {
- pxd.Root.Descendants(W.pStyle).Where(ps => ps.Parent.Name == W.pPr).Remove();
- pxd.Root.Descendants(W.rStyle).Where(ps => ps.Parent.Name == W.rPr).Remove();
- }
- pxd.Root.Descendants(W.tblStyle).Where(ps => ps.Parent.Name == W.tblPr).Remove();
- pxd.Root.Descendants().Where(d => d.Name.Namespace == PtOpenXml.pt).Remove();
- if (settings.OrderElementsPerStandard)
- {
- XElement newRoot = (XElement)WordprocessingMLUtil.WmlOrderElementsPerStandard(pxd.Root);
- pxd.Root.ReplaceWith(newRoot);
- }
- }
- private static void AssembleListItemInformation(WordprocessingDocument wordDoc, ListItemRetrieverSettings settings)
- {
- foreach (var part in wordDoc.ContentParts())
- {
- XDocument xDoc = part.GetXDocument();
- foreach (var para in xDoc.Descendants(W.p))
- {
- ListItemRetriever.RetrieveListItem(wordDoc, para, settings);
- }
- }
- }
- private static void AnnotateWithGlobalDefaults(WordprocessingDocument wDoc, XElement rootElement, FormattingAssemblerSettings settings)
- {
- XElement globalDefaultParaProps = null;
- XElement globalDefaultParaPropsAsDefined = null;
- XElement globalDefaultRunProps = null;
- XElement globalDefaultRunPropsAsDefined = null;
- XDocument sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- var defaultParaStyleName = (string)sXDoc
- .Root
- .Elements(W.style)
- .Where(st => (string)st.Attribute(W.type) == "paragraph" && st.Attribute(W._default).ToBoolean() == true)
- .Attributes(W.styleId)
- .FirstOrDefault();
- var defaultCharStyleName = (string)sXDoc
- .Root
- .Elements(W.style)
- .Where(st => (string)st.Attribute(W.type) == "character" && st.Attribute(W._default).ToBoolean() == true)
- .Attributes(W.styleId)
- .FirstOrDefault();
- XElement docDefaults = sXDoc.Root.Element(W.docDefaults);
- if (docDefaults != null)
- {
- globalDefaultParaPropsAsDefined = docDefaults.Elements(W.pPrDefault).Elements(W.pPr)
- .FirstOrDefault();
- if (globalDefaultParaPropsAsDefined == null)
- globalDefaultParaPropsAsDefined = new XElement(W.pPr,
- new XElement(W.rPr));
- globalDefaultRunPropsAsDefined = docDefaults.Elements(W.rPrDefault).Elements(W.rPr)
- .FirstOrDefault();
- if (globalDefaultRunPropsAsDefined == null)
- globalDefaultRunPropsAsDefined = new XElement(W.rPr);
- if (globalDefaultRunPropsAsDefined.Element(W.rFonts) == null)
- globalDefaultRunPropsAsDefined.Add(
- new XElement(W.rFonts,
- new XAttribute(W.ascii, "Times New Roman"),
- new XAttribute(W.hAnsi, "Times New Roman"),
- new XAttribute(W.cs, "Times New Roman")));
- if (globalDefaultRunPropsAsDefined.Element(W.sz) == null)
- globalDefaultRunPropsAsDefined.Add(
- new XElement(W.sz,
- new XAttribute(W.val, "20")));
- if (globalDefaultRunPropsAsDefined.Element(W.szCs) == null)
- globalDefaultRunPropsAsDefined.Add(
- new XElement(W.szCs,
- new XAttribute(W.val, "20")));
- var runPropsForGlobalDefaultParaProps = MergeStyleElement(globalDefaultRunPropsAsDefined, globalDefaultParaPropsAsDefined.Element(W.rPr));
- globalDefaultParaProps = new XElement(globalDefaultParaPropsAsDefined.Name,
- globalDefaultParaPropsAsDefined.Attributes(),
- globalDefaultParaPropsAsDefined.Elements().Where(e => e.Name != W.rPr),
- runPropsForGlobalDefaultParaProps);
- globalDefaultRunProps = MergeStyleElement(globalDefaultParaPropsAsDefined.Element(W.rPr), globalDefaultRunPropsAsDefined);
- }
- var rPr = new XElement(W.rPr,
- new XElement(W.rFonts,
- new XAttribute(W.ascii, "Times New Roman"),
- new XAttribute(W.hAnsi, "Times New Roman"),
- new XAttribute(W.cs, "Times New Roman")),
- new XElement(W.sz,
- new XAttribute(W.val, "20")),
- new XElement(W.szCs,
- new XAttribute(W.val, "20")));
- if (globalDefaultParaProps == null)
- globalDefaultParaProps = new XElement(W.pPr, rPr);
- if (globalDefaultRunProps == null)
- globalDefaultRunProps = rPr;
- XElement ptGlobalDefaultParaProps = new XElement(globalDefaultParaProps);
- XElement ptGlobalDefaultRunProps = new XElement(globalDefaultRunProps);
- ptGlobalDefaultParaProps.Name = PtOpenXml.pPr;
- ptGlobalDefaultRunProps.Name = PtOpenXml.rPr;
- var parasAndRuns = rootElement.Descendants().Where(d =>
- {
- return d.Name == W.p || d.Name == W.r;
- });
- if (settings.CreateHtmlConverterAnnotationAttributes)
- {
- foreach (var d in parasAndRuns)
- {
- if (d.Name == W.p)
- {
- var pStyle = (string)d.Elements(W.pPr).Elements(W.pStyle).Attributes(W.val).FirstOrDefault();
- if (pStyle == null)
- pStyle = defaultParaStyleName;
- if (pStyle != null)
- {
- if (d.Attribute(PtOpenXml.StyleName) != null)
- d.Attribute(PtOpenXml.StyleName).Value = pStyle;
- else
- d.Add(new XAttribute(PtOpenXml.StyleName, pStyle));
- }
- d.Add(ptGlobalDefaultParaProps);
- }
- else
- {
- var rStyle = (string)d.Elements(W.rPr).Elements(W.rStyle).Attributes(W.val).FirstOrDefault();
- if (rStyle == null)
- rStyle = defaultCharStyleName;
- if (rStyle != null)
- {
- if (d.Attribute(PtOpenXml.StyleName) != null)
- d.Attribute(PtOpenXml.StyleName).Value = rStyle;
- else
- d.Add(new XAttribute(PtOpenXml.StyleName, rStyle));
- }
- d.Add(ptGlobalDefaultRunProps);
- }
- }
- }
- else
- {
- foreach (var d in parasAndRuns)
- {
- if (d.Name == W.p)
- {
- d.Add(ptGlobalDefaultParaProps);
- }
- else
- {
- d.Add(ptGlobalDefaultRunProps);
- }
- }
- }
- }
- private static XElement BlankTcBorders = new XElement(W.tcBorders,
- new XElement(W.top, new XAttribute(W.val, "nil")),
- new XElement(W.left, new XAttribute(W.val, "nil")),
- new XElement(W.bottom, new XAttribute(W.val, "nil")),
- new XElement(W.right, new XAttribute(W.val, "nil")));
- private static void AnnotateTablesWithTableStyles(WordprocessingDocument wDoc, XElement rootElement)
- {
- XDocument sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- foreach (var tbl in rootElement.Descendants(W.tbl))
- {
- string tblStyleName = (string)tbl.Elements(W.tblPr).Elements(W.tblStyle).Attributes(W.val).FirstOrDefault();
- if (tblStyleName != null)
- {
- XElement style = TableStyleRollup(wDoc, tblStyleName);
- // annotate table with table style, in PowerTools namespace
- style.Name = PtOpenXml.style;
- tbl.Add(style);
- // merge tblPr in table style with tblPr of the table
- // annnotate in PowerTools namespace
- XElement tblPr2 = style.Element(W.tblPr);
- XElement tblPr3 = MergeStyleElement(tbl.Element(W.tblPr), tblPr2, true);
- if (tblPr3 != null)
- {
- XElement newTblPr = new XElement(tblPr3);
- newTblPr.Name = PtOpenXml.pt + "tblPr";
- tbl.Add(newTblPr);
- }
- AddTcPrPtToEveryCell(tbl);
- AddOuterBorders(tbl, style);
- var tableTcPr = style.Element(W.tcPr);
- if (tableTcPr != null)
- {
- foreach (var row in tbl.Elements(W.tr))
- {
- foreach (var cell in row.Elements(W.tc))
- {
- bool tcPrPtExists = false;
- var tcPrPt = cell.Element(PtOpenXml.pt + "tcPr");
- if (tcPrPt != null)
- tcPrPtExists = true;
- else
- tcPrPt = new XElement(W.tcPr);
- tcPrPt = MergeStyleElement(tableTcPr, tcPrPt);
- var newTcPrPt = new XElement(tcPrPt);
- newTcPrPt.Name = PtOpenXml.tcPr;
- if (tcPrPtExists)
- cell.Element(PtOpenXml.tcPr).ReplaceWith(newTcPrPt);
- else
- cell.Add(newTcPrPt);
- }
- }
- }
- // Iterate through every row and cell in the table, rolling up row properties and cell properties
- // as appropriate per the cnfStyle element, then replacing the row and cell properties
- foreach (var row in tbl.Elements(W.tr))
- {
- XElement trPr2 = null;
- trPr2 = style.Element(W.trPr);
- if (trPr2 == null)
- trPr2 = new XElement(W.trPr);
- XElement rowCnf = row.Elements(W.trPr).Elements(W.cnfStyle).FirstOrDefault();
- if (rowCnf != null)
- {
- foreach (var ot in TableStyleOverrideTypes)
- {
- XName attName = TableStyleOverrideXNameMap[ot];
- if (rowCnf != null && rowCnf.Attribute(attName).ToBoolean() == true)
- {
- XElement o = style
- .Elements(W.tblStylePr)
- .Where(tsp => (string)tsp.Attribute(W.type) == ot)
- .FirstOrDefault();
- if (o != null)
- {
- XElement ottrPr = o.Element(W.trPr);
- trPr2 = MergeStyleElement(ottrPr, trPr2);
- }
- }
- }
- }
- trPr2 = MergeStyleElement(row.Element(W.trPr), trPr2);
- if (trPr2.HasElements)
- {
- trPr2.Name = PtOpenXml.pt + "trPr";
- row.Add(trPr2);
- }
- }
- foreach (var ot in TableStyleOverrideTypes)
- {
- XName attName = TableStyleOverrideXNameMap[ot];
- if (attName == W.oddHBand ||
- attName == W.evenHBand ||
- attName == W.firstRow ||
- attName == W.lastRow)
- {
- foreach (var row in tbl.Elements(W.tr))
- {
- XElement rowCnf = row.Elements(W.trPr).Elements(W.cnfStyle).FirstOrDefault();
- if (rowCnf != null && rowCnf.Attribute(attName).ToBoolean() == true)
- {
- XElement o = style
- .Elements(W.tblStylePr)
- .Where(tsp => (string)tsp.Attribute(W.type) == ot)
- .FirstOrDefault();
- if (o != null)
- {
- foreach (var cell in row.Elements(W.tc))
- {
- bool tcPrPtExists = false;
- var tcPrPt = cell.Element(PtOpenXml.pt + "tcPr");
- if (tcPrPt != null)
- tcPrPtExists = true;
- else
- tcPrPt = new XElement(W.tcPr);
- tcPrPt = MergeStyleElement(o.Element(W.tcPr), tcPrPt);
- var newTcPrPt = new XElement(tcPrPt);
- newTcPrPt.Name = PtOpenXml.pt + "tcPr";
- if (tcPrPtExists)
- cell.Element(PtOpenXml.pt + "tcPr").ReplaceWith(newTcPrPt);
- else
- cell.Add(newTcPrPt);
- }
- }
- }
- }
- }
- else if (attName == W.firstColumn ||
- attName == W.lastColumn ||
- attName == W.oddVBand ||
- attName == W.evenVBand)
- {
- foreach (var row in tbl.Elements(W.tr))
- {
- foreach (var cell in row.Elements(W.tc))
- {
- ApplyCndFmtToCell(style, ot, attName, cell);
- }
- }
- }
- else if (attName == W.firstRowLastColumn)
- {
- var row = tbl.Elements(W.tr).FirstOrDefault();
- if (row != null)
- {
- var cell = row.Elements(W.tc).LastOrDefault();
- if (cell != null)
- ApplyCndFmtToCell(style, ot, attName, cell);
- }
- }
- else if (attName == W.firstRowFirstColumn)
- {
- var row = tbl.Elements(W.tr).FirstOrDefault();
- if (row != null)
- {
- var cell = row.Elements(W.tc).FirstOrDefault();
- if (cell != null)
- ApplyCndFmtToCell(style, ot, attName, cell);
- }
- }
- else if (attName == W.lastRowLastColumn)
- {
- var row = tbl.Elements(W.tr).LastOrDefault();
- if (row != null)
- {
- var cell = row.Elements(W.tc).LastOrDefault();
- if (cell != null)
- ApplyCndFmtToCell(style, ot, attName, cell);
- }
- }
- else if (attName == W.lastRowFirstColumn)
- {
- var row = tbl.Elements(W.tr).LastOrDefault();
- if (row != null)
- {
- var cell = row.Elements(W.tc).FirstOrDefault();
- if (cell != null)
- ApplyCndFmtToCell(style, ot, attName, cell);
- }
- }
- }
- ProcessInnerBorders(tbl, style);
- }
- else
- {
- var tblPr = new XElement(W.tblPr);
- XElement tblPr3 = MergeStyleElement(tbl.Element(W.tblPr), tblPr, true);
- if (tblPr3 != null)
- {
- XElement newTblPr = new XElement(tblPr3);
- newTblPr.Name = PtOpenXml.pt + "tblPr";
- tbl.Add(newTblPr);
- }
- AddTcPrPtToEveryCell(tbl);
- }
- RollInDirectFormatting(tbl); // it is important that this is last. This merges in direct formatting.
- }
- }
- private static void AddTcPrPtToEveryCell(XElement tbl)
- {
- foreach (var row in tbl.Elements(W.tr))
- {
- foreach (var cell in row.Elements(W.tc))
- {
- var tcPrPt = cell.Element(PtOpenXml.pt + "tcPr");
- if (tcPrPt != null)
- continue;
- tcPrPt = new XElement(PtOpenXml.pt + "tcPr",
- new XElement(W.tcBorders));
- cell.Add(tcPrPt);
- }
- }
- }
- private static void ApplyCndFmtToCell(XElement style, string ot, XName attName, XElement cell)
- {
- XElement cellCnf = cell.Elements(W.tcPr).Elements(W.cnfStyle).FirstOrDefault();
- if (cellCnf != null && cellCnf.Attribute(attName).ToBoolean() == true)
- {
- XElement o = style
- .Elements(W.tblStylePr)
- .Where(tsp => (string)tsp.Attribute(W.type) == ot)
- .FirstOrDefault();
- if (o != null)
- {
- bool tcPrPtExists = false;
- var tcPrPt = cell.Element(PtOpenXml.pt + "tcPr");
- if (tcPrPt != null)
- tcPrPtExists = true;
- else
- tcPrPt = new XElement(W.tcPr);
- tcPrPt = MergeStyleElement(o.Element(W.tcPr), tcPrPt);
- var newTcPrPt = new XElement(tcPrPt);
- newTcPrPt.Name = PtOpenXml.pt + "tcPr";
- if (tcPrPtExists)
- cell.Element(PtOpenXml.pt + "tcPr").ReplaceWith(newTcPrPt);
- else
- cell.Add(newTcPrPt);
- }
- }
- }
- private static void RollInDirectFormatting(XElement tbl)
- {
- foreach (var row in tbl.Elements(W.tr))
- {
- foreach (var cell in row.Elements(W.tc))
- {
- var ptTcPr = cell.Element(PtOpenXml.pt + "tcPr");
- var tcPr = cell.Element(W.tcPr);
- var mTcPr = MergeStyleElement(tcPr, ptTcPr);
- if (mTcPr == null)
- {
- mTcPr = new XElement(PtOpenXml.pt + "tcPr");
- cell.Add(tcPr);
- }
- var newTcPr = new XElement(mTcPr);
- newTcPr.Name = PtOpenXml.pt + "tcPr";
- var existing = cell.Element(PtOpenXml.pt + "tcPr");
- if (existing != null)
- existing.ReplaceWith(newTcPr);
- else
- cell.Add(newTcPr);
- }
- }
- var tblBorders = tbl.Elements(PtOpenXml.pt + "tblPr").Elements(W.tblBorders).FirstOrDefault();
- if (tblBorders != null && tblBorders.Attribute(PtOpenXml.pt + "fromDirect") != null)
- {
- ApplyTblBordersToTable(tbl, tblBorders);
- ProcessInnerBordersPerTblBorders(tbl, tblBorders);
- }
- }
- private static void ApplyTblBordersToTable(XElement tbl, XElement tblBorders)
- {
- var top = tblBorders.Element(W.top);
- if (top != null)
- {
- var firstRow = tbl.Elements(W.tr).FirstOrDefault();
- if (firstRow != null)
- {
- foreach (var cell in firstRow.Elements(W.tc))
- {
- var cellTcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- if (cellTcBorders != null)
- {
- var cellTop = cellTcBorders.Element(W.top);
- if (cellTop == null)
- cellTcBorders.Add(top);
- else
- cellTop.ReplaceAttributes(top.Attributes());
- }
- }
- }
- }
- var bottom = tblBorders.Element(W.bottom);
- if (bottom != null)
- {
- var lastRow = tbl.Elements(W.tr).LastOrDefault();
- if (lastRow != null)
- {
- foreach (var cell in lastRow.Elements(W.tc))
- {
- var cellTcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- if (cellTcBorders != null)
- {
- var cellBottom = cellTcBorders.Element(W.bottom);
- if (cellBottom == null)
- cellTcBorders.Add(bottom);
- else
- cellBottom.ReplaceAttributes(bottom.Attributes());
- }
- }
- }
- }
- foreach (var row in tbl.Elements(W.tr))
- {
- var left = tblBorders.Element(W.left);
- if (left != null)
- {
- var firstCell = row.Elements(W.tc).FirstOrDefault();
- if (firstCell != null)
- {
- var cellTcBorders = firstCell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- if (cellTcBorders != null)
- {
- var firstCellLeft = cellTcBorders.Element(W.left);
- if (firstCellLeft == null)
- cellTcBorders.Add(left);
- else
- firstCellLeft.ReplaceAttributes(left.Attributes());
- }
- }
- }
- var right = tblBorders.Element(W.right);
- if (right != null)
- {
- var lastCell = row.Elements(W.tc).LastOrDefault();
- if (lastCell != null)
- {
- var cellTcBorders = lastCell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- if (cellTcBorders != null)
- {
- var lastCellRight = cellTcBorders.Element(W.right);
- if (lastCellRight == null)
- cellTcBorders.Add(right);
- else
- lastCellRight.ReplaceAttributes(right.Attributes());
- }
- }
- }
- }
- }
- private static void AddOuterBorders(XElement tbl, XElement style)
- {
- var tblBorders = tbl.Elements(PtOpenXml.pt + "tblPr").Elements(W.tblBorders).FirstOrDefault();
- if (tblBorders != null)
- ApplyTblBordersToTable(tbl, tblBorders);
- }
- private static void ProcessInnerBorders(XElement tbl, XElement style)
- {
- var tblBorders = tbl.Elements(PtOpenXml.pt + "tblPr").Elements(W.tblBorders).FirstOrDefault();
- if (tblBorders != null)
- ProcessInnerBordersPerTblBorders(tbl, tblBorders);
- foreach (var attName in new[] { W.oddHBand, W.evenHBand, W.firstRow, W.lastRow })
- {
- int rowCount = tbl.Elements(W.tr).Count();
- int lastRow = rowCount - 1;
- XElement insideV = null;
- foreach (var row in tbl.Elements(W.tr))
- {
- var rowCnfStyle = row.Elements(W.trPr).Elements(W.cnfStyle).FirstOrDefault();
- if (rowCnfStyle != null)
- {
- var shouldApply = rowCnfStyle.Attribute(attName).ToBoolean();
- if (shouldApply == true)
- {
- var cndType = TableStyleOverrideXNameRevMap[attName];
- var cndStyle = style
- .Elements(W.tblStylePr)
- .FirstOrDefault(tsp => (string)tsp.Attribute(W.type) == cndType);
- if (cndStyle != null)
- {
- var styleTcBorders = cndStyle.Elements(W.tcPr).Elements(W.tcBorders).FirstOrDefault();
- if (styleTcBorders != null)
- {
- var top = styleTcBorders.Element(W.top);
- var left = styleTcBorders.Element(W.left);
- var bottom = styleTcBorders.Element(W.bottom);
- var right = styleTcBorders.Element(W.right);
- insideV = cndStyle.Elements(W.tcPr).Elements(W.tcBorders).Elements(W.insideV).FirstOrDefault();
- if (insideV != null)
- {
- int lastCol = row.Elements(W.tc).Count() - 1;
- int colIdx = 0;
- foreach (var cell in row.Elements(W.tc))
- {
- var tcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- if (colIdx == 0)
- {
- ResolveInsideWithExisting(tcBorders, insideV, W.right);
- }
- else if (colIdx == lastCol)
- {
- ResolveInsideWithExisting(tcBorders, insideV, W.left);
- }
- else
- {
- ResolveInsideWithExisting(tcBorders, insideV, W.left);
- ResolveInsideWithExisting(tcBorders, insideV, W.right);
- }
- colIdx++;
- }
- }
- }
- }
- }
- }
- }
- }
- foreach (var attName in new[] { W.oddVBand, W.evenVBand, W.firstColumn, W.lastColumn })
- {
- int rowIdx = 0;
- int lastRow = tbl.Elements(W.tr).Count() - 1;
- foreach (var row in tbl.Elements(W.tr))
- {
- foreach (var cell in row.Elements(W.tc))
- {
- var cellCnfStyle = cell.Elements(W.tcPr).Elements(W.cnfStyle).FirstOrDefault();
- if (cellCnfStyle != null)
- {
- var shouldApply = cellCnfStyle.Attribute(attName).ToBoolean();
- if (shouldApply == true)
- {
- var cndType = TableStyleOverrideXNameRevMap[attName];
- var cndStyle = style
- .Elements(W.tblStylePr)
- .FirstOrDefault(tsp => (string)tsp.Attribute(W.type) == cndType);
- if (cndStyle != null)
- {
- var insideH = cndStyle.Elements(W.tcPr).Elements(W.tcBorders).Elements(W.insideH).FirstOrDefault();
- if (insideH != null)
- {
- var tcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- if (rowIdx == 0)
- {
- ResolveInsideWithExisting(tcBorders, insideH, W.bottom);
- }
- else if (rowIdx == lastRow)
- {
- ResolveInsideWithExisting(tcBorders, insideH, W.top);
- }
- else
- {
- ResolveInsideWithExisting(tcBorders, insideH, W.bottom);
- ResolveInsideWithExisting(tcBorders, insideH, W.top);
- }
- }
- }
- }
- }
- }
- rowIdx++;
- }
- }
- }
- private static void ProcessInnerBordersPerTblBorders(XElement tbl, XElement tblBorders)
- {
- var tblInsideV = tblBorders.Elements(W.insideV).FirstOrDefault();
- if (tblInsideV != null)
- {
- foreach (var row in tbl.Elements(W.tr))
- {
- var lastCell = row.Elements(W.tc).Count() - 1;
- int cellIdx = 0;
- foreach (var cell in row.Elements(W.tc))
- {
- var tcPr = cell.Element(PtOpenXml.pt + "tcPr");
- if (tcPr == null)
- {
- tcPr = new XElement(PtOpenXml.pt + "tcPr");
- cell.Add(tcPr);
- }
- var tcBorders = tcPr.Element(W.tcBorders);
- if (tcBorders == null)
- {
- tcBorders = new XElement(W.tcBorders);
- tcPr.Add(tcBorders);
- }
- if (cellIdx == 0)
- {
- ResolveInsideWithExisting(tcBorders, tblInsideV, W.right);
- }
- else if (cellIdx == lastCell)
- {
- ResolveInsideWithExisting(tcBorders, tblInsideV, W.left);
- }
- else
- {
- ResolveInsideWithExisting(tcBorders, tblInsideV, W.left);
- ResolveInsideWithExisting(tcBorders, tblInsideV, W.right);
- }
- cellIdx++;
- }
- }
- }
- var tblInsideH = tblBorders.Elements(W.insideH).FirstOrDefault();
- if (tblInsideH != null)
- {
- int rowIdx1 = 0;
- int lastRow1 = tbl.Elements(W.tr).Count() - 1;
- foreach (var row in tbl.Elements(W.tr))
- {
- if (rowIdx1 == 0)
- {
- foreach (var cell in row.Elements(W.tc))
- {
- var tcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- ResolveInsideWithExisting(tcBorders, tblInsideH, W.bottom);
- }
- }
- else if (rowIdx1 == lastRow1)
- {
- foreach (var cell in row.Elements(W.tc))
- {
- var tcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- ResolveInsideWithExisting(tcBorders, tblInsideH, W.top);
- }
- }
- else
- {
- foreach (var cell in row.Elements(W.tc))
- {
- var tcBorders = cell.Elements(PtOpenXml.pt + "tcPr").Elements(W.tcBorders).FirstOrDefault();
- ResolveInsideWithExisting(tcBorders, tblInsideH, W.top);
- ResolveInsideWithExisting(tcBorders, tblInsideH, W.bottom);
- }
- }
- rowIdx1++;
- }
- }
- }
- private static void ResolveInsideWithExisting(XElement tcBorders, XElement inside, XName whichSide)
- {
- if (tcBorders.Element(whichSide) != null)
- {
- var newInsideH = ResolveInsideBorder(inside, tcBorders.Element(whichSide));
- tcBorders.Element(whichSide).ReplaceAttributes(
- newInsideH.Attributes());
- }
- else
- {
- tcBorders.Add(
- new XElement(whichSide,
- inside.Attributes()));
- }
- }
- private static Dictionary<string, int> BorderTypePriority = new Dictionary<string, int>()
- {
- { "single", 1 },
- { "thick", 2 },
- { "double", 3 },
- { "dotted", 4 },
- };
- private static Dictionary<string, int> BorderNumber = new Dictionary<string, int>()
- {
- {"single", 1 },
- {"thick", 2 },
- {"double", 3 },
- {"dotted", 4 },
- {"dashed", 5 },
- {"dotDash", 6 },
- {"dotDotDash", 7 },
- {"triple", 8 },
- {"thinThickSmallGap", 9 },
- {"thickThinSmallGap", 10 },
- {"thinThickThinSmallGap", 11 },
- {"thinThickMediumGap", 12 },
- {"thickThinMediumGap", 13 },
- {"thinThickThinMediumGap", 14 },
- {"thinThickLargeGap", 15 },
- {"thickThinLargeGap", 16 },
- {"thinThickThinLargeGap", 17 },
- {"wave", 18 },
- {"doubleWave", 19 },
- {"dashSmallGap", 20 },
- {"dashDotStroked", 21 },
- {"threeDEmboss", 22 },
- {"threeDEngrave", 23 },
- {"outset", 24 },
- {"inset", 25 },
- };
- private static XElement ResolveInsideBorder(XElement inside1, XElement sideToReplace)
- {
- if (inside1 == null && sideToReplace == null)
- return null;
- if (inside1 == null)
- return sideToReplace;
- if (sideToReplace == null)
- return inside1;
- // The following handles the situation where
- // if table innerV is set, and cnd format for first row specifies nill border, then nil border wins.
- // if table innerH is set, and cnd format for first columns specifies nil border, then table innerH wins.
- if (sideToReplace.Name == W.left ||
- sideToReplace.Name == W.right)
- {
- if ((string)inside1.Attribute(W.val) == "nil")
- return inside1;
- if ((string)sideToReplace.Attribute(W.val) == "nil")
- return sideToReplace;
- }
- else
- {
- if ((string)inside1.Attribute(W.val) == "nil")
- return sideToReplace;
- if ((string)sideToReplace.Attribute(W.val) == "nil")
- return inside1;
- }
- var inside1Val = (string)inside1.Attribute(W.val);
- var border1Weight = 1;
- if (BorderNumber.ContainsKey(inside1Val))
- border1Weight = BorderNumber[inside1Val];
- var sideToReplaceVal = (string)sideToReplace.Attribute(W.val);
- var sideToReplaceWeight = 1;
- if (BorderNumber.ContainsKey(sideToReplaceVal))
- sideToReplaceWeight = BorderNumber[sideToReplaceVal];
- if (border1Weight != sideToReplaceWeight)
- {
- if (border1Weight < sideToReplaceWeight)
- return sideToReplace;
- else
- return inside1;
- }
- if ((int)inside1.Attribute(W.sz) > (int)sideToReplace.Attribute(W.sz))
- return inside1;
- if ((int)sideToReplace.Attribute(W.sz) > (int)inside1.Attribute(W.sz))
- return sideToReplace;
- if (BorderTypePriority.ContainsKey(inside1Val) &&
- BorderTypePriority.ContainsKey(sideToReplaceVal))
- {
- var inside1Pri = BorderTypePriority[inside1Val];
- var inside2Pri = BorderTypePriority[sideToReplaceVal];
- if (inside1Pri > inside2Pri)
- return inside1;
- if (inside2Pri > inside1Pri)
- return sideToReplace;
- }
- if ((int)inside1.Attribute(W.sz) > (int)sideToReplace.Attribute(W.sz))
- return inside1;
- if ((int)sideToReplace.Attribute(W.sz) > (int)inside1.Attribute(W.sz))
- return sideToReplace;
- var color1str = (string)inside1.Attribute(W.color);
- if (color1str == "auto")
- color1str = "000000";
- var color2str = (string)sideToReplace.Attribute(W.color);
- if (color2str == "auto")
- color2str = "000000";
- if (color1str != null && color2str != null && color1str != color2str)
- {
- Int32 color1;
- Int32 color2;
- try
- {
- color1 = Convert.ToInt32(color1str, 16);
- }
- // if the above throws ArgumentException, FormatException, or OverflowException, then abort
- catch (Exception)
- {
- return sideToReplace;
- }
- try
- {
- color2 = Convert.ToInt32(color2str, 16);
- }
- // if the above throws ArgumentException, FormatException, or OverflowException, then abort
- catch (Exception)
- {
- return inside1;
- }
- if (color1 < color2)
- return inside1;
- if (color2 < color1)
- return sideToReplace;
- return inside1;
- }
- return inside1;
- }
- private static XElement TableStyleRollup(WordprocessingDocument wDoc, string tblStyleName)
- {
- var tblStyleChain = TableStyleStack(wDoc, tblStyleName)
- .Reverse();
- XElement rolledStyle = new XElement(W.style);
- foreach (var style in tblStyleChain)
- {
- rolledStyle = MergeStyleElement(style, rolledStyle);
- }
- return rolledStyle;
- }
- private static XName[] SpecialCaseChildProperties =
- {
- W.tblPr,
- W.trPr,
- W.tcPr,
- W.pPr,
- W.rPr,
- W.pBdr,
- W.tabs,
- W.rFonts,
- W.ind,
- W.spacing,
- W.tblStylePr,
- W.tcBorders,
- W.tblBorders,
- W.lang,
- W.numPr,
- };
- private static XName[] MergeChildProperties =
- {
- W.tblPr,
- W.trPr,
- W.tcPr,
- W.pPr,
- W.rPr,
- W.pBdr,
- W.tcBorders,
- W.tblBorders,
- W.numPr,
- };
- private static string[] TableStyleOverrideTypes =
- {
- "band1Vert",
- "band2Vert",
- "band1Horz",
- "band2Horz",
- "firstCol",
- "lastCol",
- "firstRow",
- "lastRow",
- "neCell",
- "nwCell",
- "seCell",
- "swCell",
- };
- private static Dictionary<string, XName> TableStyleOverrideXNameMap = new Dictionary<string, XName>
- {
- {"band1Vert", W.oddVBand},
- {"band2Vert", W.evenVBand},
- {"band1Horz", W.oddHBand},
- {"band2Horz", W.evenHBand},
- {"firstCol", W.firstColumn},
- {"lastCol", W.lastColumn},
- {"firstRow", W.firstRow},
- {"lastRow", W.lastRow},
- {"neCell", W.firstRowLastColumn},
- {"nwCell", W.firstRowFirstColumn},
- {"seCell", W.lastRowLastColumn},
- {"swCell", W.lastRowFirstColumn},
- };
- private static Dictionary<XName, string> TableStyleOverrideXNameRevMap = new Dictionary<XName, string>
- {
- {W.oddVBand, "band1Vert"},
- {W.evenVBand, "band2Vert"},
- {W.oddHBand, "band1Horz"},
- {W.evenHBand, "band2Horz"},
- {W.firstColumn, "firstCol"},
- {W.lastColumn, "lastCol"},
- {W.firstRow, "firstRow"},
- {W.lastRow, "lastRow"},
- };
- private static XElement MergeStyleElement(XElement higherPriorityElement, XElement lowerPriorityElement)
- {
- return MergeStyleElement(higherPriorityElement, lowerPriorityElement, null);
- }
- private static XElement MergeStyleElement(XElement higherPriorityElement, XElement lowerPriorityElement, bool? highPriIsDirectFormatting)
- {
- // If, when in the process of merging, the source element doesn't have a
- // corresponding element in the merged element, then include the source element
- // in the merged element.
- if (lowerPriorityElement == null)
- return higherPriorityElement;
- if (higherPriorityElement == null)
- return lowerPriorityElement;
- var hpe = higherPriorityElement
- .Elements()
- .Where(e => !SpecialCaseChildProperties.Contains(e.Name))
- .ToArray();
- if (highPriIsDirectFormatting == true)
- {
- hpe = hpe
- .Select(e =>
- new XElement(e.Name,
- e.Attributes(),
- new XAttribute(PtOpenXml.pt + "fromDirect", true),
- e.Elements()))
- .ToArray();
- }
- var lpe = lowerPriorityElement
- .Elements()
- .Where(e => !SpecialCaseChildProperties.Contains(e.Name) && !hpe.Select(z => z.Name).Contains(e.Name))
- .ToArray();
- var ma = SpacingMerge(higherPriorityElement.Element(W.spacing), lowerPriorityElement.Element(W.spacing));
- var rFonts = FontMerge(higherPriorityElement.Element(W.rFonts), lowerPriorityElement.Element(W.rFonts));
- var tabs = TabsMerge(higherPriorityElement.Element(W.tabs), lowerPriorityElement.Element(W.tabs));
- var ind = IndMerge(higherPriorityElement.Element(W.ind), lowerPriorityElement.Element(W.ind));
- var lang = LangMerge(higherPriorityElement.Element(W.lang), lowerPriorityElement.Element(W.lang));
- var mcp = MergeChildProperties
- .Select(e =>
- {
- // test is here to prevent unnecessary recursion to make debugging easier
- var h = higherPriorityElement.Element(e);
- var l = lowerPriorityElement.Element(e);
- if (h == null && l == null)
- return null;
- if (h == null && l != null)
- return l;
- if (h != null && l == null)
- {
- var newH = new XElement(h.Name,
- h.Attributes(),
- highPriIsDirectFormatting == true ? new XAttribute(PtOpenXml.pt + "fromDirect", true) : null,
- h.Elements());
- return newH;
- }
- return MergeStyleElement(h, l, highPriIsDirectFormatting);
- })
- .Where(m => m != null)
- .ToArray();
- var tsor = TableStyleOverrideTypes
- .Select(e =>
- {
- // test is here to prevent unnecessary recursion to make debugging easier
- var h = higherPriorityElement.Elements(W.tblStylePr).FirstOrDefault(tsp => (string)tsp.Attribute(W.type) == e);
- var l = lowerPriorityElement.Elements(W.tblStylePr).FirstOrDefault(tsp => (string)tsp.Attribute(W.type) == e);
- if (h == null && l == null)
- return null;
- if (h == null && l != null)
- return l;
- if (h != null && l == null)
- return h;
- return MergeStyleElement(h, l);
- })
- .Where(m => m != null)
- .ToArray();
- XElement newMergedElement = new XElement(higherPriorityElement.Name,
- new XAttribute(XNamespace.Xmlns + "w", W.w),
- higherPriorityElement.Attributes().Where(a => !a.IsNamespaceDeclaration),
- hpe, // higher priority elements
- lpe, // lower priority elements where there is not a higher priority element of same name
- ind, // w:ind has very special rules
- ma, // elements that require merged attributes
- lang,
- rFonts, // font merge is special case
- tabs, // tabs merge is special case
- mcp, // elements that need child properties to be merged
- tsor // merged table style override elements
- );
- return newMergedElement;
- }
- private static XElement LangMerge(XElement hLang, XElement lLang)
- {
- if (hLang == null && lLang == null)
- return null;
- if (hLang != null && lLang == null)
- return hLang;
- if (lLang != null && hLang == null)
- return lLang;
- return new XElement(W.lang,
- hLang.Attribute(W.val) != null ? hLang.Attribute(W.val) : lLang.Attribute(W.val),
- hLang.Attribute(W.bidi) != null ? hLang.Attribute(W.bidi) : lLang.Attribute(W.bidi),
- hLang.Attribute(W.eastAsia) != null ? hLang.Attribute(W.eastAsia) : lLang.Attribute(W.eastAsia));
- }
- private enum IndAttType
- {
- End,
- FirstLineOrHanging,
- Start,
- Left,
- Right,
- None,
- };
- private static XElement IndMerge(XElement higherPriorityElement, XElement lowerPriorityElement)
- {
- if (higherPriorityElement == null && lowerPriorityElement == null)
- return null;
- if (higherPriorityElement != null && lowerPriorityElement == null)
- return higherPriorityElement;
- if (lowerPriorityElement != null && higherPriorityElement == null)
- return lowerPriorityElement;
- XElement hpe = new XElement(higherPriorityElement);
- XElement lpe = new XElement(lowerPriorityElement);
- if (hpe.Attribute(W.firstLine) != null)
- lpe.Attributes(W.hanging).Remove();
- if (hpe.Attribute(W.firstLineChars) != null)
- lpe.Attributes(W.hangingChars).Remove();
- if (hpe.Attribute(W.hanging) != null)
- lpe.Attributes(W.firstLine).Remove();
- if (hpe.Attribute(W.hangingChars) != null)
- lpe.Attributes(W.firstLineChars).Remove();
- var highPriAtts = hpe
- .Attributes()
- .Where(a => !a.IsNamespaceDeclaration)
- .ToList();
- var highPriAttNames = highPriAtts
- .Select(a => a.Name);
- var lowPriAtts = lpe
- .Attributes()
- .Where(a => !a.IsNamespaceDeclaration)
- .Where(a => !highPriAttNames.Contains(a.Name))
- .ToList();
- var mergedElement = new XElement(higherPriorityElement.Name,
- highPriAtts,
- lowPriAtts);
- return mergedElement;
- }
- // merge child tab elements
- // they are additive, with the exception that if there are two elements at the same location,
- // we need to take the higher, and not take the lower.
- private static XElement TabsMerge(XElement higherPriorityElement, XElement lowerPriorityElement)
- {
- if (higherPriorityElement != null && lowerPriorityElement == null)
- return higherPriorityElement;
- if (higherPriorityElement == null && lowerPriorityElement != null)
- return lowerPriorityElement;
- if (higherPriorityElement == null && lowerPriorityElement == null)
- return null;
- var hps = higherPriorityElement.Elements().Select(e =>
- new
- {
- Pos = (int)e.Attribute(W.pos),
- Pri = 1,
- Element = e,
- }
- );
- var lps = lowerPriorityElement.Elements().Select(e =>
- new
- {
- Pos = (int)e.Attribute(W.pos),
- Pri = 2,
- Element = e,
- }
- );
- var newTabElements = hps.Concat(lps)
- .GroupBy(s => s.Pos)
- .Select(g => g.OrderBy(s => s.Pri).First().Element)
- .Where(e => (string)e.Attribute(W.val) != "clear")
- .OrderBy(e => (int)e.Attribute(W.pos));
- var newTabs = new XElement(W.tabs, newTabElements);
- return newTabs;
- }
- private static XElement SpacingMerge(XElement hn, XElement ln)
- {
- if (hn == null && ln == null)
- return null;
- if (hn != null && ln == null)
- return hn;
- if (hn == null && ln != null)
- return ln;
- var mn1 = new XElement(W.spacing,
- hn.Attributes(),
- ln.Attributes().Where(a => hn.Attribute(a.Name) == null));
- return mn1;
- }
- private static IEnumerable<XElement> TableStyleStack(WordprocessingDocument wDoc, string tblStyleName)
- {
- XDocument sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- string currentStyle = tblStyleName;
- while (true)
- {
- XElement style = sXDoc
- .Root
- .Elements(W.style).Where(s => (string)s.Attribute(W.type) == "table" &&
- (string)s.Attribute(W.styleId) == currentStyle)
- .FirstOrDefault();
- if (style == null)
- yield break;
- yield return style;
- currentStyle = (string)style.Elements(W.basedOn).Attributes(W.val).FirstOrDefault();
- if (currentStyle == null)
- yield break;
- }
- }
- private static XElement FontMerge(XElement higherPriorityFont, XElement lowerPriorityFont)
- {
- XElement rFonts;
- if (higherPriorityFont == null)
- return lowerPriorityFont;
- if (lowerPriorityFont == null)
- return higherPriorityFont;
- if (higherPriorityFont == null && lowerPriorityFont == null)
- return null;
- rFonts = new XElement(W.rFonts,
- (higherPriorityFont.Attribute(W.ascii) != null || higherPriorityFont.Attribute(W.asciiTheme) != null) ?
- new[] { higherPriorityFont.Attribute(W.ascii), higherPriorityFont.Attribute(W.asciiTheme) } :
- new[] { lowerPriorityFont.Attribute(W.ascii), lowerPriorityFont.Attribute(W.asciiTheme) },
- (higherPriorityFont.Attribute(W.hAnsi) != null || higherPriorityFont.Attribute(W.hAnsiTheme) != null) ?
- new[] { higherPriorityFont.Attribute(W.hAnsi), higherPriorityFont.Attribute(W.hAnsiTheme) } :
- new[] { lowerPriorityFont.Attribute(W.hAnsi), lowerPriorityFont.Attribute(W.hAnsiTheme) },
- (higherPriorityFont.Attribute(W.eastAsia) != null || higherPriorityFont.Attribute(W.eastAsiaTheme) != null) ?
- new[] { higherPriorityFont.Attribute(W.eastAsia), higherPriorityFont.Attribute(W.eastAsiaTheme) } :
- new[] { lowerPriorityFont.Attribute(W.eastAsia), lowerPriorityFont.Attribute(W.eastAsiaTheme) },
- (higherPriorityFont.Attribute(W.cs) != null || higherPriorityFont.Attribute(W.cstheme) != null) ?
- new[] { higherPriorityFont.Attribute(W.cs), higherPriorityFont.Attribute(W.cstheme) } :
- new[] { lowerPriorityFont.Attribute(W.cs), lowerPriorityFont.Attribute(W.cstheme) },
- (higherPriorityFont.Attribute(W.hint) != null ? higherPriorityFont.Attribute(W.hint) :
- lowerPriorityFont.Attribute(W.hint))
- );
- return rFonts;
- }
- private static void AnnotateParagraphs(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, XElement root, FormattingAssemblerSettings settings)
- {
- foreach (var para in root.Descendants(W.p))
- {
- AnnotateParagraph(fai, wDoc, para, settings);
- }
- }
- private static void AnnotateParagraph(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, XElement para, FormattingAssemblerSettings settings)
- {
- XElement localParaProps = para.Element(W.pPr);
- if (localParaProps == null)
- {
- localParaProps = new XElement(W.pPr);
- }
- // get para table props, to be merged.
- XElement tablepPr = null;
- var blockLevelContentContainer = para
- .Ancestors()
- .FirstOrDefault(a => a.Name == W.body ||
- a.Name == W.tbl ||
- a.Name == W.txbxContent ||
- a.Name == W.ftr ||
- a.Name == W.hdr ||
- a.Name == W.footnote ||
- a.Name == W.endnote);
- if (blockLevelContentContainer.Name == W.tbl)
- {
- XElement tbl = blockLevelContentContainer;
- XElement style = tbl.Element(PtOpenXml.pt + "style");
- XElement cellCnf = para.Ancestors(W.tc).Take(1).Elements(W.tcPr).Elements(W.cnfStyle).FirstOrDefault();
- XElement rowCnf = para.Ancestors(W.tr).Take(1).Elements(W.trPr).Elements(W.cnfStyle).FirstOrDefault();
- if (style != null)
- {
- // roll up tblPr, trPr, and tcPr from within a specific style.
- // add each of these to the table, in PowerTools namespace.
- tablepPr = style.Element(W.pPr);
- if (tablepPr == null)
- tablepPr = new XElement(W.pPr);
- foreach (var ot in TableStyleOverrideTypes)
- {
- XName attName = TableStyleOverrideXNameMap[ot];
- if ((cellCnf != null && cellCnf.Attribute(attName).ToBoolean() == true) ||
- (rowCnf != null && rowCnf.Attribute(attName).ToBoolean() == true))
- {
- XElement o = style
- .Elements(W.tblStylePr)
- .Where(tsp => (string)tsp.Attribute(W.type) == ot)
- .FirstOrDefault();
- if (o != null)
- {
- XElement otpPr = o.Element(W.pPr);
- tablepPr = MergeStyleElement(otpPr, tablepPr);
- }
- }
- }
- }
- }
- var stylesPart = wDoc.MainDocumentPart.StyleDefinitionsPart;
- XDocument sXDoc = null;
- if (stylesPart != null)
- sXDoc = stylesPart.GetXDocument();
- ListItemRetriever.ListItemInfo lif = para.Annotation<ListItemRetriever.ListItemInfo>();
- XElement rolledParaProps = ParagraphStyleRollup(para, sXDoc, fai.DefaultParagraphStyleName);
- if (lif != null && lif.IsZeroNumId)
- rolledParaProps.Elements(W.ind).Remove();
- XElement toggledParaProps = MergeStyleElement(rolledParaProps, tablepPr);
- XElement mergedParaProps = MergeStyleElement(localParaProps, toggledParaProps);
- string li = ListItemRetriever.RetrieveListItem(wDoc, para, settings.ListItemRetrieverSettings);
- if (lif != null && lif.IsListItem)
- {
- if (settings.RestrictToSupportedNumberingFormats)
- {
- string numFmtForLevel = (string)lif.Lvl(ListItemRetriever.GetParagraphLevel(para)).Elements(W.numFmt).Attributes(W.val).FirstOrDefault();
- if (numFmtForLevel == null)
- {
- var numFmtElement = lif.Lvl(ListItemRetriever.GetParagraphLevel(para)).Elements(MC.AlternateContent).Elements(MC.Choice).Elements(W.numFmt).FirstOrDefault();
- if (numFmtElement != null && (string)numFmtElement.Attribute(W.val) == "custom")
- numFmtForLevel = (string)numFmtElement.Attribute(W.format);
- }
- bool isLgl = lif.Lvl(ListItemRetriever.GetParagraphLevel(para)).Elements(W.isLgl).Any();
- if (isLgl && numFmtForLevel != "decimalZero")
- numFmtForLevel = "decimal";
- if (!AcceptableNumFormats.Contains(numFmtForLevel))
- throw new UnsupportedNumberingFormatException(numFmtForLevel + " is not a supported numbering format");
- }
- int paragraphLevel = ListItemRetriever.GetParagraphLevel(para);
- var numberingParaProps = lif
- .Lvl(paragraphLevel)
- .Elements(W.pPr)
- .FirstOrDefault();
- if (numberingParaProps == null)
- {
- numberingParaProps = new XElement(W.pPr);
- }
- else
- {
- numberingParaProps
- .Elements()
- .Where(e => e.Name != W.ind)
- .Remove();
- }
- // have:
- // - localParaProps
- // - toggledParaProps
- // - numberingParaProps
- // if a paragraph contains a numPr with a numId=0, in other words, it is NOT a numbered item, then the indentation from the style
- // hierarchy is ignored.
- ListItemRetriever.ListItemInfo lii = para.Annotation<ListItemRetriever.ListItemInfo>();
- if (lii.FromParagraph != null)
- {
- // order
- // - toggledParaProps
- // - numberingParaProps
- // - localParaProps
- mergedParaProps = MergeStyleElement(numberingParaProps, toggledParaProps);
- mergedParaProps = MergeStyleElement(localParaProps, mergedParaProps);
- }
- else if (lii.FromStyle != null)
- {
- // order
- // - numberingParaProps
- // - toggledParaProps
- // - localParaProps
- mergedParaProps = MergeStyleElement(toggledParaProps, numberingParaProps);
- mergedParaProps = MergeStyleElement(localParaProps, mergedParaProps);
- }
- }
- else
- {
- mergedParaProps = MergeStyleElement(localParaProps, toggledParaProps);
- }
- // merge mergedParaProps with existing accumulatedParaProps, with mergedParaProps as high pri
- // replace accumulatedParaProps with newly merged
- XElement accumulatedParaProps = para.Element(PtOpenXml.pt + "pPr");
- XElement newAccumulatedParaProps = MergeStyleElement(mergedParaProps, accumulatedParaProps);
- AdjustFontAttributes(wDoc, para, newAccumulatedParaProps, newAccumulatedParaProps.Element(W.rPr), settings);
- newAccumulatedParaProps.Name = PtOpenXml.pt + "pPr";
- if (accumulatedParaProps != null)
- {
- accumulatedParaProps.ReplaceWith(newAccumulatedParaProps);
- }
- else
- {
- para.Add(newAccumulatedParaProps);
- }
- }
- private static string[] AcceptableNumFormats = new[] {
- "decimal",
- "decimalZero",
- "upperRoman",
- "lowerRoman",
- "upperLetter",
- "lowerLetter",
- "ordinal",
- "cardinalText",
- "ordinalText",
- "bullet",
- "0001, 0002, 0003, ...",
- "none",
- };
- public static XElement ParagraphStyleRollup(XElement paragraph, XDocument stylesXDoc, string defaultParagraphStyleName)
- {
- var paraStyle = (string)paragraph
- .Elements(W.pPr)
- .Elements(W.pStyle)
- .Attributes(W.val)
- .FirstOrDefault();
- if (paraStyle == null)
- paraStyle = defaultParagraphStyleName;
- var rolledUpParaStyleParaProps = new XElement(W.pPr);
- if (stylesXDoc == null)
- return rolledUpParaStyleParaProps;
- if (paraStyle != null)
- {
- rolledUpParaStyleParaProps = ParaStyleParaPropsStack(stylesXDoc, paraStyle, paragraph)
- .Reverse()
- .Aggregate(new XElement(W.pPr),
- (r, s) =>
- {
- var newParaProps = MergeStyleElement(s, r);
- return newParaProps;
- });
- }
- return rolledUpParaStyleParaProps;
- }
- private static IEnumerable<XElement> ParaStyleParaPropsStack(XDocument stylesXDoc, string paraStyleName, XElement para)
- {
- if (stylesXDoc == null)
- yield break;
- var localParaStyleName = paraStyleName;
- while (localParaStyleName != null)
- {
- XElement paraStyle = stylesXDoc.Root.Elements(W.style).FirstOrDefault(s =>
- s.Attribute(W.type).Value == "paragraph" &&
- s.Attribute(W.styleId).Value == localParaStyleName);
- if (paraStyle == null)
- {
- yield break;
- }
- if (paraStyle.Element(W.pPr) == null)
- {
- if (paraStyle.Element(W.rPr) != null)
- {
- var elementToYield2 = new XElement(W.pPr,
- paraStyle.Element(W.rPr));
- yield return elementToYield2;
- }
- localParaStyleName = (string)(paraStyle
- .Elements(W.basedOn)
- .Attributes(W.val)
- .FirstOrDefault());
- continue;
- }
- var elementToYield = new XElement(W.pPr,
- paraStyle.Element(W.pPr).Attributes(),
- paraStyle.Element(W.pPr).Elements(),
- paraStyle.Element(W.rPr));
- yield return (elementToYield);
- var listItemInfo = para.Annotation<ListItemRetriever.ListItemInfo>();
- if (listItemInfo != null)
- {
- if (listItemInfo.IsListItem)
- {
- XElement lipPr = listItemInfo.Lvl(ListItemRetriever.GetParagraphLevel(para)).Element(W.pPr);
- if (lipPr == null)
- lipPr = new XElement(W.pPr);
- XElement lirPr = listItemInfo.Lvl(ListItemRetriever.GetParagraphLevel(para)).Element(W.rPr);
- var elementToYield2 = new XElement(W.pPr,
- lipPr.Attributes(),
- lipPr.Elements(),
- lirPr);
- yield return (elementToYield2);
- }
- }
- localParaStyleName = (string)paraStyle
- .Elements(W.basedOn)
- .Attributes(W.val)
- .FirstOrDefault();
- }
- yield break;
- }
- private static void AnnotateRuns(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, XElement root, FormattingAssemblerSettings settings)
- {
- var runsOrParas = root.Descendants()
- .Where(rp =>
- {
- return rp.Name == W.r || rp.Name == W.p;
- });
- foreach (var runOrPara in runsOrParas)
- {
- AnnotateRunProperties(fai, wDoc, runOrPara, settings);
- }
- }
- private static void AnnotateRunProperties(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, XElement runOrPara, FormattingAssemblerSettings settings)
- {
- XElement localRunProps = null;
- if (runOrPara.Name == W.p)
- {
- var rPr = runOrPara.Elements(W.pPr).Elements(W.rPr).FirstOrDefault();
- if (rPr != null)
- {
- localRunProps = rPr;
- }
- }
- else
- {
- localRunProps = runOrPara.Element(W.rPr);
- }
- if (localRunProps == null)
- {
- localRunProps = new XElement(W.rPr);
- }
- // get run table props, to be merged.
- XElement tablerPr = null;
- var blockLevelContentContainer = runOrPara
- .Ancestors()
- .FirstOrDefault(a => a.Name == W.body ||
- a.Name == W.tbl ||
- a.Name == W.txbxContent ||
- a.Name == W.ftr ||
- a.Name == W.hdr ||
- a.Name == W.footnote ||
- a.Name == W.endnote);
- if (blockLevelContentContainer.Name == W.tbl)
- {
- XElement tbl = blockLevelContentContainer;
- XElement style = tbl.Element(PtOpenXml.pt + "style");
- XElement cellCnf = runOrPara.Ancestors(W.tc).Take(1).Elements(W.tcPr).Elements(W.cnfStyle).FirstOrDefault();
- XElement rowCnf = runOrPara.Ancestors(W.tr).Take(1).Elements(W.trPr).Elements(W.cnfStyle).FirstOrDefault();
- if (style != null)
- {
- tablerPr = style.Element(W.rPr);
- if (tablerPr == null)
- tablerPr = new XElement(W.rPr);
- foreach (var ot in TableStyleOverrideTypes)
- {
- XName attName = TableStyleOverrideXNameMap[ot];
- if ((cellCnf != null && cellCnf.Attribute(attName).ToBoolean() == true) ||
- (rowCnf != null && rowCnf.Attribute(attName).ToBoolean() == true))
- {
- XElement o = style
- .Elements(W.tblStylePr)
- .Where(tsp => (string)tsp.Attribute(W.type) == ot)
- .FirstOrDefault();
- if (o != null)
- {
- XElement otrPr = o.Element(W.rPr);
- tablerPr = MergeStyleElement(otrPr, tablerPr);
- }
- }
- }
- }
- }
- XElement rolledRunProps = CharStyleRollup(fai, wDoc, runOrPara);
- var toggledRunProps = ToggleMergeRunProps(rolledRunProps, tablerPr);
- var currentRunProps = runOrPara.Element(PtOpenXml.rPr); // this is already stored on the run from previous aggregation of props
- var mergedRunProps = MergeStyleElement(toggledRunProps, currentRunProps);
- var newMergedRunProps = MergeStyleElement(localRunProps, mergedRunProps);
- XElement pPr = null;
- if (runOrPara.Name == W.p)
- pPr = runOrPara.Element(PtOpenXml.pPr);
- AdjustFontAttributes(wDoc, runOrPara, pPr, newMergedRunProps, settings);
- newMergedRunProps.Name = PtOpenXml.rPr;
- if (currentRunProps != null)
- {
- currentRunProps.ReplaceWith(newMergedRunProps);
- }
- else
- {
- runOrPara.Add(newMergedRunProps);
- }
- }
- private static XElement CharStyleRollup(FormattingAssemblerInfo fai, WordprocessingDocument wDoc, XElement runOrPara)
- {
- var sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- string charStyle = null;
- string paraStyle = null;
- XElement rPr = null;
- XElement pPr = null;
- XElement pStyle = null;
- XElement rStyle = null;
- CachedParaInfo cpi = null; // CachedParaInfo is an optimization for the case where a paragraph contains thousands of runs.
- if (runOrPara.Name == W.p)
- {
- cpi = runOrPara.Annotation<CachedParaInfo>();
- if (cpi != null)
- pPr = cpi.ParagraphProperties;
- else
- {
- pPr = runOrPara.Element(W.pPr);
- if (pPr != null)
- {
- paraStyle = (string)pPr.Elements(W.pStyle).Attributes(W.val).FirstOrDefault();
- }
- else
- {
- paraStyle = fai.DefaultParagraphStyleName;
- }
- cpi = new CachedParaInfo
- {
- ParagraphProperties = pPr,
- ParagraphStyleName = paraStyle,
- };
- runOrPara.AddAnnotation(cpi);
- }
- if (pPr != null)
- {
- rPr = pPr.Element(W.rPr);
- }
- }
- else
- {
- rPr = runOrPara.Element(W.rPr);
- }
- if (rPr != null)
- {
- rStyle = rPr.Element(W.rStyle);
- if (rStyle != null)
- {
- charStyle = (string)rStyle.Attribute(W.val);
- }
- else
- {
- if (runOrPara.Name == W.r)
- charStyle = (string)runOrPara
- .Ancestors(W.p)
- .Take(1)
- .Elements(W.pPr)
- .Elements(W.pStyle)
- .Attributes(W.val)
- .FirstOrDefault();
- else
- charStyle = (string)runOrPara
- .Elements(W.pPr)
- .Elements(W.pStyle)
- .Attributes(W.val)
- .FirstOrDefault();
- }
- }
- if (charStyle == null)
- {
- if (runOrPara.Name == W.r)
- {
- var ancestorPara = runOrPara.Ancestors(W.p).First();
- cpi = ancestorPara.Annotation<CachedParaInfo>();
- if (cpi != null)
- charStyle = cpi.ParagraphStyleName;
- else
- charStyle = (string)runOrPara.Ancestors(W.p).First().Elements(W.pPr).Elements(W.pStyle).Attributes(W.val).FirstOrDefault();
- }
- if (charStyle == null)
- {
- charStyle = fai.DefaultParagraphStyleName;
- }
- }
- // A run always must have an ancestor paragraph.
- XElement para = null;
- var rolledUpParaStyleRunProps = new XElement(W.rPr);
- if (runOrPara.Name == W.r)
- {
- para = runOrPara.Ancestors(W.p).FirstOrDefault();
- }
- else
- {
- para = runOrPara;
- }
- cpi = para.Annotation<CachedParaInfo>();
- if (cpi != null)
- {
- pPr = cpi.ParagraphProperties;
- }
- else
- {
- pPr = para.Element(W.pPr);
- }
- if (pPr != null)
- {
- pStyle = pPr.Element(W.pStyle);
- if (pStyle != null)
- {
- paraStyle = (string)pStyle.Attribute(W.val);
- }
- else
- {
- paraStyle = fai.DefaultParagraphStyleName;
- }
- }
- else
- paraStyle = fai.DefaultParagraphStyleName;
- string key = (paraStyle == null ? "[null]" : paraStyle) + "~|~" +
- (charStyle == null ? "[null]" : charStyle);
- XElement rolledRunProps = null;
- if (fai.RolledCharacterStyles.ContainsKey(key))
- rolledRunProps = fai.RolledCharacterStyles[key];
- else
- {
- XElement rolledUpCharStyleRunProps = new XElement(W.rPr);
- if (charStyle != null)
- {
- rolledUpCharStyleRunProps =
- CharStyleStack(wDoc, charStyle)
- .Aggregate(new XElement(W.rPr),
- (r, s) =>
- {
- var newRunProps = MergeStyleElement(s, r);
- return newRunProps;
- });
- }
- if (paraStyle != null)
- {
- rolledUpParaStyleRunProps = ParaStyleRunPropsStack(wDoc, paraStyle)
- .Aggregate(new XElement(W.rPr),
- (r, s) =>
- {
- var newCharStyleRunProps = MergeStyleElement(s, r);
- return newCharStyleRunProps;
- });
- }
- rolledRunProps = MergeStyleElement(rolledUpCharStyleRunProps, rolledUpParaStyleRunProps);
- fai.RolledCharacterStyles.Add(key, rolledRunProps);
- }
- return rolledRunProps;
- }
- private static IEnumerable<XElement> ParaStyleRunPropsStack(WordprocessingDocument wDoc, string paraStyleName)
- {
- var localParaStyleName = paraStyleName;
- var sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- var rValue = new Stack<XElement>();
- while (localParaStyleName != null)
- {
- var paraStyle = sXDoc.Root.Elements(W.style).FirstOrDefault(s =>
- {
- return (string)s.Attribute(W.type) == "paragraph" &&
- (string)s.Attribute(W.styleId) == localParaStyleName;
- });
- if (paraStyle == null)
- {
- return rValue;
- }
- if (paraStyle.Element(W.rPr) != null)
- {
- rValue.Push(paraStyle.Element(W.rPr));
- }
- localParaStyleName = (string)paraStyle
- .Elements(W.basedOn)
- .Attributes(W.val)
- .FirstOrDefault();
- }
- return rValue;
- }
- // returns collection of run properties
- private static IEnumerable<XElement> CharStyleStack(WordprocessingDocument wDoc, string charStyleName)
- {
- var localCharStyleName = charStyleName;
- var sXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
- var rValue = new Stack<XElement>();
- while (localCharStyleName != null)
- {
- XElement basedOn = null;
- // first look for character style
- var charStyle = sXDoc.Root.Elements(W.style).FirstOrDefault(s =>
- {
- return (string)s.Attribute(W.type) == "character" &&
- (string)s.Attribute(W.styleId) == localCharStyleName;
- });
- // if not found, look for paragraph style
- if (charStyle == null)
- {
- charStyle = sXDoc.Root.Elements(W.style).FirstOrDefault(s =>
- {
- return (string)s.Attribute(W.styleId) == localCharStyleName;
- });
- }
- if (charStyle == null)
- {
- return rValue;
- }
- if (charStyle.Element(W.rPr) == null)
- {
- basedOn = charStyle.Element(W.basedOn);
- if (basedOn != null)
- {
- localCharStyleName = (string)basedOn.Attribute(W.val);
- }
- else
- {
- return rValue;
- }
- }
- rValue.Push(charStyle.Element(W.rPr));
- localCharStyleName = null;
- basedOn = charStyle.Element(W.basedOn);
- if (basedOn != null)
- {
- localCharStyleName = (string)basedOn.Attribute(W.val);
- }
- }
- return rValue;
- }
- private static XElement ToggleMergeRunProps(XElement higherPriorityElement, XElement lowerPriorityElement)
- {
- if (lowerPriorityElement == null)
- return higherPriorityElement;
- if (higherPriorityElement == null)
- return lowerPriorityElement;
- var hpe = higherPriorityElement.Elements().Select(e => e.Name).ToArray();
- var newMergedElement = new XElement(higherPriorityElement.Name,
- higherPriorityElement.Attributes(),
- // process toggle properties
- higherPriorityElement.Elements()
- .Where(e => { return e.Name != W.rFonts; })
- .Select(higherChildElement =>
- {
- if (TogglePropertyNames.Contains(higherChildElement.Name))
- {
- var lowerChildElement = lowerPriorityElement.Element(higherChildElement.Name);
- if (lowerChildElement == null)
- {
- return higherChildElement;
- }
- var bHigher = higherChildElement.Attribute(W.val) == null || higherChildElement.Attribute(W.val).ToBoolean() == true;
- var bLower = lowerChildElement.Attribute(W.val) == null || lowerChildElement.Attribute(W.val).ToBoolean() == true;
- // if higher is true and lower is false, then return true element
- if (bHigher && !bLower)
- {
- return higherChildElement;
- }
- // if higher is false and lower is true, then return false element
- if (!bHigher && bLower)
- {
- return higherChildElement;
- }
- // if higher and lower are both true, then return false
- if (bHigher && bLower)
- {
- return new XElement(higherChildElement.Name,
- new XAttribute(W.val, "0"));
- }
- // otherwise, both higher and lower are false so can return higher element.
- return higherChildElement;
- }
- return higherChildElement;
- }),
- FontMerge(higherPriorityElement.Element(W.rFonts), lowerPriorityElement.Element(W.rFonts)),
- // take lower priority elements where there is not a higher priority element of same name
- lowerPriorityElement.Elements()
- .Where(e =>
- {
- return e.Name != W.rFonts && !hpe.Contains(e.Name);
- }));
- return newMergedElement;
- }
- private static XName[] TogglePropertyNames = new[] {
- W.b,
- W.bCs,
- W.caps,
- W.emboss,
- W.i,
- W.iCs,
- W.imprint,
- W.outline,
- W.shadow,
- W.smallCaps,
- W.strike,
- W.vanish
- };
- private static XName[] PropertyNames = new[] {
- W.cs,
- W.rtl,
- W.u,
- W.color,
- W.highlight,
- W.shd
- };
- public class CharStyleAttributes
- {
- public string AsciiFont;
- public string HAnsiFont;
- public string EastAsiaFont;
- public string CsFont;
- public string Hint;
- public bool Rtl;
- public string LatinLang;
- public string BidiLang;
- public string EastAsiaLang;
- public Dictionary<XName, bool?> ToggleProperties;
- public Dictionary<XName, XElement> Properties;
- public CharStyleAttributes(XElement pPr, XElement rPr)
- {
- ToggleProperties = new Dictionary<XName, bool?>();
- Properties = new Dictionary<XName, XElement>();
- if (rPr == null)
- return;
- foreach (XName xn in TogglePropertyNames)
- {
- ToggleProperties[xn] = GetBoolProperty(rPr, xn);
- }
- foreach (XName xn in PropertyNames)
- {
- Properties[xn] = GetXmlProperty(rPr, xn);
- }
- var rFonts = rPr.Element(W.rFonts);
- if (rFonts == null)
- {
- this.AsciiFont = null;
- this.HAnsiFont = null;
- this.EastAsiaFont = null;
- this.CsFont = null;
- this.Hint = null;
- }
- else
- {
- this.AsciiFont = (string)(rFonts.Attribute(W.ascii));
- this.HAnsiFont = (string)(rFonts.Attribute(W.hAnsi));
- this.EastAsiaFont = (string)(rFonts.Attribute(W.eastAsia));
- this.CsFont = (string)(rFonts.Attribute(W.cs));
- this.Hint = (string)(rFonts.Attribute(W.hint));
- }
- XElement csel = this.Properties[W.cs];
- bool cs = csel != null && (csel.Attribute(W.val) == null || csel.Attribute(W.val).ToBoolean() == true);
- XElement rtlel = this.Properties[W.rtl];
- bool rtl = rtlel != null && (rtlel.Attribute(W.val) == null || rtlel.Attribute(W.val).ToBoolean() == true);
- var bidi = false;
- if (pPr != null)
- {
- XElement bidiel = pPr.Element(W.bidi);
- bidi = bidiel != null && (bidiel.Attribute(W.val) == null || bidiel.Attribute(W.val).ToBoolean() == true);
- }
- Rtl = cs || rtl || bidi;
- var lang = rPr.Element(W.lang);
- if (lang != null)
- {
- LatinLang = (string)lang.Attribute(W.val);
- BidiLang = (string)lang.Attribute(W.bidi);
- EastAsiaLang = (string)lang.Attribute(W.eastAsia);
- }
- }
- private static bool? GetBoolProperty(XElement rPr, XName propertyName)
- {
- if (rPr.Element(propertyName) == null)
- return null;
- var s = (string)rPr.Element(propertyName).Attribute(W.val);
- if (s == null)
- return true;
- if (s == "1")
- return true;
- if (s == "0")
- return false;
- if (s == "true")
- return true;
- if (s == "false")
- return false;
- if (s == "on")
- return true;
- if (s == "off")
- return false;
- return (bool)(rPr.Element(propertyName).Attribute(W.val));
- }
- private static XElement GetXmlProperty(XElement rPr, XName propertyName)
- {
- return rPr.Element(propertyName);
- }
- private static XName[] TogglePropertyNames = new[] {
- W.b,
- W.bCs,
- W.caps,
- W.emboss,
- W.i,
- W.iCs,
- W.imprint,
- W.outline,
- W.shadow,
- W.smallCaps,
- W.strike,
- W.vanish
- };
- private static XName[] PropertyNames = new[] {
- W.cs,
- W.rtl,
- W.u,
- W.color,
- W.highlight,
- W.shd
- };
- }
- private static HashSet<char> WeakAndNeutralDirectionalCharacters = new HashSet<char>() {
- '0',
- '1',
- '2',
- '3',
- '4',
- '5',
- '6',
- '7',
- '8',
- '9',
- '+',
- '-',
- ':',
- ',',
- '.',
- '|',
- '\t',
- '\r',
- '\n',
- ' ',
- '\x00A0', // non breaking space
- '\x00B0', // degree sign
- '\x066B', // arabic decimal separator
- '\x066C', // arabic thousands separator
- '\x0627', // arabic pipe
- '\x20A0', // start currency symbols
- '\x20A1',
- '\x20A2',
- '\x20A3',
- '\x20A4',
- '\x20A5',
- '\x20A6',
- '\x20A7',
- '\x20A8',
- '\x20A9',
- '\x20AA',
- '\x20AB',
- '\x20AC',
- '\x20AD',
- '\x20AE',
- '\x20AF',
- '\x20B0',
- '\x20B1',
- '\x20B2',
- '\x20B3',
- '\x20B4',
- '\x20B5',
- '\x20B6',
- '\x20B7',
- '\x20B8',
- '\x20B9',
- '\x20BA',
- '\x20BB',
- '\x20BC',
- '\x20BD',
- '\x20BE',
- '\x20BF',
- '\x20C0',
- '\x20C1',
- '\x20C2',
- '\x20C3',
- '\x20C4',
- '\x20C5',
- '\x20C6',
- '\x20C7',
- '\x20C8',
- '\x20C9',
- '\x20CA',
- '\x20CB',
- '\x20CC',
- '\x20CD',
- '\x20CE',
- '\x20CF', // end currency symbols
- '\x0660', // "Arabic" Indic Numeral Forms Iraq and West
- '\x0661',
- '\x0662',
- '\x0663',
- '\x0664',
- '\x0665',
- '\x0666',
- '\x0667',
- '\x0668',
- '\x0669',
- '\x06F0', // "Arabic" Indic Numberal Forms Iran and East
- '\x06F1',
- '\x06F2',
- '\x06F3',
- '\x06F4',
- '\x06F5',
- '\x06F6',
- '\x06F7',
- '\x06F8',
- '\x06F9',
- };
- private static void AdjustFontAttributes(WordprocessingDocument wDoc, XElement paraOrRun, XElement pPr,
- XElement rPr, FormattingAssemblerSettings settings)
- {
- XDocument themeXDoc = null;
- if (wDoc.MainDocumentPart.ThemePart != null)
- themeXDoc = wDoc.MainDocumentPart.ThemePart.GetXDocument();
- XElement fontScheme = null;
- XElement majorFont = null;
- XElement minorFont = null;
- if (themeXDoc != null)
- {
- fontScheme = themeXDoc.Root.Element(A.themeElements).Element(A.fontScheme);
- majorFont = fontScheme.Element(A.majorFont);
- minorFont = fontScheme.Element(A.minorFont);
- }
- var rFonts = rPr.Element(W.rFonts);
- if (rFonts == null)
- {
- return;
- }
- var asciiTheme = (string)rFonts.Attribute(W.asciiTheme);
- var hAnsiTheme = (string)rFonts.Attribute(W.hAnsiTheme);
- var eastAsiaTheme = (string)rFonts.Attribute(W.eastAsiaTheme);
- var cstheme = (string)rFonts.Attribute(W.cstheme);
- string ascii = null;
- string hAnsi = null;
- string eastAsia = null;
- string cs = null;
- XElement minorLatin = null;
- string minorLatinTypeface = null;
- XElement majorLatin = null;
- string majorLatinTypeface = null;
- if (minorFont != null)
- {
- minorLatin = minorFont.Element(A.latin);
- minorLatinTypeface = (string)minorLatin.Attribute("typeface");
- }
- if (majorFont != null)
- {
- majorLatin = majorFont.Element(A.latin);
- majorLatinTypeface = (string)majorLatin.Attribute("typeface");
- }
- if (asciiTheme != null)
- {
- if (asciiTheme.StartsWith("minor") && minorLatinTypeface != null)
- {
- ascii = minorLatinTypeface;
- }
- else if (asciiTheme.StartsWith("major") && majorLatinTypeface != null)
- {
- ascii = majorLatinTypeface;
- }
- }
- if (hAnsiTheme != null)
- {
- if (hAnsiTheme.StartsWith("minor") && minorLatinTypeface != null)
- {
- hAnsi = minorLatinTypeface;
- }
- else if (hAnsiTheme.StartsWith("major") && majorLatinTypeface != null)
- {
- hAnsi = majorLatinTypeface;
- }
- }
- if (eastAsiaTheme != null)
- {
- if (eastAsiaTheme.StartsWith("minor") && minorLatinTypeface != null)
- {
- eastAsia = minorLatinTypeface;
- }
- else if (eastAsiaTheme.StartsWith("major") && majorLatinTypeface != null)
- {
- eastAsia = majorLatinTypeface;
- }
- }
- if (cstheme != null)
- {
- if (cstheme.StartsWith("minor") && minorFont != null)
- {
- cs = (string)minorFont.Element(A.cs).Attribute("typeface");
- }
- else if (cstheme.StartsWith("major") && majorFont != null)
- {
- cs = (string)majorFont.Element(A.cs).Attribute("typeface");
- }
- }
- if (ascii != null)
- {
- rFonts.SetAttributeValue(W.ascii, ascii);
- }
- if (hAnsi != null)
- {
- rFonts.SetAttributeValue(W.hAnsi, hAnsi);
- }
- if (eastAsia != null)
- {
- rFonts.SetAttributeValue(W.eastAsia, eastAsia);
- }
- if (cs != null)
- {
- rFonts.SetAttributeValue(W.cs, cs);
- }
- var firstTextNode = paraOrRun.Descendants(W.t).FirstOrDefault(t => t.Value.Length > 0);
- string str = " ";
- // if there is a run with no text in it, then no need to do any of the rest of this method.
- if (firstTextNode == null && paraOrRun.Name == W.r)
- return;
- if (firstTextNode != null)
- str = firstTextNode.Value;
- var csa = new CharStyleAttributes(pPr, rPr);
- // This module determines the font based on just the first character.
- // Technically, a run can contain characters from different Unicode code blocks, and hence should be rendered with different fonts.
- // However, Word breaks up runs that use more than one font into multiple runs. Other producers of WordprocessingML may not, so in
- // that case, this routine may need to be augmented to look at all characters in a run.
- /*
- old code
- var fontFamilies = str.select(function (c) {
- var ft = Pav.DetermineFontTypeFromCharacter(c, csa);
- switch (ft) {
- case Pav.FontType.Ascii:
- return cast(rFonts.attribute(W.ascii));
- case Pav.FontType.HAnsi:
- return cast(rFonts.attribute(W.hAnsi));
- case Pav.FontType.EastAsia:
- return cast(rFonts.attribute(W.eastAsia));
- case Pav.FontType.CS:
- return cast(rFonts.attribute(W.cs));
- default:
- return null;
- }
- })
- .where(function (f) { return f != null && f != ""; })
- .distinct()
- .select(function (f) { return new Pav.FontFamily(f); })
- .toArray();
- */
- var charToExamine = str.FirstOrDefault(c => ! WeakAndNeutralDirectionalCharacters.Contains(c));
- if (charToExamine == '\0')
- charToExamine = str[0];
- var ft = DetermineFontTypeFromCharacter(charToExamine, csa);
- string fontType = null;
- string languageType = null;
- switch (ft)
- {
- case FontType.Ascii:
- fontType = (string)rFonts.Attribute(W.ascii);
- languageType = "western";
- break;
- case FontType.HAnsi:
- fontType = (string)rFonts.Attribute(W.hAnsi);
- languageType = "western";
- break;
- case FontType.EastAsia:
- if (settings.RestrictToSupportedLanguages)
- throw new UnsupportedLanguageException("EastAsia languages are not supported");
- fontType = (string)rFonts.Attribute(W.eastAsia);
- languageType = "eastAsia";
- break;
- case FontType.CS:
- if (settings.RestrictToSupportedLanguages)
- throw new UnsupportedLanguageException("Complex script (RTL) languages are not supported");
- fontType = (string)rFonts.Attribute(W.cs);
- languageType = "bidi";
- break;
- }
- if (fontType != null)
- {
- if (paraOrRun.Attribute(PtOpenXml.FontName) == null)
- {
- XAttribute fta = new XAttribute(PtOpenXml.FontName, fontType.ToString());
- paraOrRun.Add(fta);
- }
- else
- {
- paraOrRun.Attribute(PtOpenXml.FontName).Value = fontType.ToString();
- }
- }
- if (languageType != null)
- {
- if (paraOrRun.Attribute(PtOpenXml.LanguageType) == null)
- {
- XAttribute lta = new XAttribute(PtOpenXml.LanguageType, languageType);
- paraOrRun.Add(lta);
- }
- else
- {
- paraOrRun.Attribute(PtOpenXml.LanguageType).Value = languageType;
- }
- }
- }
- public enum FontType
- {
- Ascii,
- HAnsi,
- EastAsia,
- CS
- };
- // The algorithm for this method comes from the implementer notes in [MS-OI29500].pdf
- // section 2.1.87
- // The implementer notes are at:
- // http://msdn.microsoft.com/en-us/library/ee908652.aspx
- public static FontType DetermineFontTypeFromCharacter(char ch, CharStyleAttributes csa)
- {
- // If the run has the cs element ("[ISO/IEC-29500-1] §17.3.2.7; cs") or the rtl element ("[ISO/IEC-29500-1] §17.3.2.30; rtl"),
- // then the cs (or cstheme if defined) font is used, regardless of the Unicode character values of the run’s content.
- if (csa.Rtl)
- {
- return FontType.CS;
- }
- // A large percentage of characters will fall in the following rule.
- // Unicode Block: Basic Latin
- if (ch >= 0x00 && ch <= 0x7f)
- {
- return FontType.Ascii;
- }
- // If the eastAsia (or eastAsiaTheme if defined) attribute’s value is “Times New Roman” and the ascii (or asciiTheme if defined)
- // and hAnsi (or hAnsiTheme if defined) attributes are equal, then the ascii (or asciiTheme if defined) font is used.
- if (csa.EastAsiaFont == "Times New Roman" &&
- csa.AsciiFont == csa.HAnsiFont)
- {
- return FontType.Ascii;
- }
- // Unicode BLock: Latin-1 Supplement
- if (ch >= 0xA0 && ch <= 0xFF)
- {
- if (csa.Hint == "eastAsia")
- {
- if (ch == 0xA1 ||
- ch == 0xA4 ||
- ch == 0xA7 ||
- ch == 0xA8 ||
- ch == 0xAA ||
- ch == 0xAD ||
- ch == 0xAF ||
- (ch >= 0xB0 && ch <= 0xB4) ||
- (ch >= 0xB6 && ch <= 0xBA) ||
- (ch >= 0xBC && ch <= 0xBF) ||
- ch == 0xD7 ||
- ch == 0xF7)
- {
- return FontType.EastAsia;
- }
- if (csa.EastAsiaLang == "zh-hant" ||
- csa.EastAsiaLang == "zh-hans")
- {
- if (ch == 0xE0 ||
- ch == 0xE1 ||
- (ch >= 0xE8 && ch <= 0xEA) ||
- (ch >= 0xEC && ch <= 0xED) ||
- (ch >= 0xF2 && ch <= 0xF3) ||
- (ch >= 0xF9 && ch <= 0xFA) ||
- ch == 0xFC)
- {
- return FontType.EastAsia;
- }
- }
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Latin Extended-A
- if (ch >= 0x0100 && ch <= 0x017F)
- {
- if (csa.Hint == "eastAsia")
- {
- if (csa.EastAsiaLang == "zh-hant" ||
- csa.EastAsiaLang == "zh-hans"
- /* || the character set of the east Asia (or east Asia theme) font is Chinese5 || GB2312 todo */)
- {
- return FontType.EastAsia;
- }
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Latin Extended-B
- if (ch >= 0x0180 && ch <= 0x024F)
- {
- if (csa.Hint == "eastAsia")
- {
- if (csa.EastAsiaLang == "zh-hant" ||
- csa.EastAsiaLang == "zh-hans"
- /* || the character set of the east Asia (or east Asia theme) font is Chinese5 || GB2312 todo */)
- {
- return FontType.EastAsia;
- }
- }
- return FontType.HAnsi;
- }
- // Unicode Block: IPA Extensions
- if (ch >= 0x0250 && ch <= 0x02AF)
- {
- if (csa.Hint == "eastAsia")
- {
- if (csa.EastAsiaLang == "zh-hant" ||
- csa.EastAsiaLang == "zh-hans"
- /* || the character set of the east Asia (or east Asia theme) font is Chinese5 || GB2312 todo */)
- {
- return FontType.EastAsia;
- }
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Spacing Modifier Letters
- if (ch >= 0x02B0 && ch <= 0x02FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Combining Diacritic Marks
- if (ch >= 0x0300 && ch <= 0x036F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Greek
- if (ch >= 0x0370 && ch <= 0x03CF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Cyrillic
- if (ch >= 0x0400 && ch <= 0x04FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Hebrew
- if (ch >= 0x0590 && ch <= 0x05FF)
- {
- return FontType.Ascii;
- }
- // Unicode Block: Arabic
- if (ch >= 0x0600 && ch <= 0x06FF)
- {
- return FontType.Ascii;
- }
- // Unicode Block: Syriac
- if (ch >= 0x0700 && ch <= 0x074F)
- {
- return FontType.Ascii;
- }
- // Unicode Block: Arabic Supplement
- if (ch >= 0x0750 && ch <= 0x077F)
- {
- return FontType.Ascii;
- }
- // Unicode Block: Thanna
- if (ch >= 0x0780 && ch <= 0x07BF)
- {
- return FontType.Ascii;
- }
- // Unicode Block: Hangul Jamo
- if (ch >= 0x1100 && ch <= 0x11FF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Latin Extended Additional
- if (ch >= 0x1E00 && ch <= 0x1EFF)
- {
- if (csa.Hint == "eastAsia" &&
- (csa.EastAsiaLang == "zh-hant" ||
- csa.EastAsiaLang == "zh-hans"))
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: General Punctuation
- if (ch >= 0x2000 && ch <= 0x206F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Superscripts and Subscripts
- if (ch >= 0x2070 && ch <= 0x209F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Currency Symbols
- if (ch >= 0x20A0 && ch <= 0x20CF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Combining Diacritical Marks for Symbols
- if (ch >= 0x20D0 && ch <= 0x20FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Letter-like Symbols
- if (ch >= 0x2100 && ch <= 0x214F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Number Forms
- if (ch >= 0x2150 && ch <= 0x218F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Arrows
- if (ch >= 0x2190 && ch <= 0x21FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Mathematical Operators
- if (ch >= 0x2200 && ch <= 0x22FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Miscellaneous Technical
- if (ch >= 0x2300 && ch <= 0x23FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Control Pictures
- if (ch >= 0x2400 && ch <= 0x243F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Optical Character Recognition
- if (ch >= 0x2440 && ch <= 0x245F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Enclosed Alphanumerics
- if (ch >= 0x2460 && ch <= 0x24FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Box Drawing
- if (ch >= 0x2500 && ch <= 0x257F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Block Elements
- if (ch >= 0x2580 && ch <= 0x259F)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Geometric Shapes
- if (ch >= 0x25A0 && ch <= 0x25FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Miscellaneous Symbols
- if (ch >= 0x2600 && ch <= 0x26FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Dingbats
- if (ch >= 0x2700 && ch <= 0x27BF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: CJK Radicals Supplement
- if (ch >= 0x2E80 && ch <= 0x2EFF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Kangxi Radicals
- if (ch >= 0x2F00 && ch <= 0x2FDF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Ideographic Description Characters
- if (ch >= 0x2FF0 && ch <= 0x2FFF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: CJK Symbols and Punctuation
- if (ch >= 0x3000 && ch <= 0x303F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Hiragana
- if (ch >= 0x3040 && ch <= 0x309F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Katakana
- if (ch >= 0x30A0 && ch <= 0x30FF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Bopomofo
- if (ch >= 0x3100 && ch <= 0x312F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Hangul Compatibility Jamo
- if (ch >= 0x3130 && ch <= 0x318F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Kanbun
- if (ch >= 0x3190 && ch <= 0x319F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Enclosed CJK Letters and Months
- if (ch >= 0x3200 && ch <= 0x32FF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: CJK Compatibility
- if (ch >= 0x3300 && ch <= 0x33FF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: CJK Unified Ideographs Extension A
- if (ch >= 0x3400 && ch <= 0x4DBF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: CJK Unified Ideographs
- if (ch >= 0x4E00 && ch <= 0x9FAF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Yi Syllables
- if (ch >= 0xA000 && ch <= 0xA48F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Yi Radicals
- if (ch >= 0xA490 && ch <= 0xA4CF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Hangul Syllables
- if (ch >= 0xAC00 && ch <= 0xD7AF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: High Surrogates
- if (ch >= 0xD800 && ch <= 0xDB7F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: High Private Use Surrogates
- if (ch >= 0xDB80 && ch <= 0xDBFF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Low Surrogates
- if (ch >= 0xDC00 && ch <= 0xDFFF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Private Use Area
- if (ch >= 0xE000 && ch <= 0xF8FF)
- {
- if (csa.Hint == "eastAsia")
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: CJK Compatibility Ideographs
- if (ch >= 0xF900 && ch <= 0xFAFF)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Alphabetic Presentation Forms
- if (ch >= 0xFB00 && ch <= 0xFB4F)
- {
- if (csa.Hint == "eastAsia")
- {
- if (ch >= 0xFB00 && ch <= 0xFB1C)
- return FontType.EastAsia;
- if (ch >= 0xFB1D && ch <= 0xFB4F)
- return FontType.Ascii;
- }
- return FontType.HAnsi;
- }
- // Unicode Block: Arabic Presentation Forms-A
- if (ch >= 0xFB50 && ch <= 0xFDFF)
- {
- return FontType.Ascii;
- }
- // Unicode Block: CJK Compatibility Forms
- if (ch >= 0xFE30 && ch <= 0xFE4F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Small Form Variants
- if (ch >= 0xFE50 && ch <= 0xFE6F)
- {
- return FontType.EastAsia;
- }
- // Unicode Block: Arabic Presentation Forms-B
- if (ch >= 0xFE70 && ch <= 0xFEFE)
- {
- return FontType.Ascii;
- }
- // Unicode Block: Halfwidth and Fullwidth Forms
- if (ch >= 0xFF00 && ch <= 0xFFEF)
- {
- return FontType.EastAsia;
- }
- return FontType.HAnsi;
- }
- private class FormattingAssemblerInfo
- {
- public string DefaultParagraphStyleName;
- public string DefaultCharacterStyleName;
- public string DefaultTableStyleName;
- public Dictionary<string, XElement> RolledCharacterStyles;
- public FormattingAssemblerInfo()
- {
- RolledCharacterStyles = new Dictionary<string, XElement>();
- }
- }
- // CachedParaInfo is an optimization for the case where a paragraph contains thousands of runs.
- private class CachedParaInfo
- {
- public string ParagraphStyleName;
- public XElement ParagraphProperties;
- }
- public class UnsupportedNumberingFormatException : Exception
- {
- public UnsupportedNumberingFormatException(string message) : base(message) { }
- }
- public class UnsupportedLanguageException : Exception
- {
- public UnsupportedLanguageException(string message) : base(message) { }
- }
- }
- }
|