12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755 |
- // 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;
- List<XAttribute> listItemHtmlAttributes = new List<XAttribute>();
- 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);
- string numFmt = null;
- string format = null;
- numFmt = (string)listItemLvl.Elements(W.numFmt).Attributes(W.val).FirstOrDefault();
- if (numFmt == null)
- {
- var mcAlternativeContent = listItemLvl.Descendants(MC.AlternateContent).FirstOrDefault();
- if (mcAlternativeContent != null)
- {
- var choice = mcAlternativeContent.Element(MC.Choice);
- if (choice != null)
- {
- numFmt = (string)choice.Elements(W.numFmt).Attributes(W.val).FirstOrDefault();
- format = (string)choice.Elements(W.numFmt).Attributes(W.format).FirstOrDefault();
- }
- }
- }
- if (numFmt == "bullet")
- {
- listItemRunProps.Elements(W.rtl).Remove();
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStructure, "ul")
- );
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: circle;")
- );
- }
- 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);
- }
- }
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStructure, "ol")
- );
- if (numFmt == "decimal")
- {
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: decimal;")
- );
- }
- else if (numFmt == "lowerLetter")
- {
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: lower-alpha;")
- );
- }
- else if (numFmt == "lowerRoman")
- {
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: lower-roman;")
- );
- }
- else if (numFmt == "upperLetter")
- {
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: upper-alpha;")
- );
- }
- else if (numFmt == "upperRoman")
- {
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: upper-roman;")
- );
- }
- else if (numFmt == "custom" && format.StartsWith("0"))
- {
- listItemHtmlAttributes.Add(
- new XAttribute(PtOpenXml.HtmlStyle, "list-style-type: decimal-leading-zero;")
- );
- }
- }
- }
- 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('.');
- ListItemRetriever.ListItemInfo listItemInfo2 = element.Annotation<ListItemRetriever.ListItemInfo>();
- var listItemRun = new XElement(W.r,
- new XAttribute(PtOpenXml.ListItemRun, levelNumsString),
- listItemInfo2 != null ? new XAttribute(PtOpenXml.AbstractNumId, listItemInfo2.AbstractNumId) : null,
- 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 tabRun = suffix != null ?
- new XElement(W.r,
- new XAttribute(PtOpenXml.ListItemRun, levelNumsString),
- listItemRunProps,
- suffix) : null;
- bool isDeleted = false;
- bool isInserted = false;
- XAttribute authorAtt = null;
- XAttribute dateAtt = null;
- var paraDelElement = newParaProps
- .Elements(W.rPr)
- .Elements(W.del)
- .FirstOrDefault();
- if (paraDelElement != null)
- {
- isDeleted = true;
- authorAtt = paraDelElement.Attribute(W.author);
- dateAtt = paraDelElement.Attribute(W.date);
- }
- var paraInsElement = newParaProps
- .Elements(W.rPr)
- .Elements(W.ins)
- .FirstOrDefault();
- if (paraInsElement != null)
- {
- isInserted = true;
- authorAtt = paraInsElement.Attribute(W.author);
- dateAtt = paraInsElement.Attribute(W.date);
- }
- var paragraphBefore = element
- .SiblingsBeforeSelfReverseDocumentOrder()
- .FirstOrDefault();
- if (paragraphBefore != null)
- {
- var paraInsElement2 = paragraphBefore
- .Elements(W.pPr)
- .Elements(W.rPr)
- .Elements(W.ins)
- .FirstOrDefault();
- if (paraInsElement2 != null)
- {
- isInserted = true;
- authorAtt = paraInsElement2.Attribute(W.author);
- dateAtt = paraInsElement2.Attribute(W.date);
- }
- }
- #if false
- <w:p w14:paraId="448CD560"
- w14:textId="77777777"
- w:rsidR="003C33D5"
- w:rsidRDefault="003C33D5"
- w:rsidP="003C33D5">
- <w:pPr>
- <w:pStyle w:val="ListParagraph"/>
- <w:numPr>
- <w:ilvl w:val="0"/>
- <w:numId w:val="1"/>
- </w:numPr>
- <w:pPrChange w:id="4"
- w:author="e"
- w:date="2020-02-07T18:26:00Z">
- <w:pPr/>
- </w:pPrChange>
- </w:pPr>
- <w:r>
- <w:t>When you click Online Video, you can paste in the embed code for the video you want to add.</w:t>
- </w:r>
- </w:p>
- #endif
- var pPrChange = element
- .Elements(W.pPr)
- .Elements(W.pPrChange)
- .FirstOrDefault();
- if (pPrChange != null)
- {
- authorAtt = pPrChange.Attribute(W.author);
- dateAtt = pPrChange.Attribute(W.date);
- var thisNumPr = element
- .Elements(W.pPr)
- .Elements(W.numPr)
- .FirstOrDefault();
- var thisNumPrChange = pPrChange
- .Elements(W.numPr)
- .FirstOrDefault();
- if (thisNumPr != null && thisNumPrChange == null)
- isInserted = true;
- if (thisNumPr == null && thisNumPrChange != null)
- isDeleted = true;
- }
- if (isDeleted)
- {
- // convert listItemRun and tabRun to their deleted equivalents
- var highestId = wDoc
- .MainDocumentPart
- .GetXDocument()
- .Descendants()
- .Attributes(W.id)
- .Select(id =>
- {
- int numId;
- if (int.TryParse((string)id, out numId))
- return numId;
- else
- return 0;
- })
- .Max();
- listItemRun = new XElement(W.del,
- new XAttribute(W.id, highestId + 1),
- authorAtt,
- dateAtt,
- (XElement)TransformToDeleted(listItemRun));
- tabRun = new XElement(W.del,
- new XAttribute(W.id, highestId + 2),
- authorAtt,
- dateAtt,
- (XElement)TransformToDeleted(tabRun));
- }
- else
- {
- if (isInserted)
- {
- // convert listItemRun and tabRun to their inserted equivalents
- var highestId = wDoc
- .MainDocumentPart
- .GetXDocument()
- .Descendants()
- .Attributes(W.id)
- .Select(id =>
- {
- int numId;
- if (int.TryParse((string)id, out numId))
- return numId;
- else
- return 0;
- })
- .Max();
- listItemRun = new XElement(W.ins,
- new XAttribute(W.id, highestId + 1),
- authorAtt,
- dateAtt,
- listItemRun);
- tabRun = new XElement(W.ins,
- new XAttribute(W.id, highestId + 2),
- authorAtt,
- dateAtt,
- tabRun);
- }
- }
- XElement newPara = new XElement(W.p,
- element.Attribute(PtOpenXml.FontName),
- element.Attribute(PtOpenXml.LanguageType),
- element.Attribute(PtOpenXml.Unid),
- new XAttribute(PtOpenXml.AbstractNumId, abstractNumId),
- listItemHtmlAttributes,
- newParaProps,
- listItemRun,
- tabRun,
- 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 object TransformToDeleted(XNode node)
- {
- XElement element = node as XElement;
- if (element != null)
- {
- if (element.Name == W.t)
- return new XElement(W.delText, element.Value);
- return new XElement(element.Name,
- element.Attributes(),
- element.Nodes().Select(n => TransformToDeleted(n)));
- }
- 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 => WordprocessingMLUtil.StringToTwips((string)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.HtmlStructure,
- PtOpenXml.HtmlStyle,
- 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 = WordprocessingMLUtil.StringToTwips((string)e.Attribute(W.pos)),
- Pri = 1,
- Element = e,
- }
- );
- var lps = lowerPriorityElement.Elements().Select(e =>
- new
- {
- Pos = WordprocessingMLUtil.StringToTwips((string)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 => WordprocessingMLUtil.StringToTwips((string)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) { }
- }
- }
- }
|