HtmlToWmlConverterCore.cs 212 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359
  1. // Copyright (c) Microsoft. All rights reserved.
  2. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  3. /***************************************************************************
  4. * HTML elements handled in this module:
  5. *
  6. * a
  7. * b
  8. * body
  9. * caption
  10. * div
  11. * em
  12. * h1, h2, h3, h4, h5, h6, h7, h8
  13. * hr
  14. * html
  15. * i
  16. * blockquote
  17. * img
  18. * li
  19. * ol
  20. * p
  21. * s
  22. * span
  23. * strong
  24. * style
  25. * sub
  26. * sup
  27. * table
  28. * tbody
  29. * td
  30. * th
  31. * tr
  32. * u
  33. * ul
  34. * br
  35. * tt
  36. * code
  37. * kbd
  38. * samp
  39. * pre
  40. *
  41. * HTML elements that are handled by recursively processing descedants
  42. *
  43. * article
  44. * hgroup
  45. * nav
  46. * section
  47. * dd
  48. * dl
  49. * dt
  50. * figure
  51. * main
  52. * abbr
  53. * bdi
  54. * bdo
  55. * cite
  56. * data
  57. * dfn
  58. * mark
  59. * q
  60. * rp
  61. * rt
  62. * ruby
  63. * small
  64. * time
  65. * var
  66. * wbr
  67. *
  68. * HTML elements ignored in this module
  69. *
  70. * head
  71. *
  72. ***************************************************************************/
  73. // need to research all of the html attributes that take effect, such as border="1" and somehow work into the rendering system.
  74. // note that some of these 'inherit' so need to implement correct logic.
  75. // this module has not been fully engineered to work with RTL languages. This is a pending work item. There are issues involved,
  76. // including that there is RTL content in HTML that can't be represented in WordprocessingML, although this probably is rare.
  77. // The reverse is not true - all RTL WordprocessingML can be represented in HTML, but there is some HTML RTL content that can only
  78. // be approximated in WordprocessingML.
  79. // have I handled all forms of colors? see GetWmlColorFromExpression in HtmlToWmlCssApplier
  80. // min-height and max-height not implemented yet.
  81. // internal hyperlinks are not supported. I believe it possible - bookmarks can be created, hyperlinks to the bookmark can be created.
  82. // To be supported in future
  83. // page-break-before:always
  84. // ************************************************************************
  85. // ToDo at some point in the future
  86. // I'm not implementing caption exactly correctly. If caption does not have borders, then there needs to not be a border around the table,
  87. // otherwise it looks as if caption has a border. See T1200. If there is, per the markup, a table border, but caption does not have a border,
  88. // then need to make sure that all of the cells below the caption have the border on the appropriate sides so that it looks as if the table
  89. // has a border.
  90. using System;
  91. using System.Collections.Generic;
  92. using System.Drawing;
  93. using System.Drawing.Imaging;
  94. using System.IO;
  95. using System.Linq;
  96. using System.Text;
  97. using System.Xml.Linq;
  98. using DocumentFormat.OpenXml.Packaging;
  99. using OpenXmlPowerTools;
  100. using OpenXmlPowerTools.HtmlToWml;
  101. using OpenXmlPowerTools.HtmlToWml.CSS;
  102. using System.Text.RegularExpressions;
  103. namespace OpenXmlPowerTools.HtmlToWml
  104. {
  105. public class ElementToStyleMap
  106. {
  107. public string ElementName;
  108. public string StyleName;
  109. }
  110. public static class LocalExtensions
  111. {
  112. public static CssExpression GetProp(this XElement element, string propertyName)
  113. {
  114. Dictionary<string, CssExpression> d = element.Annotation<Dictionary<string, CssExpression>>();
  115. if (d != null)
  116. {
  117. if (d.ContainsKey(propertyName))
  118. return d[propertyName];
  119. }
  120. return null;
  121. }
  122. }
  123. public class HtmlToWmlConverterCore
  124. {
  125. public static WmlDocument ConvertHtmlToWml(
  126. string defaultCss,
  127. string authorCss,
  128. string userCss,
  129. XElement xhtml,
  130. HtmlToWmlConverterSettings settings)
  131. {
  132. return ConvertHtmlToWml(defaultCss, authorCss, userCss, xhtml, settings, null, null);
  133. }
  134. public static WmlDocument ConvertHtmlToWml(
  135. string defaultCss,
  136. string authorCss,
  137. string userCss,
  138. XElement xhtml,
  139. HtmlToWmlConverterSettings settings,
  140. WmlDocument emptyDocument,
  141. string annotatedHtmlDumpFileName)
  142. {
  143. if (emptyDocument == null)
  144. emptyDocument = HtmlToWmlConverter.EmptyDocument;
  145. NextRectId = 1025;
  146. // clone and transform all element names to lower case
  147. XElement html = (XElement)TransformToLower(xhtml);
  148. // add pseudo cells for rowspan
  149. html = (XElement)AddPseudoCells(html);
  150. html = (XElement)TransformWhiteSpaceInPreCodeTtKbdSamp(html, false, false);
  151. CssDocument defaultCssDoc, userCssDoc, authorCssDoc;
  152. CssApplier.ApplyAllCss(
  153. defaultCss,
  154. authorCss,
  155. userCss,
  156. html,
  157. settings,
  158. out defaultCssDoc,
  159. out authorCssDoc,
  160. out userCssDoc,
  161. annotatedHtmlDumpFileName);
  162. WmlDocument newWmlDocument;
  163. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(emptyDocument))
  164. {
  165. using (WordprocessingDocument wDoc = streamDoc.GetWordprocessingDocument())
  166. {
  167. AnnotateOlUl(wDoc, html);
  168. UpdateMainDocumentPart(wDoc, html, settings);
  169. NormalizeMainDocumentPart(wDoc);
  170. StylesUpdater.UpdateStylesPart(wDoc, html, settings, defaultCssDoc, authorCssDoc, userCssDoc);
  171. HtmlToWmlFontUpdater.UpdateFontsPart(wDoc, html, settings);
  172. ThemeUpdater.UpdateThemePart(wDoc, html, settings);
  173. NumberingUpdater.UpdateNumberingPart(wDoc, html, settings);
  174. }
  175. newWmlDocument = streamDoc.GetModifiedWmlDocument();
  176. }
  177. return newWmlDocument;
  178. }
  179. private static object TransformToLower(XNode node)
  180. {
  181. XElement element = node as XElement;
  182. if (element != null)
  183. {
  184. XElement e = new XElement(element.Name.LocalName.ToLower(),
  185. element.Attributes().Select(a => new XAttribute(a.Name.LocalName.ToLower(), a.Value)),
  186. element.Nodes().Select(n => TransformToLower(n)));
  187. return e;
  188. }
  189. return node;
  190. }
  191. private static XElement AddPseudoCells(XElement html)
  192. {
  193. while (true)
  194. {
  195. var rowSpanCell = html
  196. .Descendants(XhtmlNoNamespace.td)
  197. .FirstOrDefault(td => td.Attribute(XhtmlNoNamespace.rowspan) != null && td.Attribute("HtmlToWmlVMergeRestart") == null);
  198. if (rowSpanCell == null)
  199. break;
  200. rowSpanCell.Add(
  201. new XAttribute("HtmlToWmlVMergeRestart", "true"));
  202. int colNumber = rowSpanCell.ElementsBeforeSelf(XhtmlNoNamespace.td).Count();
  203. int numberPseudoToAdd = (int)rowSpanCell.Attribute(XhtmlNoNamespace.rowspan) - 1;
  204. var tr = rowSpanCell.Ancestors(XhtmlNoNamespace.tr).FirstOrDefault();
  205. if (tr == null)
  206. throw new OpenXmlPowerToolsException("Invalid HTML - td does not have parent tr");
  207. var rowsToAddTo = tr
  208. .ElementsAfterSelf(XhtmlNoNamespace.tr)
  209. .Take(numberPseudoToAdd)
  210. .ToList();
  211. foreach (var rowToAddTo in rowsToAddTo)
  212. {
  213. if (colNumber > 0)
  214. {
  215. var tdToAddAfter = rowToAddTo
  216. .Elements(XhtmlNoNamespace.td)
  217. .Skip(colNumber - 1)
  218. .FirstOrDefault();
  219. var td = new XElement(XhtmlNoNamespace.td,
  220. rowSpanCell.Attributes(),
  221. new XAttribute("HtmlToWmlVMergeNoRestart", "true"));
  222. tdToAddAfter.AddAfterSelf(td);
  223. }
  224. else
  225. {
  226. var tdToAddBefore = rowToAddTo
  227. .Elements(XhtmlNoNamespace.td)
  228. .Skip(colNumber)
  229. .FirstOrDefault();
  230. var td = new XElement(XhtmlNoNamespace.td,
  231. rowSpanCell.Attributes(),
  232. new XAttribute("HtmlToWmlVMergeNoRestart", "true"));
  233. tdToAddBefore.AddBeforeSelf(td);
  234. }
  235. }
  236. }
  237. return html;
  238. }
  239. public class NumberedItemAnnotation
  240. {
  241. public int numId;
  242. public int ilvl;
  243. public string listStyleType;
  244. }
  245. private static void AnnotateOlUl(WordprocessingDocument wDoc, XElement html)
  246. {
  247. int numId;
  248. NumberingUpdater.GetNextNumId(wDoc, out numId);
  249. foreach (var item in html.DescendantsAndSelf().Where(d => d.Name == XhtmlNoNamespace.ol || d.Name == XhtmlNoNamespace.ul))
  250. {
  251. XElement parentOlUl = item.Ancestors().Where(a => a.Name == XhtmlNoNamespace.ol || a.Name == XhtmlNoNamespace.ul).LastOrDefault();
  252. int numIdToUse;
  253. if (parentOlUl != null)
  254. numIdToUse = parentOlUl.Annotation<NumberedItemAnnotation>().numId;
  255. else
  256. numIdToUse = numId++;
  257. string lst = CssApplier.GetComputedPropertyValue(null, item, "list-style-type", null).ToString();
  258. item.AddAnnotation(new NumberedItemAnnotation
  259. {
  260. numId = numIdToUse,
  261. ilvl = item.Ancestors().Where(a => a.Name == XhtmlNoNamespace.ol || a.Name == XhtmlNoNamespace.ul).Count(),
  262. listStyleType = lst,
  263. });
  264. }
  265. }
  266. private static void UpdateMainDocumentPart(WordprocessingDocument wDoc, XElement html, HtmlToWmlConverterSettings settings)
  267. {
  268. XDocument xDoc = XDocument.Parse(
  269. @"<w:document xmlns:wpc='http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas'
  270. xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'
  271. xmlns:o='urn:schemas-microsoft-com:office:office'
  272. xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships'
  273. xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math'
  274. xmlns:v='urn:schemas-microsoft-com:vml'
  275. xmlns:wp14='http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing'
  276. xmlns:wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'
  277. xmlns:w10='urn:schemas-microsoft-com:office:word'
  278. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'
  279. xmlns:w14='http://schemas.microsoft.com/office/word/2010/wordml'
  280. xmlns:wpg='http://schemas.microsoft.com/office/word/2010/wordprocessingGroup'
  281. xmlns:wpi='http://schemas.microsoft.com/office/word/2010/wordprocessingInk'
  282. xmlns:wne='http://schemas.microsoft.com/office/word/2006/wordml'
  283. xmlns:wps='http://schemas.microsoft.com/office/word/2010/wordprocessingShape'
  284. mc:Ignorable='w14 wp14'/>");
  285. XElement body = new XElement(W.body,
  286. Transform(html, settings, wDoc, NextExpected.Paragraph, false),
  287. settings.SectPr);
  288. AddNonBreakingSpacesForSpansWithWidth(wDoc, body);
  289. body = (XElement)TransformAndOrderElements(body);
  290. foreach (var d in body.Descendants())
  291. d.Attributes().Where(a => a.Name.Namespace == PtOpenXml.pt).Remove();
  292. xDoc.Root.Add(body);
  293. wDoc.MainDocumentPart.PutXDocument(xDoc);
  294. }
  295. private static object TransformWhiteSpaceInPreCodeTtKbdSamp(XNode node, bool inPre, bool inOther)
  296. {
  297. XElement element = node as XElement;
  298. if (element != null)
  299. {
  300. if (element.Name == XhtmlNoNamespace.pre)
  301. {
  302. return new XElement(element.Name,
  303. element.Attributes(),
  304. element.Nodes().Select(n => TransformWhiteSpaceInPreCodeTtKbdSamp(n, true, false)));
  305. }
  306. if (element.Name == XhtmlNoNamespace.code ||
  307. element.Name == XhtmlNoNamespace.tt ||
  308. element.Name == XhtmlNoNamespace.kbd ||
  309. element.Name == XhtmlNoNamespace.samp)
  310. {
  311. return new XElement(element.Name,
  312. element.Attributes(),
  313. element.Nodes().Select(n => TransformWhiteSpaceInPreCodeTtKbdSamp(n, false, true)));
  314. }
  315. return new XElement(element.Name,
  316. element.Attributes(),
  317. element.Nodes().Select(n => TransformWhiteSpaceInPreCodeTtKbdSamp(n, false, false)));
  318. }
  319. XText xt = node as XText;
  320. if (xt != null && inPre)
  321. {
  322. var val = xt.Value.TrimStart('\r', '\n').TrimEnd('\r', '\n');
  323. var groupedCharacters = val.GroupAdjacent(c => c == '\r' || c == '\n');
  324. var newNodes = groupedCharacters.Select(g =>
  325. {
  326. if (g.Key == true)
  327. return (object)(new XElement(XhtmlNoNamespace.br));
  328. string x = g.Select(c => c.ToString()).StringConcatenate();
  329. return new XText(x);
  330. });
  331. return newNodes;
  332. }
  333. if (xt != null && inOther)
  334. {
  335. var val = xt.Value.TrimStart('\r', '\n', '\t', ' ').TrimEnd('\r', '\n', '\t', ' ');
  336. return new XText(val);
  337. }
  338. return node;
  339. }
  340. private static Dictionary<XName, int> Order_pPr = new Dictionary<XName, int>
  341. {
  342. { W.pStyle, 10 },
  343. { W.keepNext, 20 },
  344. { W.keepLines, 30 },
  345. { W.pageBreakBefore, 40 },
  346. { W.framePr, 50 },
  347. { W.widowControl, 60 },
  348. { W.numPr, 70 },
  349. { W.suppressLineNumbers, 80 },
  350. { W.pBdr, 90 },
  351. { W.shd, 100 },
  352. { W.tabs, 120 },
  353. { W.suppressAutoHyphens, 130 },
  354. { W.kinsoku, 140 },
  355. { W.wordWrap, 150 },
  356. { W.overflowPunct, 160 },
  357. { W.topLinePunct, 170 },
  358. { W.autoSpaceDE, 180 },
  359. { W.autoSpaceDN, 190 },
  360. { W.bidi, 200 },
  361. { W.adjustRightInd, 210 },
  362. { W.snapToGrid, 220 },
  363. { W.spacing, 230 },
  364. { W.ind, 240 },
  365. { W.contextualSpacing, 250 },
  366. { W.mirrorIndents, 260 },
  367. { W.suppressOverlap, 270 },
  368. { W.jc, 280 },
  369. { W.textDirection, 290 },
  370. { W.textAlignment, 300 },
  371. { W.textboxTightWrap, 310 },
  372. { W.outlineLvl, 320 },
  373. { W.divId, 330 },
  374. { W.cnfStyle, 340 },
  375. { W.rPr, 350 },
  376. { W.sectPr, 360 },
  377. { W.pPrChange, 370 },
  378. };
  379. private static Dictionary<XName, int> Order_rPr = new Dictionary<XName, int>
  380. {
  381. { W.ins, 10 },
  382. { W.del, 20 },
  383. { W.rStyle, 30 },
  384. { W.rFonts, 40 },
  385. { W.b, 50 },
  386. { W.bCs, 60 },
  387. { W.i, 70 },
  388. { W.iCs, 80 },
  389. { W.caps, 90 },
  390. { W.smallCaps, 100 },
  391. { W.strike, 110 },
  392. { W.dstrike, 120 },
  393. { W.outline, 130 },
  394. { W.shadow, 140 },
  395. { W.emboss, 150 },
  396. { W.imprint, 160 },
  397. { W.noProof, 170 },
  398. { W.snapToGrid, 180 },
  399. { W.vanish, 190 },
  400. { W.webHidden, 200 },
  401. { W.color, 210 },
  402. { W.spacing, 220 },
  403. { W._w, 230 },
  404. { W.kern, 240 },
  405. { W.position, 250 },
  406. { W.sz, 260 },
  407. { W14.wShadow, 270 },
  408. { W14.wTextOutline, 280 },
  409. { W14.wTextFill, 290 },
  410. { W14.wScene3d, 300 },
  411. { W14.wProps3d, 310 },
  412. { W.szCs, 320 },
  413. { W.highlight, 330 },
  414. { W.u, 340 },
  415. { W.effect, 350 },
  416. { W.bdr, 360 },
  417. { W.shd, 370 },
  418. { W.fitText, 380 },
  419. { W.vertAlign, 390 },
  420. { W.rtl, 400 },
  421. { W.cs, 410 },
  422. { W.em, 420 },
  423. { W.lang, 430 },
  424. { W.eastAsianLayout, 440 },
  425. { W.specVanish, 450 },
  426. { W.oMath, 460 },
  427. };
  428. private static Dictionary<XName, int> Order_tblPr = new Dictionary<XName, int>
  429. {
  430. { W.tblStyle, 10 },
  431. { W.tblpPr, 20 },
  432. { W.tblOverlap, 30 },
  433. { W.bidiVisual, 40 },
  434. { W.tblStyleRowBandSize, 50 },
  435. { W.tblStyleColBandSize, 60 },
  436. { W.tblW, 70 },
  437. { W.jc, 80 },
  438. { W.tblCellSpacing, 90 },
  439. { W.tblInd, 100 },
  440. { W.tblBorders, 110 },
  441. { W.shd, 120 },
  442. { W.tblLayout, 130 },
  443. { W.tblCellMar, 140 },
  444. { W.tblLook, 150 },
  445. { W.tblCaption, 160 },
  446. { W.tblDescription, 170 },
  447. };
  448. private static Dictionary<XName, int> Order_tblBorders = new Dictionary<XName, int>
  449. {
  450. { W.top, 10 },
  451. { W.left, 20 },
  452. { W.start, 30 },
  453. { W.bottom, 40 },
  454. { W.right, 50 },
  455. { W.end, 60 },
  456. { W.insideH, 70 },
  457. { W.insideV, 80 },
  458. };
  459. private static Dictionary<XName, int> Order_tcPr = new Dictionary<XName, int>
  460. {
  461. { W.cnfStyle, 10 },
  462. { W.tcW, 20 },
  463. { W.gridSpan, 30 },
  464. { W.hMerge, 40 },
  465. { W.vMerge, 50 },
  466. { W.tcBorders, 60 },
  467. { W.shd, 70 },
  468. { W.noWrap, 80 },
  469. { W.tcMar, 90 },
  470. { W.textDirection, 100 },
  471. { W.tcFitText, 110 },
  472. { W.vAlign, 120 },
  473. { W.hideMark, 130 },
  474. { W.headers, 140 },
  475. };
  476. private static Dictionary<XName, int> Order_tcBorders = new Dictionary<XName, int>
  477. {
  478. { W.top, 10 },
  479. { W.start, 20 },
  480. { W.left, 30 },
  481. { W.bottom, 40 },
  482. { W.right, 50 },
  483. { W.end, 60 },
  484. { W.insideH, 70 },
  485. { W.insideV, 80 },
  486. { W.tl2br, 90 },
  487. { W.tr2bl, 100 },
  488. };
  489. private static Dictionary<XName, int> Order_pBdr = new Dictionary<XName, int>
  490. {
  491. { W.top, 10 },
  492. { W.left, 20 },
  493. { W.bottom, 30 },
  494. { W.right, 40 },
  495. { W.between, 50 },
  496. { W.bar, 60 },
  497. };
  498. private static object TransformAndOrderElements(XNode node)
  499. {
  500. XElement element = node as XElement;
  501. if (element != null)
  502. {
  503. if (element.Name == W.pPr)
  504. return new XElement(element.Name,
  505. element.Attributes(),
  506. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  507. {
  508. if (Order_pPr.ContainsKey(e.Name))
  509. return Order_pPr[e.Name];
  510. return 999;
  511. }));
  512. if (element.Name == W.rPr)
  513. return new XElement(element.Name,
  514. element.Attributes(),
  515. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  516. {
  517. if (Order_rPr.ContainsKey(e.Name))
  518. return Order_rPr[e.Name];
  519. return 999;
  520. }));
  521. if (element.Name == W.tblPr)
  522. return new XElement(element.Name,
  523. element.Attributes(),
  524. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  525. {
  526. if (Order_tblPr.ContainsKey(e.Name))
  527. return Order_tblPr[e.Name];
  528. return 999;
  529. }));
  530. if (element.Name == W.tcPr)
  531. return new XElement(element.Name,
  532. element.Attributes(),
  533. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  534. {
  535. if (Order_tcPr.ContainsKey(e.Name))
  536. return Order_tcPr[e.Name];
  537. return 999;
  538. }));
  539. if (element.Name == W.tcBorders)
  540. return new XElement(element.Name,
  541. element.Attributes(),
  542. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  543. {
  544. if (Order_tcBorders.ContainsKey(e.Name))
  545. return Order_tcBorders[e.Name];
  546. return 999;
  547. }));
  548. if (element.Name == W.tblBorders)
  549. return new XElement(element.Name,
  550. element.Attributes(),
  551. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  552. {
  553. if (Order_tblBorders.ContainsKey(e.Name))
  554. return Order_tblBorders[e.Name];
  555. return 999;
  556. }));
  557. if (element.Name == W.pBdr)
  558. return new XElement(element.Name,
  559. element.Attributes(),
  560. element.Elements().Select(e => (XElement)TransformAndOrderElements(e)).OrderBy(e =>
  561. {
  562. if (Order_pBdr.ContainsKey(e.Name))
  563. return Order_pBdr[e.Name];
  564. return 999;
  565. }));
  566. if (element.Name == W.p)
  567. return new XElement(element.Name,
  568. element.Attributes(),
  569. element.Elements(W.pPr).Select(e => (XElement)TransformAndOrderElements(e)),
  570. element.Elements().Where(e => e.Name != W.pPr).Select(e => (XElement)TransformAndOrderElements(e)));
  571. if (element.Name == W.r)
  572. return new XElement(element.Name,
  573. element.Attributes(),
  574. element.Elements(W.rPr).Select(e => (XElement)TransformAndOrderElements(e)),
  575. element.Elements().Where(e => e.Name != W.rPr).Select(e => (XElement)TransformAndOrderElements(e)));
  576. return new XElement(element.Name,
  577. element.Attributes(),
  578. element.Nodes().Select(n => TransformAndOrderElements(n)));
  579. }
  580. return node;
  581. }
  582. private static void AddNonBreakingSpacesForSpansWithWidth(WordprocessingDocument wDoc, XElement body)
  583. {
  584. List<XElement> runsWithWidth = body
  585. .Descendants(W.r)
  586. .Where(r => r.Attribute(PtOpenXml.HtmlToWmlCssWidth) != null)
  587. .ToList();
  588. foreach (XElement run in runsWithWidth)
  589. {
  590. XElement p = run.Ancestors(W.p).FirstOrDefault();
  591. XElement pPr = p != null ? p.Element(W.pPr) : null;
  592. XElement rPr = run.Element(W.rPr);
  593. XElement rFonts = rPr != null ? rPr.Element(W.rFonts) : null;
  594. string str = run.Descendants(W.t).Select(t => (string) t).StringConcatenate();
  595. if ((pPr == null) || (rPr == null) || (rFonts == null) || (str == "")) continue;
  596. AdjustFontAttributes(wDoc, run, pPr, rPr);
  597. var csa = new CharStyleAttributes(pPr, rPr);
  598. char charToExamine = str.FirstOrDefault(c => !WeakAndNeutralDirectionalCharacters.Contains(c));
  599. if (charToExamine == '\0')
  600. charToExamine = str[0];
  601. FontType ft = DetermineFontTypeFromCharacter(charToExamine, csa);
  602. string fontType = null;
  603. string languageType = null;
  604. switch (ft)
  605. {
  606. case FontType.Ascii:
  607. fontType = (string) rFonts.Attribute(W.ascii);
  608. languageType = "western";
  609. break;
  610. case FontType.HAnsi:
  611. fontType = (string) rFonts.Attribute(W.hAnsi);
  612. languageType = "western";
  613. break;
  614. case FontType.EastAsia:
  615. fontType = (string) rFonts.Attribute(W.eastAsia);
  616. languageType = "eastAsia";
  617. break;
  618. case FontType.CS:
  619. fontType = (string) rFonts.Attribute(W.cs);
  620. languageType = "bidi";
  621. break;
  622. }
  623. if (fontType != null)
  624. {
  625. XAttribute fontNameAttribute = run.Attribute(PtOpenXml.FontName);
  626. if (fontNameAttribute == null)
  627. run.Add(new XAttribute(PtOpenXml.FontName, fontType));
  628. else
  629. fontNameAttribute.SetValue(fontType);
  630. }
  631. if (languageType != null)
  632. {
  633. XAttribute languageTypeAttribute = run.Attribute(PtOpenXml.LanguageType);
  634. if (languageTypeAttribute == null)
  635. {
  636. run.Add(new XAttribute(PtOpenXml.LanguageType, languageType));
  637. }
  638. else
  639. {
  640. languageTypeAttribute.SetValue(languageType);
  641. }
  642. }
  643. int pixWidth = CalcWidthOfRunInPixels(run) ?? 0;
  644. // calc width of non breaking spaces
  645. var npSpRun = new XElement(W.r,
  646. run.Attributes(),
  647. run.Elements(W.rPr),
  648. new XElement(W.t, "\u00a0"));
  649. int nbSpWidth = CalcWidthOfRunInPixels(npSpRun) ?? 0;
  650. if (nbSpWidth == 0)
  651. continue;
  652. // get HtmlToWmlCssWidth attribute
  653. var cssWidth = (string) run.Attribute(PtOpenXml.HtmlToWmlCssWidth);
  654. if (!cssWidth.EndsWith("pt")) continue;
  655. cssWidth = cssWidth.Substring(0, cssWidth.Length - 2);
  656. decimal cssWidthInDecimal;
  657. if (!decimal.TryParse(cssWidth, out cssWidthInDecimal)) continue;
  658. // calculate the number of non-breaking spaces to add
  659. decimal cssWidthInPixels = cssWidthInDecimal/72*96;
  660. var numberOfNpSpToAdd = (int) ((cssWidthInPixels - pixWidth)/nbSpWidth);
  661. if (numberOfNpSpToAdd > 0)
  662. run.Add(new XElement(W.t, "".PadRight(numberOfNpSpToAdd, '\u00a0')));
  663. }
  664. }
  665. private static void NormalizeMainDocumentPart(WordprocessingDocument wDoc)
  666. {
  667. XDocument mainXDoc = wDoc.MainDocumentPart.GetXDocument();
  668. XElement newRoot = (XElement)NormalizeTransform(mainXDoc.Root);
  669. mainXDoc.Root.ReplaceWith(newRoot);
  670. wDoc.MainDocumentPart.PutXDocument();
  671. }
  672. private static object NormalizeTransform(XNode node)
  673. {
  674. XElement element = node as XElement;
  675. if (element != null)
  676. {
  677. if (element.Name == W.p && element.Elements().Any(c => c.Name == W.p || c.Name == W.tbl))
  678. {
  679. var groupedChildren = element.Elements()
  680. .GroupAdjacent(e => e.Name == W.p || e.Name == W.tbl);
  681. var newContent = groupedChildren
  682. .Select(g =>
  683. {
  684. if (g.Key == false)
  685. {
  686. XElement paragraph = new XElement(W.p,
  687. element.Elements(W.pPr),
  688. g.Where(gc => gc.Name != W.pPr));
  689. return (object)paragraph;
  690. }
  691. return g.Select(n => NormalizeTransform(n));
  692. });
  693. return newContent;
  694. }
  695. return new XElement(element.Name,
  696. element.Attributes(),
  697. element.Nodes().Select(n => NormalizeTransform(n)));
  698. }
  699. return node;
  700. }
  701. private enum NextExpected
  702. {
  703. Paragraph,
  704. Run,
  705. SubRun,
  706. }
  707. private static object Transform(XNode node, HtmlToWmlConverterSettings settings, WordprocessingDocument wDoc, NextExpected nextExpected, bool preserveWhiteSpace)
  708. {
  709. XElement element = node as XElement;
  710. if (element != null)
  711. {
  712. if (element.Name == XhtmlNoNamespace.a)
  713. {
  714. string rId = "R" + Guid.NewGuid().ToString().Replace("-", "");
  715. string href = (string)element.Attribute(NoNamespace.href);
  716. if (href != null)
  717. {
  718. Uri uri = null;
  719. try
  720. {
  721. uri = new Uri(href);
  722. }
  723. catch (UriFormatException)
  724. {
  725. XElement rPr = GetRunProperties(element, settings);
  726. XElement run = new XElement(W.r,
  727. rPr,
  728. new XElement(W.t, element.Value));
  729. return new[] { run };
  730. }
  731. if (uri != null)
  732. {
  733. wDoc.MainDocumentPart.AddHyperlinkRelationship(uri, true, rId);
  734. if (element.Element(XhtmlNoNamespace.img) != null)
  735. {
  736. var imageTransformed = element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace)).OfType<XElement>();
  737. var newImageTransformed = imageTransformed
  738. .Select(i =>
  739. {
  740. if (i.Elements(W.drawing).Any())
  741. {
  742. var newRun = new XElement(i);
  743. var docPr = newRun.Elements(W.drawing).Elements(WP.inline).Elements(WP.docPr).FirstOrDefault();
  744. if (docPr != null)
  745. {
  746. var hlinkClick = new XElement(A.hlinkClick,
  747. new XAttribute(R.id, rId),
  748. new XAttribute(XNamespace.Xmlns + "a", A.a.NamespaceName));
  749. docPr.Add(hlinkClick);
  750. }
  751. return newRun;
  752. }
  753. return i;
  754. })
  755. .ToList();
  756. return newImageTransformed;
  757. }
  758. XElement rPr = GetRunProperties(element, settings);
  759. XElement hyperlink = new XElement(W.hyperlink,
  760. new XAttribute(R.id, rId),
  761. new XElement(W.r,
  762. rPr,
  763. new XElement(W.t, element.Value)));
  764. return new[] { hyperlink };
  765. }
  766. }
  767. return null;
  768. }
  769. if (element.Name == XhtmlNoNamespace.b)
  770. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  771. if (element.Name == XhtmlNoNamespace.body)
  772. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  773. if (element.Name == XhtmlNoNamespace.caption)
  774. {
  775. return new XElement(W.tr,
  776. GetTableRowProperties(element),
  777. new XElement(W.tc,
  778. GetCellPropertiesForCaption(element),
  779. element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Paragraph, preserveWhiteSpace))));
  780. }
  781. if (element.Name == XhtmlNoNamespace.div)
  782. {
  783. if (nextExpected == NextExpected.Paragraph)
  784. {
  785. if (element.Descendants().Any(d => d.Name == XhtmlNoNamespace.h1 ||
  786. d.Name == XhtmlNoNamespace.li ||
  787. d.Name == XhtmlNoNamespace.p ||
  788. d.Name == XhtmlNoNamespace.table))
  789. {
  790. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  791. }
  792. else
  793. {
  794. return GenerateNextExpected(element, settings, wDoc, null, nextExpected, false);
  795. }
  796. }
  797. else
  798. {
  799. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  800. }
  801. }
  802. if (element.Name == XhtmlNoNamespace.em)
  803. return element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Run, preserveWhiteSpace));
  804. HeadingInfo hi = HeadingTagMap.FirstOrDefault(htm => htm.Name == element.Name);
  805. if (hi != null)
  806. {
  807. return GenerateNextExpected(element, settings, wDoc, hi.StyleName, NextExpected.Paragraph, false);
  808. }
  809. if (element.Name == XhtmlNoNamespace.hr)
  810. {
  811. int i = GetNextRectId();
  812. XElement hr = XElement.Parse(
  813. @"<w:p xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'
  814. xmlns:o='urn:schemas-microsoft-com:office:office'
  815. xmlns:w14='http://schemas.microsoft.com/office/word/2010/wordml'
  816. xmlns:v='urn:schemas-microsoft-com:vml'>
  817. <w:r>
  818. <w:pict w14:anchorId='0DBC9ADE'>
  819. <v:rect id='_x0000_i" + i + @"'
  820. style='width:0;height:1.5pt'
  821. o:hralign='center'
  822. o:hrstd='t'
  823. o:hr='t'
  824. fillcolor='#a0a0a0'
  825. stroked='f'/>
  826. </w:pict>
  827. </w:r>
  828. </w:p>");
  829. hr.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
  830. return hr;
  831. }
  832. if (element.Name == XhtmlNoNamespace.html)
  833. return element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Paragraph, preserveWhiteSpace));
  834. if (element.Name == XhtmlNoNamespace.i)
  835. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  836. if (element.Name == XhtmlNoNamespace.blockquote)
  837. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  838. if (element.Name == XhtmlNoNamespace.img)
  839. {
  840. if (element.Parent.Name == XhtmlNoNamespace.body)
  841. {
  842. XElement para = new XElement(W.p,
  843. GetParagraphPropertiesForImage(),
  844. TransformImageToWml(element, settings, wDoc));
  845. return para;
  846. }
  847. else
  848. {
  849. XElement content = TransformImageToWml(element, settings, wDoc);
  850. return content;
  851. }
  852. }
  853. if (element.Name == XhtmlNoNamespace.li)
  854. {
  855. return GenerateNextExpected(element, settings, wDoc, null, NextExpected.Paragraph, false);
  856. }
  857. if (element.Name == XhtmlNoNamespace.ol)
  858. return element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Paragraph, preserveWhiteSpace));
  859. if (element.Name == XhtmlNoNamespace.p)
  860. {
  861. return GenerateNextExpected(element, settings, wDoc, null, NextExpected.Paragraph, false);
  862. }
  863. if (element.Name == XhtmlNoNamespace.s)
  864. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  865. /****************************************** SharePoint Specific ********************************************/
  866. // todo sharepoint specific
  867. //if (element.Name == Xhtml.div && (string)element.Attribute(Xhtml._class) == "ms-rteElement-Callout1")
  868. //{
  869. // return new XElement(W.p,
  870. // // todo need a style for class
  871. // new XElement(W.pPr,
  872. // new XElement(W.pStyle,
  873. // new XAttribute(W.val, "ms-rteElement-Callout1"))),
  874. // new XElement(W.r,
  875. // new XElement(W.t, element.Value)));
  876. //}
  877. if (element.Name == XhtmlNoNamespace.span && (string)element.Attribute(XhtmlNoNamespace.id) == "layoutsData")
  878. return null;
  879. /****************************************** End SharePoint Specific ********************************************/
  880. if (element.Name == XhtmlNoNamespace.span)
  881. {
  882. var spanReplacement = element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  883. var dummyElement = new XElement("dummy", spanReplacement);
  884. var firstChild = dummyElement.Elements().FirstOrDefault();
  885. XElement run = null;
  886. if (firstChild != null && firstChild.Name == W.r)
  887. run = firstChild;
  888. if (run != null)
  889. {
  890. Dictionary<string, CssExpression> computedProperties = element.Annotation<Dictionary<string, CssExpression>>();
  891. if (computedProperties != null && computedProperties.ContainsKey("width"))
  892. {
  893. string width = computedProperties["width"];
  894. if (width != "auto")
  895. run.Add(new XAttribute(PtOpenXml.HtmlToWmlCssWidth, width));
  896. var rFontsLocal = run.Element(W.rFonts);
  897. XElement rFontsGlobal = null;
  898. var styleDefPart = wDoc.MainDocumentPart.StyleDefinitionsPart;
  899. if (styleDefPart != null)
  900. {
  901. rFontsGlobal = styleDefPart.GetXDocument().Root.Elements(W.docDefaults).Elements(W.rPrDefault).Elements(W.rPr).Elements(W.rFonts).FirstOrDefault();
  902. }
  903. var rFontsNew = FontMerge(rFontsLocal, rFontsGlobal);
  904. var rPr = run.Element(W.rPr);
  905. if (rPr != null)
  906. {
  907. var rFontsExisting = rPr.Element(W.rFonts);
  908. if (rFontsExisting == null)
  909. rPr.AddFirst(rFontsGlobal);
  910. else
  911. rFontsExisting.ReplaceWith(rFontsGlobal);
  912. }
  913. }
  914. return dummyElement.Elements();
  915. }
  916. return spanReplacement;
  917. }
  918. if (element.Name == XhtmlNoNamespace.strong)
  919. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  920. if (element.Name == XhtmlNoNamespace.style)
  921. return null;
  922. if (element.Name == XhtmlNoNamespace.sub)
  923. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  924. if (element.Name == XhtmlNoNamespace.sup)
  925. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  926. if (element.Name == XhtmlNoNamespace.table)
  927. {
  928. XElement wmlTable = new XElement(W.tbl,
  929. GetTableProperties(element),
  930. GetTableGrid(element, settings),
  931. element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Paragraph, preserveWhiteSpace)));
  932. return wmlTable;
  933. }
  934. if (element.Name == XhtmlNoNamespace.tbody)
  935. return element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Paragraph, preserveWhiteSpace));
  936. if (element.Name == XhtmlNoNamespace.td)
  937. {
  938. var tdText = element.DescendantNodes().OfType<XText>().Select(t => t.Value).StringConcatenate().Trim();
  939. var hasOtherThanSpansAndParas = element.Descendants().Any(d => d.Name != XhtmlNoNamespace.span && d.Name != XhtmlNoNamespace.p);
  940. if (tdText != "" || hasOtherThanSpansAndParas)
  941. {
  942. var newElementRaw = new XElement("dummy", element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Paragraph, preserveWhiteSpace)));
  943. var newElements = new XElement("dummy",
  944. newElementRaw
  945. .Elements()
  946. .Select(e =>
  947. {
  948. if (e.Name == W.hyperlink || e.Name == W.r)
  949. return new XElement(W.p, e);
  950. return e;
  951. }));
  952. return new XElement(W.tc,
  953. GetCellProperties(element),
  954. newElements.Elements());
  955. }
  956. else
  957. {
  958. XElement p;
  959. p = new XElement(W.p,
  960. GetParagraphProperties(element, null, settings),
  961. new XElement(W.r,
  962. GetRunProperties(element, settings),
  963. new XElement(W.t, "")));
  964. return new XElement(W.tc,
  965. GetCellProperties(element), p);
  966. }
  967. }
  968. if (element.Name == XhtmlNoNamespace.th)
  969. {
  970. return new XElement(W.tc,
  971. GetCellHeaderProperties(element),
  972. element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace)));
  973. }
  974. if (element.Name == XhtmlNoNamespace.tr)
  975. {
  976. return new XElement(W.tr,
  977. GetTableRowProperties(element),
  978. element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace)));
  979. }
  980. if (element.Name == XhtmlNoNamespace.u)
  981. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  982. if (element.Name == XhtmlNoNamespace.ul)
  983. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  984. if (element.Name == XhtmlNoNamespace.br)
  985. if (nextExpected == NextExpected.Paragraph)
  986. {
  987. return new XElement(W.p,
  988. new XElement(W.r,
  989. new XElement(W.t)));
  990. }
  991. else
  992. {
  993. return new XElement(W.r, new XElement(W.br));
  994. }
  995. if (element.Name == XhtmlNoNamespace.tt || element.Name == XhtmlNoNamespace.code || element.Name == XhtmlNoNamespace.kbd || element.Name == XhtmlNoNamespace.samp)
  996. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  997. if (element.Name == XhtmlNoNamespace.pre)
  998. return GenerateNextExpected(element, settings, wDoc, null, NextExpected.Paragraph, true);
  999. // if no match up to this point, then just recursively process descendants
  1000. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  1001. }
  1002. if (node.Parent.Name != XhtmlNoNamespace.title)
  1003. return GenerateNextExpected(node, settings, wDoc, null, nextExpected, preserveWhiteSpace);
  1004. return null;
  1005. }
  1006. private static XElement FontMerge(XElement higherPriorityFont, XElement lowerPriorityFont)
  1007. {
  1008. XElement rFonts;
  1009. if (higherPriorityFont == null)
  1010. return lowerPriorityFont;
  1011. if (lowerPriorityFont == null)
  1012. return higherPriorityFont;
  1013. if (higherPriorityFont == null && lowerPriorityFont == null)
  1014. return null;
  1015. rFonts = new XElement(W.rFonts,
  1016. (higherPriorityFont.Attribute(W.ascii) != null || higherPriorityFont.Attribute(W.asciiTheme) != null) ?
  1017. new[] { higherPriorityFont.Attribute(W.ascii), higherPriorityFont.Attribute(W.asciiTheme) } :
  1018. new[] { lowerPriorityFont.Attribute(W.ascii), lowerPriorityFont.Attribute(W.asciiTheme) },
  1019. (higherPriorityFont.Attribute(W.hAnsi) != null || higherPriorityFont.Attribute(W.hAnsiTheme) != null) ?
  1020. new[] { higherPriorityFont.Attribute(W.hAnsi), higherPriorityFont.Attribute(W.hAnsiTheme) } :
  1021. new[] { lowerPriorityFont.Attribute(W.hAnsi), lowerPriorityFont.Attribute(W.hAnsiTheme) },
  1022. (higherPriorityFont.Attribute(W.eastAsia) != null || higherPriorityFont.Attribute(W.eastAsiaTheme) != null) ?
  1023. new[] { higherPriorityFont.Attribute(W.eastAsia), higherPriorityFont.Attribute(W.eastAsiaTheme) } :
  1024. new[] { lowerPriorityFont.Attribute(W.eastAsia), lowerPriorityFont.Attribute(W.eastAsiaTheme) },
  1025. (higherPriorityFont.Attribute(W.cs) != null || higherPriorityFont.Attribute(W.cstheme) != null) ?
  1026. new[] { higherPriorityFont.Attribute(W.cs), higherPriorityFont.Attribute(W.cstheme) } :
  1027. new[] { lowerPriorityFont.Attribute(W.cs), lowerPriorityFont.Attribute(W.cstheme) },
  1028. (higherPriorityFont.Attribute(W.hint) != null ? higherPriorityFont.Attribute(W.hint) :
  1029. lowerPriorityFont.Attribute(W.hint))
  1030. );
  1031. return rFonts;
  1032. }
  1033. private static int? CalcWidthOfRunInPixels(XElement r)
  1034. {
  1035. var fontName = (string)r.Attribute(PtOpenXml.FontName) ??
  1036. (string)r.Ancestors(W.p).First().Attribute(PtOpenXml.FontName);
  1037. if (fontName == null)
  1038. throw new OpenXmlPowerToolsException("Internal Error, should have FontName attribute");
  1039. if (UnknownFonts.Contains(fontName))
  1040. return 0;
  1041. if (UnknownFonts.Contains(fontName))
  1042. return null;
  1043. var rPr = r.Element(W.rPr);
  1044. if (rPr == null)
  1045. return null;
  1046. var sz = GetFontSize(r) ?? 22m;
  1047. // unknown font families will throw ArgumentException, in which case just return 0
  1048. if (!KnownFamilies.Contains(fontName))
  1049. return 0;
  1050. // in theory, all unknown fonts are found by the above test, but if not...
  1051. FontFamily ff;
  1052. try
  1053. {
  1054. ff = new FontFamily(fontName);
  1055. }
  1056. catch (ArgumentException)
  1057. {
  1058. UnknownFonts.Add(fontName);
  1059. return 0;
  1060. }
  1061. var fs = FontStyle.Regular;
  1062. if (Util.GetBoolProp(rPr, W.b) == true || Util.GetBoolProp(rPr, W.bCs) == true)
  1063. fs |= FontStyle.Bold;
  1064. if (Util.GetBoolProp(rPr, W.i) == true || Util.GetBoolProp(rPr, W.iCs) == true)
  1065. fs |= FontStyle.Italic;
  1066. // Appended blank as a quick fix to accommodate &nbsp; that will get
  1067. // appended to some layout-critical runs such as list item numbers.
  1068. // In some cases, this might not be required or even wrong, so this
  1069. // must be revisited.
  1070. // TODO: Revisit.
  1071. var runText = r.DescendantsTrimmed(W.txbxContent)
  1072. .Where(e => e.Name == W.t)
  1073. .Select(t => (string)t)
  1074. .StringConcatenate() + " ";
  1075. var tabLength = r.DescendantsTrimmed(W.txbxContent)
  1076. .Where(e => e.Name == W.tab)
  1077. .Select(t => (decimal)t.Attribute(PtOpenXml.TabWidth))
  1078. .Sum();
  1079. if (runText.Length == 0 && tabLength == 0)
  1080. return 0;
  1081. int multiplier = 1;
  1082. if (runText.Length <= 2)
  1083. multiplier = 100;
  1084. else if (runText.Length <= 4)
  1085. multiplier = 50;
  1086. else if (runText.Length <= 8)
  1087. multiplier = 25;
  1088. else if (runText.Length <= 16)
  1089. multiplier = 12;
  1090. else if (runText.Length <= 32)
  1091. multiplier = 6;
  1092. if (multiplier != 1)
  1093. {
  1094. StringBuilder sb = new StringBuilder();
  1095. for (int i = 0; i < multiplier; i++)
  1096. sb.Append(runText);
  1097. runText = sb.ToString();
  1098. }
  1099. return MetricsGetter.GetTextWidth(ff, fs, sz, runText) / multiplier;
  1100. }
  1101. // The algorithm for this method comes from the implementer notes in [MS-OI29500].pdf
  1102. // section 2.1.87
  1103. // The implementer notes are at:
  1104. // http://msdn.microsoft.com/en-us/library/ee908652.aspx
  1105. public enum FontType
  1106. {
  1107. Ascii,
  1108. HAnsi,
  1109. EastAsia,
  1110. CS
  1111. };
  1112. public class CharStyleAttributes
  1113. {
  1114. public string AsciiFont;
  1115. public string HAnsiFont;
  1116. public string EastAsiaFont;
  1117. public string CsFont;
  1118. public string Hint;
  1119. public bool Rtl;
  1120. public string LatinLang;
  1121. public string BidiLang;
  1122. public string EastAsiaLang;
  1123. public Dictionary<XName, bool?> ToggleProperties;
  1124. public Dictionary<XName, XElement> Properties;
  1125. public CharStyleAttributes(XElement pPr, XElement rPr)
  1126. {
  1127. ToggleProperties = new Dictionary<XName, bool?>();
  1128. Properties = new Dictionary<XName, XElement>();
  1129. if (rPr == null)
  1130. return;
  1131. foreach (XName xn in TogglePropertyNames)
  1132. {
  1133. ToggleProperties[xn] = Util.GetBoolProp(rPr, xn);
  1134. }
  1135. foreach (XName xn in PropertyNames)
  1136. {
  1137. Properties[xn] = GetXmlProperty(rPr, xn);
  1138. }
  1139. var rFonts = rPr.Element(W.rFonts);
  1140. if (rFonts == null)
  1141. {
  1142. this.AsciiFont = null;
  1143. this.HAnsiFont = null;
  1144. this.EastAsiaFont = null;
  1145. this.CsFont = null;
  1146. this.Hint = null;
  1147. }
  1148. else
  1149. {
  1150. this.AsciiFont = (string)(rFonts.Attribute(W.ascii));
  1151. this.HAnsiFont = (string)(rFonts.Attribute(W.hAnsi));
  1152. this.EastAsiaFont = (string)(rFonts.Attribute(W.eastAsia));
  1153. this.CsFont = (string)(rFonts.Attribute(W.cs));
  1154. this.Hint = (string)(rFonts.Attribute(W.hint));
  1155. }
  1156. XElement csel = this.Properties[W.cs];
  1157. bool cs = csel != null && (csel.Attribute(W.val) == null || csel.Attribute(W.val).ToBoolean() == true);
  1158. XElement rtlel = this.Properties[W.rtl];
  1159. bool rtl = rtlel != null && (rtlel.Attribute(W.val) == null || rtlel.Attribute(W.val).ToBoolean() == true);
  1160. var bidi = false;
  1161. if (pPr != null)
  1162. {
  1163. XElement bidiel = pPr.Element(W.bidi);
  1164. bidi = bidiel != null && (bidiel.Attribute(W.val) == null || bidiel.Attribute(W.val).ToBoolean() == true);
  1165. }
  1166. Rtl = cs || rtl || bidi;
  1167. var lang = rPr.Element(W.lang);
  1168. if (lang != null)
  1169. {
  1170. LatinLang = (string)lang.Attribute(W.val);
  1171. BidiLang = (string)lang.Attribute(W.bidi);
  1172. EastAsiaLang = (string)lang.Attribute(W.eastAsia);
  1173. }
  1174. }
  1175. private static XElement GetXmlProperty(XElement rPr, XName propertyName)
  1176. {
  1177. return rPr.Element(propertyName);
  1178. }
  1179. private static XName[] TogglePropertyNames = new[] {
  1180. W.b,
  1181. W.bCs,
  1182. W.caps,
  1183. W.emboss,
  1184. W.i,
  1185. W.iCs,
  1186. W.imprint,
  1187. W.outline,
  1188. W.shadow,
  1189. W.smallCaps,
  1190. W.strike,
  1191. W.vanish
  1192. };
  1193. private static XName[] PropertyNames = new[] {
  1194. W.cs,
  1195. W.rtl,
  1196. W.u,
  1197. W.color,
  1198. W.highlight,
  1199. W.shd
  1200. };
  1201. }
  1202. public static FontType DetermineFontTypeFromCharacter(char ch, CharStyleAttributes csa)
  1203. {
  1204. // 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"),
  1205. // then the cs (or cstheme if defined) font is used, regardless of the Unicode character values of the run’s content.
  1206. if (csa.Rtl)
  1207. {
  1208. return FontType.CS;
  1209. }
  1210. // A large percentage of characters will fall in the following rule.
  1211. // Unicode Block: Basic Latin
  1212. if (ch >= 0x00 && ch <= 0x7f)
  1213. {
  1214. return FontType.Ascii;
  1215. }
  1216. // If the eastAsia (or eastAsiaTheme if defined) attribute’s value is “Times New Roman” and the ascii (or asciiTheme if defined)
  1217. // and hAnsi (or hAnsiTheme if defined) attributes are equal, then the ascii (or asciiTheme if defined) font is used.
  1218. if (csa.EastAsiaFont == "Times New Roman" &&
  1219. csa.AsciiFont == csa.HAnsiFont)
  1220. {
  1221. return FontType.Ascii;
  1222. }
  1223. // Unicode BLock: Latin-1 Supplement
  1224. if (ch >= 0xA0 && ch <= 0xFF)
  1225. {
  1226. if (csa.Hint == "eastAsia")
  1227. {
  1228. if (ch == 0xA1 ||
  1229. ch == 0xA4 ||
  1230. ch == 0xA7 ||
  1231. ch == 0xA8 ||
  1232. ch == 0xAA ||
  1233. ch == 0xAD ||
  1234. ch == 0xAF ||
  1235. (ch >= 0xB0 && ch <= 0xB4) ||
  1236. (ch >= 0xB6 && ch <= 0xBA) ||
  1237. (ch >= 0xBC && ch <= 0xBF) ||
  1238. ch == 0xD7 ||
  1239. ch == 0xF7)
  1240. {
  1241. return FontType.EastAsia;
  1242. }
  1243. if (csa.EastAsiaLang == "zh-hant" ||
  1244. csa.EastAsiaLang == "zh-hans")
  1245. {
  1246. if (ch == 0xE0 ||
  1247. ch == 0xE1 ||
  1248. (ch >= 0xE8 && ch <= 0xEA) ||
  1249. (ch >= 0xEC && ch <= 0xED) ||
  1250. (ch >= 0xF2 && ch <= 0xF3) ||
  1251. (ch >= 0xF9 && ch <= 0xFA) ||
  1252. ch == 0xFC)
  1253. {
  1254. return FontType.EastAsia;
  1255. }
  1256. }
  1257. }
  1258. return FontType.HAnsi;
  1259. }
  1260. // Unicode Block: Latin Extended-A
  1261. if (ch >= 0x0100 && ch <= 0x017F)
  1262. {
  1263. if (csa.Hint == "eastAsia")
  1264. {
  1265. if (csa.EastAsiaLang == "zh-hant" ||
  1266. csa.EastAsiaLang == "zh-hans"
  1267. /* || the character set of the east Asia (or east Asia theme) font is Chinese5 || GB2312 todo */)
  1268. {
  1269. return FontType.EastAsia;
  1270. }
  1271. }
  1272. return FontType.HAnsi;
  1273. }
  1274. // Unicode Block: Latin Extended-B
  1275. if (ch >= 0x0180 && ch <= 0x024F)
  1276. {
  1277. if (csa.Hint == "eastAsia")
  1278. {
  1279. if (csa.EastAsiaLang == "zh-hant" ||
  1280. csa.EastAsiaLang == "zh-hans"
  1281. /* || the character set of the east Asia (or east Asia theme) font is Chinese5 || GB2312 todo */)
  1282. {
  1283. return FontType.EastAsia;
  1284. }
  1285. }
  1286. return FontType.HAnsi;
  1287. }
  1288. // Unicode Block: IPA Extensions
  1289. if (ch >= 0x0250 && ch <= 0x02AF)
  1290. {
  1291. if (csa.Hint == "eastAsia")
  1292. {
  1293. if (csa.EastAsiaLang == "zh-hant" ||
  1294. csa.EastAsiaLang == "zh-hans"
  1295. /* || the character set of the east Asia (or east Asia theme) font is Chinese5 || GB2312 todo */)
  1296. {
  1297. return FontType.EastAsia;
  1298. }
  1299. }
  1300. return FontType.HAnsi;
  1301. }
  1302. // Unicode Block: Spacing Modifier Letters
  1303. if (ch >= 0x02B0 && ch <= 0x02FF)
  1304. {
  1305. if (csa.Hint == "eastAsia")
  1306. {
  1307. return FontType.EastAsia;
  1308. }
  1309. return FontType.HAnsi;
  1310. }
  1311. // Unicode Block: Combining Diacritic Marks
  1312. if (ch >= 0x0300 && ch <= 0x036F)
  1313. {
  1314. if (csa.Hint == "eastAsia")
  1315. {
  1316. return FontType.EastAsia;
  1317. }
  1318. return FontType.HAnsi;
  1319. }
  1320. // Unicode Block: Greek
  1321. if (ch >= 0x0370 && ch <= 0x03CF)
  1322. {
  1323. if (csa.Hint == "eastAsia")
  1324. {
  1325. return FontType.EastAsia;
  1326. }
  1327. return FontType.HAnsi;
  1328. }
  1329. // Unicode Block: Cyrillic
  1330. if (ch >= 0x0400 && ch <= 0x04FF)
  1331. {
  1332. if (csa.Hint == "eastAsia")
  1333. {
  1334. return FontType.EastAsia;
  1335. }
  1336. return FontType.HAnsi;
  1337. }
  1338. // Unicode Block: Hebrew
  1339. if (ch >= 0x0590 && ch <= 0x05FF)
  1340. {
  1341. return FontType.Ascii;
  1342. }
  1343. // Unicode Block: Arabic
  1344. if (ch >= 0x0600 && ch <= 0x06FF)
  1345. {
  1346. return FontType.Ascii;
  1347. }
  1348. // Unicode Block: Syriac
  1349. if (ch >= 0x0700 && ch <= 0x074F)
  1350. {
  1351. return FontType.Ascii;
  1352. }
  1353. // Unicode Block: Arabic Supplement
  1354. if (ch >= 0x0750 && ch <= 0x077F)
  1355. {
  1356. return FontType.Ascii;
  1357. }
  1358. // Unicode Block: Thanna
  1359. if (ch >= 0x0780 && ch <= 0x07BF)
  1360. {
  1361. return FontType.Ascii;
  1362. }
  1363. // Unicode Block: Hangul Jamo
  1364. if (ch >= 0x1100 && ch <= 0x11FF)
  1365. {
  1366. return FontType.EastAsia;
  1367. }
  1368. // Unicode Block: Latin Extended Additional
  1369. if (ch >= 0x1E00 && ch <= 0x1EFF)
  1370. {
  1371. if (csa.Hint == "eastAsia" &&
  1372. (csa.EastAsiaLang == "zh-hant" ||
  1373. csa.EastAsiaLang == "zh-hans"))
  1374. {
  1375. return FontType.EastAsia;
  1376. }
  1377. return FontType.HAnsi;
  1378. }
  1379. // Unicode Block: General Punctuation
  1380. if (ch >= 0x2000 && ch <= 0x206F)
  1381. {
  1382. if (csa.Hint == "eastAsia")
  1383. {
  1384. return FontType.EastAsia;
  1385. }
  1386. return FontType.HAnsi;
  1387. }
  1388. // Unicode Block: Superscripts and Subscripts
  1389. if (ch >= 0x2070 && ch <= 0x209F)
  1390. {
  1391. if (csa.Hint == "eastAsia")
  1392. {
  1393. return FontType.EastAsia;
  1394. }
  1395. return FontType.HAnsi;
  1396. }
  1397. // Unicode Block: Currency Symbols
  1398. if (ch >= 0x20A0 && ch <= 0x20CF)
  1399. {
  1400. if (csa.Hint == "eastAsia")
  1401. {
  1402. return FontType.EastAsia;
  1403. }
  1404. return FontType.HAnsi;
  1405. }
  1406. // Unicode Block: Combining Diacritical Marks for Symbols
  1407. if (ch >= 0x20D0 && ch <= 0x20FF)
  1408. {
  1409. if (csa.Hint == "eastAsia")
  1410. {
  1411. return FontType.EastAsia;
  1412. }
  1413. return FontType.HAnsi;
  1414. }
  1415. // Unicode Block: Letter-like Symbols
  1416. if (ch >= 0x2100 && ch <= 0x214F)
  1417. {
  1418. if (csa.Hint == "eastAsia")
  1419. {
  1420. return FontType.EastAsia;
  1421. }
  1422. return FontType.HAnsi;
  1423. }
  1424. // Unicode Block: Number Forms
  1425. if (ch >= 0x2150 && ch <= 0x218F)
  1426. {
  1427. if (csa.Hint == "eastAsia")
  1428. {
  1429. return FontType.EastAsia;
  1430. }
  1431. return FontType.HAnsi;
  1432. }
  1433. // Unicode Block: Arrows
  1434. if (ch >= 0x2190 && ch <= 0x21FF)
  1435. {
  1436. if (csa.Hint == "eastAsia")
  1437. {
  1438. return FontType.EastAsia;
  1439. }
  1440. return FontType.HAnsi;
  1441. }
  1442. // Unicode Block: Mathematical Operators
  1443. if (ch >= 0x2200 && ch <= 0x22FF)
  1444. {
  1445. if (csa.Hint == "eastAsia")
  1446. {
  1447. return FontType.EastAsia;
  1448. }
  1449. return FontType.HAnsi;
  1450. }
  1451. // Unicode Block: Miscellaneous Technical
  1452. if (ch >= 0x2300 && ch <= 0x23FF)
  1453. {
  1454. if (csa.Hint == "eastAsia")
  1455. {
  1456. return FontType.EastAsia;
  1457. }
  1458. return FontType.HAnsi;
  1459. }
  1460. // Unicode Block: Control Pictures
  1461. if (ch >= 0x2400 && ch <= 0x243F)
  1462. {
  1463. if (csa.Hint == "eastAsia")
  1464. {
  1465. return FontType.EastAsia;
  1466. }
  1467. return FontType.HAnsi;
  1468. }
  1469. // Unicode Block: Optical Character Recognition
  1470. if (ch >= 0x2440 && ch <= 0x245F)
  1471. {
  1472. if (csa.Hint == "eastAsia")
  1473. {
  1474. return FontType.EastAsia;
  1475. }
  1476. return FontType.HAnsi;
  1477. }
  1478. // Unicode Block: Enclosed Alphanumerics
  1479. if (ch >= 0x2460 && ch <= 0x24FF)
  1480. {
  1481. if (csa.Hint == "eastAsia")
  1482. {
  1483. return FontType.EastAsia;
  1484. }
  1485. return FontType.HAnsi;
  1486. }
  1487. // Unicode Block: Box Drawing
  1488. if (ch >= 0x2500 && ch <= 0x257F)
  1489. {
  1490. if (csa.Hint == "eastAsia")
  1491. {
  1492. return FontType.EastAsia;
  1493. }
  1494. return FontType.HAnsi;
  1495. }
  1496. // Unicode Block: Block Elements
  1497. if (ch >= 0x2580 && ch <= 0x259F)
  1498. {
  1499. if (csa.Hint == "eastAsia")
  1500. {
  1501. return FontType.EastAsia;
  1502. }
  1503. return FontType.HAnsi;
  1504. }
  1505. // Unicode Block: Geometric Shapes
  1506. if (ch >= 0x25A0 && ch <= 0x25FF)
  1507. {
  1508. if (csa.Hint == "eastAsia")
  1509. {
  1510. return FontType.EastAsia;
  1511. }
  1512. return FontType.HAnsi;
  1513. }
  1514. // Unicode Block: Miscellaneous Symbols
  1515. if (ch >= 0x2600 && ch <= 0x26FF)
  1516. {
  1517. if (csa.Hint == "eastAsia")
  1518. {
  1519. return FontType.EastAsia;
  1520. }
  1521. return FontType.HAnsi;
  1522. }
  1523. // Unicode Block: Dingbats
  1524. if (ch >= 0x2700 && ch <= 0x27BF)
  1525. {
  1526. if (csa.Hint == "eastAsia")
  1527. {
  1528. return FontType.EastAsia;
  1529. }
  1530. return FontType.HAnsi;
  1531. }
  1532. // Unicode Block: CJK Radicals Supplement
  1533. if (ch >= 0x2E80 && ch <= 0x2EFF)
  1534. {
  1535. if (csa.Hint == "eastAsia")
  1536. {
  1537. return FontType.EastAsia;
  1538. }
  1539. return FontType.HAnsi;
  1540. }
  1541. // Unicode Block: Kangxi Radicals
  1542. if (ch >= 0x2F00 && ch <= 0x2FDF)
  1543. {
  1544. return FontType.EastAsia;
  1545. }
  1546. // Unicode Block: Ideographic Description Characters
  1547. if (ch >= 0x2FF0 && ch <= 0x2FFF)
  1548. {
  1549. return FontType.EastAsia;
  1550. }
  1551. // Unicode Block: CJK Symbols and Punctuation
  1552. if (ch >= 0x3000 && ch <= 0x303F)
  1553. {
  1554. return FontType.EastAsia;
  1555. }
  1556. // Unicode Block: Hiragana
  1557. if (ch >= 0x3040 && ch <= 0x309F)
  1558. {
  1559. return FontType.EastAsia;
  1560. }
  1561. // Unicode Block: Katakana
  1562. if (ch >= 0x30A0 && ch <= 0x30FF)
  1563. {
  1564. return FontType.EastAsia;
  1565. }
  1566. // Unicode Block: Bopomofo
  1567. if (ch >= 0x3100 && ch <= 0x312F)
  1568. {
  1569. return FontType.EastAsia;
  1570. }
  1571. // Unicode Block: Hangul Compatibility Jamo
  1572. if (ch >= 0x3130 && ch <= 0x318F)
  1573. {
  1574. return FontType.EastAsia;
  1575. }
  1576. // Unicode Block: Kanbun
  1577. if (ch >= 0x3190 && ch <= 0x319F)
  1578. {
  1579. return FontType.EastAsia;
  1580. }
  1581. // Unicode Block: Enclosed CJK Letters and Months
  1582. if (ch >= 0x3200 && ch <= 0x32FF)
  1583. {
  1584. return FontType.EastAsia;
  1585. }
  1586. // Unicode Block: CJK Compatibility
  1587. if (ch >= 0x3300 && ch <= 0x33FF)
  1588. {
  1589. return FontType.EastAsia;
  1590. }
  1591. // Unicode Block: CJK Unified Ideographs Extension A
  1592. if (ch >= 0x3400 && ch <= 0x4DBF)
  1593. {
  1594. return FontType.EastAsia;
  1595. }
  1596. // Unicode Block: CJK Unified Ideographs
  1597. if (ch >= 0x4E00 && ch <= 0x9FAF)
  1598. {
  1599. return FontType.EastAsia;
  1600. }
  1601. // Unicode Block: Yi Syllables
  1602. if (ch >= 0xA000 && ch <= 0xA48F)
  1603. {
  1604. return FontType.EastAsia;
  1605. }
  1606. // Unicode Block: Yi Radicals
  1607. if (ch >= 0xA490 && ch <= 0xA4CF)
  1608. {
  1609. return FontType.EastAsia;
  1610. }
  1611. // Unicode Block: Hangul Syllables
  1612. if (ch >= 0xAC00 && ch <= 0xD7AF)
  1613. {
  1614. return FontType.EastAsia;
  1615. }
  1616. // Unicode Block: High Surrogates
  1617. if (ch >= 0xD800 && ch <= 0xDB7F)
  1618. {
  1619. return FontType.EastAsia;
  1620. }
  1621. // Unicode Block: High Private Use Surrogates
  1622. if (ch >= 0xDB80 && ch <= 0xDBFF)
  1623. {
  1624. return FontType.EastAsia;
  1625. }
  1626. // Unicode Block: Low Surrogates
  1627. if (ch >= 0xDC00 && ch <= 0xDFFF)
  1628. {
  1629. return FontType.EastAsia;
  1630. }
  1631. // Unicode Block: Private Use Area
  1632. if (ch >= 0xE000 && ch <= 0xF8FF)
  1633. {
  1634. if (csa.Hint == "eastAsia")
  1635. {
  1636. return FontType.EastAsia;
  1637. }
  1638. return FontType.HAnsi;
  1639. }
  1640. // Unicode Block: CJK Compatibility Ideographs
  1641. if (ch >= 0xF900 && ch <= 0xFAFF)
  1642. {
  1643. return FontType.EastAsia;
  1644. }
  1645. // Unicode Block: Alphabetic Presentation Forms
  1646. if (ch >= 0xFB00 && ch <= 0xFB4F)
  1647. {
  1648. if (csa.Hint == "eastAsia")
  1649. {
  1650. if (ch >= 0xFB00 && ch <= 0xFB1C)
  1651. return FontType.EastAsia;
  1652. if (ch >= 0xFB1D && ch <= 0xFB4F)
  1653. return FontType.Ascii;
  1654. }
  1655. return FontType.HAnsi;
  1656. }
  1657. // Unicode Block: Arabic Presentation Forms-A
  1658. if (ch >= 0xFB50 && ch <= 0xFDFF)
  1659. {
  1660. return FontType.Ascii;
  1661. }
  1662. // Unicode Block: CJK Compatibility Forms
  1663. if (ch >= 0xFE30 && ch <= 0xFE4F)
  1664. {
  1665. return FontType.EastAsia;
  1666. }
  1667. // Unicode Block: Small Form Variants
  1668. if (ch >= 0xFE50 && ch <= 0xFE6F)
  1669. {
  1670. return FontType.EastAsia;
  1671. }
  1672. // Unicode Block: Arabic Presentation Forms-B
  1673. if (ch >= 0xFE70 && ch <= 0xFEFE)
  1674. {
  1675. return FontType.Ascii;
  1676. }
  1677. // Unicode Block: Halfwidth and Fullwidth Forms
  1678. if (ch >= 0xFF00 && ch <= 0xFFEF)
  1679. {
  1680. return FontType.EastAsia;
  1681. }
  1682. return FontType.HAnsi;
  1683. }
  1684. private static readonly HashSet<string> UnknownFonts = new HashSet<string>();
  1685. private static HashSet<string> _knownFamilies;
  1686. private static HashSet<string> KnownFamilies
  1687. {
  1688. get
  1689. {
  1690. if (_knownFamilies == null)
  1691. {
  1692. _knownFamilies = new HashSet<string>();
  1693. var families = FontFamily.Families;
  1694. foreach (var fam in families)
  1695. _knownFamilies.Add(fam.Name);
  1696. }
  1697. return _knownFamilies;
  1698. }
  1699. }
  1700. private static HashSet<char> WeakAndNeutralDirectionalCharacters = new HashSet<char>() {
  1701. '0',
  1702. '1',
  1703. '2',
  1704. '3',
  1705. '4',
  1706. '5',
  1707. '6',
  1708. '7',
  1709. '8',
  1710. '9',
  1711. '+',
  1712. '-',
  1713. ':',
  1714. ',',
  1715. '.',
  1716. '|',
  1717. '\t',
  1718. '\r',
  1719. '\n',
  1720. ' ',
  1721. '\x00A0', // non breaking space
  1722. '\x00B0', // degree sign
  1723. '\x066B', // arabic decimal separator
  1724. '\x066C', // arabic thousands separator
  1725. '\x0627', // arabic pipe
  1726. '\x20A0', // start currency symbols
  1727. '\x20A1',
  1728. '\x20A2',
  1729. '\x20A3',
  1730. '\x20A4',
  1731. '\x20A5',
  1732. '\x20A6',
  1733. '\x20A7',
  1734. '\x20A8',
  1735. '\x20A9',
  1736. '\x20AA',
  1737. '\x20AB',
  1738. '\x20AC',
  1739. '\x20AD',
  1740. '\x20AE',
  1741. '\x20AF',
  1742. '\x20B0',
  1743. '\x20B1',
  1744. '\x20B2',
  1745. '\x20B3',
  1746. '\x20B4',
  1747. '\x20B5',
  1748. '\x20B6',
  1749. '\x20B7',
  1750. '\x20B8',
  1751. '\x20B9',
  1752. '\x20BA',
  1753. '\x20BB',
  1754. '\x20BC',
  1755. '\x20BD',
  1756. '\x20BE',
  1757. '\x20BF',
  1758. '\x20C0',
  1759. '\x20C1',
  1760. '\x20C2',
  1761. '\x20C3',
  1762. '\x20C4',
  1763. '\x20C5',
  1764. '\x20C6',
  1765. '\x20C7',
  1766. '\x20C8',
  1767. '\x20C9',
  1768. '\x20CA',
  1769. '\x20CB',
  1770. '\x20CC',
  1771. '\x20CD',
  1772. '\x20CE',
  1773. '\x20CF', // end currency symbols
  1774. '\x0660', // "Arabic" Indic Numeral Forms Iraq and West
  1775. '\x0661',
  1776. '\x0662',
  1777. '\x0663',
  1778. '\x0664',
  1779. '\x0665',
  1780. '\x0666',
  1781. '\x0667',
  1782. '\x0668',
  1783. '\x0669',
  1784. '\x06F0', // "Arabic" Indic Numberal Forms Iran and East
  1785. '\x06F1',
  1786. '\x06F2',
  1787. '\x06F3',
  1788. '\x06F4',
  1789. '\x06F5',
  1790. '\x06F6',
  1791. '\x06F7',
  1792. '\x06F8',
  1793. '\x06F9',
  1794. };
  1795. private static void AdjustFontAttributes(WordprocessingDocument wDoc, XElement paraOrRun, XElement pPr, XElement rPr)
  1796. {
  1797. XDocument themeXDoc = null;
  1798. if (wDoc.MainDocumentPart.ThemePart != null)
  1799. themeXDoc = wDoc.MainDocumentPart.ThemePart.GetXDocument();
  1800. XElement fontScheme = null;
  1801. XElement majorFont = null;
  1802. XElement minorFont = null;
  1803. if (themeXDoc != null)
  1804. {
  1805. fontScheme = themeXDoc.Root.Element(A.themeElements).Element(A.fontScheme);
  1806. majorFont = fontScheme.Element(A.majorFont);
  1807. minorFont = fontScheme.Element(A.minorFont);
  1808. }
  1809. var rFonts = rPr.Element(W.rFonts);
  1810. if (rFonts == null)
  1811. {
  1812. return;
  1813. }
  1814. var asciiTheme = (string)rFonts.Attribute(W.asciiTheme);
  1815. var hAnsiTheme = (string)rFonts.Attribute(W.hAnsiTheme);
  1816. var eastAsiaTheme = (string)rFonts.Attribute(W.eastAsiaTheme);
  1817. var cstheme = (string)rFonts.Attribute(W.cstheme);
  1818. string ascii = null;
  1819. string hAnsi = null;
  1820. string eastAsia = null;
  1821. string cs = null;
  1822. XElement minorLatin = null;
  1823. string minorLatinTypeface = null;
  1824. XElement majorLatin = null;
  1825. string majorLatinTypeface = null;
  1826. if (minorFont != null)
  1827. {
  1828. minorLatin = minorFont.Element(A.latin);
  1829. minorLatinTypeface = (string)minorLatin.Attribute("typeface");
  1830. }
  1831. if (majorFont != null)
  1832. {
  1833. majorLatin = majorFont.Element(A.latin);
  1834. majorLatinTypeface = (string)majorLatin.Attribute("typeface");
  1835. }
  1836. if (asciiTheme != null)
  1837. {
  1838. if (asciiTheme.StartsWith("minor") && minorLatinTypeface != null)
  1839. {
  1840. ascii = minorLatinTypeface;
  1841. }
  1842. else if (asciiTheme.StartsWith("major") && majorLatinTypeface != null)
  1843. {
  1844. ascii = majorLatinTypeface;
  1845. }
  1846. }
  1847. if (hAnsiTheme != null)
  1848. {
  1849. if (hAnsiTheme.StartsWith("minor") && minorLatinTypeface != null)
  1850. {
  1851. hAnsi = minorLatinTypeface;
  1852. }
  1853. else if (hAnsiTheme.StartsWith("major") && majorLatinTypeface != null)
  1854. {
  1855. hAnsi = majorLatinTypeface;
  1856. }
  1857. }
  1858. if (eastAsiaTheme != null)
  1859. {
  1860. if (eastAsiaTheme.StartsWith("minor") && minorLatinTypeface != null)
  1861. {
  1862. eastAsia = minorLatinTypeface;
  1863. }
  1864. else if (eastAsiaTheme.StartsWith("major") && majorLatinTypeface != null)
  1865. {
  1866. eastAsia = majorLatinTypeface;
  1867. }
  1868. }
  1869. if (cstheme != null)
  1870. {
  1871. if (cstheme.StartsWith("minor") && minorFont != null)
  1872. {
  1873. cs = (string)minorFont.Element(A.cs).Attribute("typeface");
  1874. }
  1875. else if (cstheme.StartsWith("major") && majorFont != null)
  1876. {
  1877. cs = (string)majorFont.Element(A.cs).Attribute("typeface");
  1878. }
  1879. }
  1880. if (ascii != null)
  1881. {
  1882. rFonts.SetAttributeValue(W.ascii, ascii);
  1883. }
  1884. if (hAnsi != null)
  1885. {
  1886. rFonts.SetAttributeValue(W.hAnsi, hAnsi);
  1887. }
  1888. if (eastAsia != null)
  1889. {
  1890. rFonts.SetAttributeValue(W.eastAsia, eastAsia);
  1891. }
  1892. if (cs != null)
  1893. {
  1894. rFonts.SetAttributeValue(W.cs, cs);
  1895. }
  1896. var firstTextNode = paraOrRun.Descendants(W.t).FirstOrDefault(t => t.Value.Length > 0);
  1897. string str = " ";
  1898. // if there is a run with no text in it, then no need to do any of the rest of this method.
  1899. if (firstTextNode == null && paraOrRun.Name == W.r)
  1900. return;
  1901. if (firstTextNode != null)
  1902. str = firstTextNode.Value;
  1903. var csa = new CharStyleAttributes(pPr, rPr);
  1904. // This module determines the font based on just the first character.
  1905. // Technically, a run can contain characters from different Unicode code blocks, and hence should be rendered with different fonts.
  1906. // However, Word breaks up runs that use more than one font into multiple runs. Other producers of WordprocessingML may not, so in
  1907. // that case, this routine may need to be augmented to look at all characters in a run.
  1908. /*
  1909. old code
  1910. var fontFamilies = str.select(function (c) {
  1911. var ft = Pav.DetermineFontTypeFromCharacter(c, csa);
  1912. switch (ft) {
  1913. case Pav.FontType.Ascii:
  1914. return cast(rFonts.attribute(W.ascii));
  1915. case Pav.FontType.HAnsi:
  1916. return cast(rFonts.attribute(W.hAnsi));
  1917. case Pav.FontType.EastAsia:
  1918. return cast(rFonts.attribute(W.eastAsia));
  1919. case Pav.FontType.CS:
  1920. return cast(rFonts.attribute(W.cs));
  1921. default:
  1922. return null;
  1923. }
  1924. })
  1925. .where(function (f) { return f != null && f != ""; })
  1926. .distinct()
  1927. .select(function (f) { return new Pav.FontFamily(f); })
  1928. .toArray();
  1929. */
  1930. var charToExamine = str.FirstOrDefault(c => !WeakAndNeutralDirectionalCharacters.Contains(c));
  1931. if (charToExamine == '\0')
  1932. charToExamine = str[0];
  1933. var ft = DetermineFontTypeFromCharacter(charToExamine, csa);
  1934. string fontType = null;
  1935. string languageType = null;
  1936. switch (ft)
  1937. {
  1938. case FontType.Ascii:
  1939. fontType = (string)rFonts.Attribute(W.ascii);
  1940. languageType = "western";
  1941. break;
  1942. case FontType.HAnsi:
  1943. fontType = (string)rFonts.Attribute(W.hAnsi);
  1944. languageType = "western";
  1945. break;
  1946. case FontType.EastAsia:
  1947. fontType = (string)rFonts.Attribute(W.eastAsia);
  1948. languageType = "eastAsia";
  1949. break;
  1950. case FontType.CS:
  1951. fontType = (string)rFonts.Attribute(W.cs);
  1952. languageType = "bidi";
  1953. break;
  1954. }
  1955. if (fontType != null)
  1956. {
  1957. if (paraOrRun.Attribute(PtOpenXml.FontName) == null)
  1958. {
  1959. XAttribute fta = new XAttribute(PtOpenXml.FontName, fontType.ToString());
  1960. paraOrRun.Add(fta);
  1961. }
  1962. else
  1963. {
  1964. paraOrRun.Attribute(PtOpenXml.FontName).Value = fontType.ToString();
  1965. }
  1966. }
  1967. if (languageType != null)
  1968. {
  1969. if (paraOrRun.Attribute(PtOpenXml.LanguageType) == null)
  1970. {
  1971. XAttribute lta = new XAttribute(PtOpenXml.LanguageType, languageType);
  1972. paraOrRun.Add(lta);
  1973. }
  1974. else
  1975. {
  1976. paraOrRun.Attribute(PtOpenXml.LanguageType).Value = languageType;
  1977. }
  1978. }
  1979. }
  1980. private static decimal? GetFontSize(XElement e)
  1981. {
  1982. var languageType = (string)e.Attribute(PtOpenXml.LanguageType);
  1983. if (e.Name == W.p)
  1984. {
  1985. return GetFontSize(languageType, e.Elements(W.pPr).Elements(W.rPr).FirstOrDefault());
  1986. }
  1987. if (e.Name == W.r)
  1988. {
  1989. return GetFontSize(languageType, e.Element(W.rPr));
  1990. }
  1991. return null;
  1992. }
  1993. private static decimal? GetFontSize(string languageType, XElement rPr)
  1994. {
  1995. if (rPr == null) return null;
  1996. return languageType == "bidi"
  1997. ? (decimal?)rPr.Elements(W.szCs).Attributes(W.val).FirstOrDefault()
  1998. : (decimal?)rPr.Elements(W.sz).Attributes(W.val).FirstOrDefault();
  1999. }
  2000. private static int NextRectId = 1025;
  2001. private static int GetNextRectId()
  2002. {
  2003. return NextRectId++;
  2004. }
  2005. private static object GenerateNextExpected(XNode node, HtmlToWmlConverterSettings settings, WordprocessingDocument wDoc,
  2006. string styleName, NextExpected nextExpected, bool preserveWhiteSpace)
  2007. {
  2008. if (nextExpected == NextExpected.Paragraph)
  2009. {
  2010. XElement element = node as XElement;
  2011. if (element != null)
  2012. {
  2013. return new XElement(W.p,
  2014. GetParagraphProperties(element, styleName, settings),
  2015. element.Nodes().Select(n => Transform(n, settings, wDoc, NextExpected.Run, preserveWhiteSpace)));
  2016. }
  2017. else
  2018. {
  2019. XText xTextNode = node as XText;
  2020. if (xTextNode != null)
  2021. {
  2022. string textNodeString = GetDisplayText(xTextNode, preserveWhiteSpace);
  2023. XElement p;
  2024. p = new XElement(W.p,
  2025. GetParagraphProperties(node.Parent, null, settings),
  2026. new XElement(W.r,
  2027. GetRunProperties((XText)node, settings),
  2028. new XElement(W.t,
  2029. GetXmlSpaceAttribute(textNodeString),
  2030. textNodeString)));
  2031. return p;
  2032. }
  2033. return null;
  2034. }
  2035. }
  2036. else
  2037. {
  2038. XElement element = node as XElement;
  2039. if (element != null)
  2040. {
  2041. return element.Nodes().Select(n => Transform(n, settings, wDoc, nextExpected, preserveWhiteSpace));
  2042. }
  2043. else
  2044. {
  2045. string textNodeString = GetDisplayText((XText)node, preserveWhiteSpace);
  2046. XElement rPr = GetRunProperties((XText)node, settings);
  2047. XElement r = new XElement(W.r,
  2048. rPr,
  2049. new XElement(W.t,
  2050. GetXmlSpaceAttribute(textNodeString),
  2051. textNodeString));
  2052. return r;
  2053. }
  2054. }
  2055. }
  2056. private static XElement TransformImageToWml(XElement element, HtmlToWmlConverterSettings settings, WordprocessingDocument wDoc)
  2057. {
  2058. string srcAttribute = (string)element.Attribute(XhtmlNoNamespace.src);
  2059. byte[] ba = null;
  2060. Bitmap bmp = null;
  2061. if (srcAttribute.StartsWith("data:"))
  2062. {
  2063. var semiIndex = srcAttribute.IndexOf(';');
  2064. var commaIndex = srcAttribute.IndexOf(',', semiIndex);
  2065. var base64 = srcAttribute.Substring(commaIndex + 1);
  2066. ba = Convert.FromBase64String(base64);
  2067. using (MemoryStream ms = new MemoryStream(ba))
  2068. {
  2069. bmp = new Bitmap(ms);
  2070. }
  2071. }
  2072. else
  2073. {
  2074. try
  2075. {
  2076. bmp = new Bitmap(settings.BaseUriForImages + "/" + srcAttribute);
  2077. }
  2078. catch (ArgumentException)
  2079. {
  2080. return null;
  2081. }
  2082. catch (NotSupportedException)
  2083. {
  2084. return null;
  2085. }
  2086. MemoryStream ms = new MemoryStream();
  2087. bmp.Save(ms, bmp.RawFormat);
  2088. ba = ms.ToArray();
  2089. }
  2090. MainDocumentPart mdp = wDoc.MainDocumentPart;
  2091. string rId = "R" + Guid.NewGuid().ToString().Replace("-", "");
  2092. ImagePartType ipt = ImagePartType.Png;
  2093. ImagePart newPart = mdp.AddImagePart(ipt, rId);
  2094. using (Stream s = newPart.GetStream(FileMode.Create, FileAccess.ReadWrite))
  2095. s.Write(ba, 0, ba.GetUpperBound(0) + 1);
  2096. PictureId pid = wDoc.Annotation<PictureId>();
  2097. if (pid == null)
  2098. {
  2099. pid = new PictureId
  2100. {
  2101. Id = 1,
  2102. };
  2103. wDoc.AddAnnotation(pid);
  2104. }
  2105. int pictureId = pid.Id;
  2106. ++pid.Id;
  2107. string pictureDescription = "Picture " + pictureId.ToString();
  2108. string floatValue = element.GetProp("float").ToString();
  2109. if (floatValue == "none")
  2110. {
  2111. XElement run = new XElement(W.r,
  2112. GetRunPropertiesForImage(),
  2113. new XElement(W.drawing,
  2114. GetImageAsInline(element, settings, wDoc, bmp, rId, pictureId, pictureDescription)));
  2115. return run;
  2116. }
  2117. if (floatValue == "left" || floatValue == "right")
  2118. {
  2119. XElement run = new XElement(W.r,
  2120. GetRunPropertiesForImage(),
  2121. new XElement(W.drawing,
  2122. GetImageAsAnchor(element, settings, wDoc, bmp, rId, floatValue, pictureId, pictureDescription)));
  2123. return run;
  2124. }
  2125. return null;
  2126. }
  2127. private static XElement GetImageAsInline(XElement element, HtmlToWmlConverterSettings settings, WordprocessingDocument wDoc, Bitmap bmp,
  2128. string rId, int pictureId, string pictureDescription)
  2129. {
  2130. XElement inline = new XElement(WP.inline, // 20.4.2.8
  2131. new XAttribute(XNamespace.Xmlns + "wp", WP.wp.NamespaceName),
  2132. new XAttribute(NoNamespace.distT, 0), // distance from top of image to text, in EMUs, no effect if the parent is inline
  2133. new XAttribute(NoNamespace.distB, 0), // bottom
  2134. new XAttribute(NoNamespace.distL, 0), // left
  2135. new XAttribute(NoNamespace.distR, 0), // right
  2136. GetImageExtent(element, bmp),
  2137. GetEffectExtent(),
  2138. GetDocPr(element, pictureId, pictureDescription),
  2139. GetCNvGraphicFramePr(),
  2140. GetGraphicForImage(element, rId, bmp, pictureId, pictureDescription));
  2141. return inline;
  2142. }
  2143. private static XElement GetImageAsAnchor(XElement element, HtmlToWmlConverterSettings settings, WordprocessingDocument wDoc, Bitmap bmp,
  2144. string rId, string floatValue, int pictureId, string pictureDescription)
  2145. {
  2146. Emu minDistFromEdge = (long)(0.125 * Emu.s_EmusPerInch);
  2147. long relHeight = 251658240; // z-order
  2148. CssExpression marginTopProp = element.GetProp("margin-top");
  2149. CssExpression marginLeftProp = element.GetProp("margin-left");
  2150. CssExpression marginBottomProp = element.GetProp("margin-bottom");
  2151. CssExpression marginRightProp = element.GetProp("margin-right");
  2152. Emu marginTopInEmus = 0;
  2153. Emu marginBottomInEmus = 0;
  2154. Emu marginLeftInEmus = 0;
  2155. Emu marginRightInEmus = 0;
  2156. if (marginTopProp.IsNotAuto)
  2157. marginTopInEmus = (Emu)marginTopProp;
  2158. if (marginBottomProp.IsNotAuto)
  2159. marginBottomInEmus = (Emu)marginBottomProp;
  2160. if (marginLeftProp.IsNotAuto)
  2161. marginLeftInEmus = (Emu)marginLeftProp;
  2162. if (marginRightProp.IsNotAuto)
  2163. marginRightInEmus = (Emu)marginRightProp;
  2164. Emu relativeFromColumn = 0;
  2165. if (floatValue == "left")
  2166. {
  2167. relativeFromColumn = marginLeftInEmus;
  2168. CssExpression parentMarginLeft = element.Parent.GetProp("margin-left");
  2169. if (parentMarginLeft.IsNotAuto)
  2170. relativeFromColumn += (long)(Emu)parentMarginLeft;
  2171. marginRightInEmus = Math.Max(marginRightInEmus, minDistFromEdge);
  2172. }
  2173. else if (floatValue == "right")
  2174. {
  2175. Emu printWidth = (long)settings.PageWidthEmus - (long)settings.PageMarginLeftEmus - (long)settings.PageMarginRightEmus;
  2176. SizeEmu sl = GetImageSizeInEmus(element, bmp);
  2177. relativeFromColumn = printWidth - sl.m_Width;
  2178. if (marginRightProp.IsNotAuto)
  2179. relativeFromColumn -= (long)(Emu)marginRightInEmus;
  2180. CssExpression parentMarginRight = element.Parent.GetProp("margin-right");
  2181. if (parentMarginRight.IsNotAuto)
  2182. relativeFromColumn -= (long)(Emu)parentMarginRight;
  2183. marginLeftInEmus = Math.Max(marginLeftInEmus, minDistFromEdge);
  2184. }
  2185. Emu relativeFromParagraph = marginTopInEmus;
  2186. CssExpression parentMarginTop = element.Parent.GetProp("margin-top");
  2187. if (parentMarginTop.IsNotAuto)
  2188. relativeFromParagraph += (long)(Emu)parentMarginTop;
  2189. XElement anchor = new XElement(WP.anchor,
  2190. new XAttribute(XNamespace.Xmlns + "wp", WP.wp.NamespaceName),
  2191. new XAttribute(NoNamespace.distT, (long)marginTopInEmus), // distance from top of image to text, in EMUs, no effect if the parent is inline
  2192. new XAttribute(NoNamespace.distB, (long)marginBottomInEmus), // bottom
  2193. new XAttribute(NoNamespace.distL, (long)marginLeftInEmus), // left
  2194. new XAttribute(NoNamespace.distR, (long)marginRightInEmus), // right
  2195. new XAttribute(NoNamespace.simplePos, 0),
  2196. new XAttribute(NoNamespace.relativeHeight, relHeight),
  2197. new XAttribute(NoNamespace.behindDoc, 0),
  2198. new XAttribute(NoNamespace.locked, 0),
  2199. new XAttribute(NoNamespace.layoutInCell, 1),
  2200. new XAttribute(NoNamespace.allowOverlap, 1),
  2201. new XElement(WP.simplePos, new XAttribute(NoNamespace.x, 0), new XAttribute(NoNamespace.y, 0)),
  2202. new XElement(WP.positionH, new XAttribute(NoNamespace.relativeFrom, "column"),
  2203. new XElement(WP.posOffset, (long)relativeFromColumn)),
  2204. new XElement(WP.positionV, new XAttribute(NoNamespace.relativeFrom, "paragraph"),
  2205. new XElement(WP.posOffset, (long)relativeFromParagraph)),
  2206. GetImageExtent(element, bmp),
  2207. GetEffectExtent(),
  2208. new XElement(WP.wrapSquare, new XAttribute(NoNamespace.wrapText, "bothSides")),
  2209. GetDocPr(element, pictureId, pictureDescription),
  2210. GetCNvGraphicFramePr(),
  2211. GetGraphicForImage(element, rId, bmp, pictureId, pictureDescription),
  2212. new XElement(WP14.sizeRelH, new XAttribute(NoNamespace.relativeFrom, "page"),
  2213. new XElement(WP14.pctWidth, 0)),
  2214. new XElement(WP14.sizeRelV, new XAttribute(NoNamespace.relativeFrom, "page"),
  2215. new XElement(WP14.pctHeight, 0))
  2216. );
  2217. return anchor;
  2218. }
  2219. #if false
  2220. <wp:anchor distT="0"
  2221. distB="0"
  2222. distL="114300"
  2223. distR="114300"
  2224. simplePos="0"
  2225. relativeHeight="251658240"
  2226. behindDoc="0"
  2227. locked="0"
  2228. layoutInCell="1"
  2229. allowOverlap="1">
  2230. <wp:simplePos x="0"
  2231. y="0"/>
  2232. <wp:positionH relativeFrom="column">
  2233. <wp:posOffset>0</wp:posOffset>
  2234. </wp:positionH>
  2235. <wp:positionV relativeFrom="paragraph">
  2236. <wp:posOffset>0</wp:posOffset>
  2237. </wp:positionV>
  2238. <wp:extent cx="1713865"
  2239. cy="1656715"/>
  2240. <wp:effectExtent l="0"
  2241. t="0"
  2242. r="635"
  2243. b="635"/>
  2244. <wp:wrapSquare wrapText="bothSides"/>
  2245. <wp:docPr id="1"
  2246. name="Picture 1"
  2247. descr="img.png"/>
  2248. <wp:cNvGraphicFramePr>
  2249. <a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
  2250. noChangeAspect="1"/>
  2251. </wp:cNvGraphicFramePr>
  2252. <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
  2253. <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
  2254. <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
  2255. <pic:nvPicPr>
  2256. <pic:cNvPr id="0"
  2257. name="Picture 1"
  2258. descr="img.png"/>
  2259. <pic:cNvPicPr>
  2260. <a:picLocks noChangeAspect="1"
  2261. noChangeArrowheads="1"/>
  2262. </pic:cNvPicPr>
  2263. </pic:nvPicPr>
  2264. <pic:blipFill>
  2265. <a:blip r:embed="rId5">
  2266. <a:extLst>
  2267. <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
  2268. <a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"
  2269. val="0"/>
  2270. </a:ext>
  2271. </a:extLst>
  2272. </a:blip>
  2273. <a:stretch>
  2274. <a:fillRect/>
  2275. </a:stretch>
  2276. </pic:blipFill>
  2277. <pic:spPr bwMode="auto">
  2278. <a:xfrm>
  2279. <a:off x="0"
  2280. y="0"/>
  2281. <a:ext cx="1713865"
  2282. cy="1656715"/>
  2283. </a:xfrm>
  2284. <a:prstGeom prst="rect">
  2285. <a:avLst/>
  2286. </a:prstGeom>
  2287. <a:noFill/>
  2288. <a:ln>
  2289. <a:noFill/>
  2290. </a:ln>
  2291. </pic:spPr>
  2292. </pic:pic>
  2293. </a:graphicData>
  2294. </a:graphic>
  2295. <wp14:sizeRelH relativeFrom="page">
  2296. <wp14:pctWidth>0</wp14:pctWidth>
  2297. </wp14:sizeRelH>
  2298. <wp14:sizeRelV relativeFrom="page">
  2299. <wp14:pctHeight>0</wp14:pctHeight>
  2300. </wp14:sizeRelV>
  2301. </wp:anchor>
  2302. #endif
  2303. private static XElement GetParagraphPropertiesForImage()
  2304. {
  2305. return null;
  2306. }
  2307. private static XElement GetRunPropertiesForImage()
  2308. {
  2309. return new XElement(W.rPr,
  2310. new XElement(W.noProof));
  2311. }
  2312. private static SizeEmu GetImageSizeInEmus(XElement img, Bitmap bmp)
  2313. {
  2314. double hres = bmp.HorizontalResolution;
  2315. double vres = bmp.VerticalResolution;
  2316. Size s = bmp.Size;
  2317. Emu cx = (long)((double)(s.Width / hres) * (double)Emu.s_EmusPerInch);
  2318. Emu cy = (long)((double)(s.Height / vres) * (double)Emu.s_EmusPerInch);
  2319. CssExpression width = img.GetProp("width");
  2320. CssExpression height = img.GetProp("height");
  2321. if (width.IsNotAuto && height.IsAuto)
  2322. {
  2323. Emu widthInEmus = (Emu)width;
  2324. double percentChange = (float)widthInEmus / (float)cx;
  2325. cx = widthInEmus;
  2326. cy = (long)(cy * percentChange);
  2327. return new SizeEmu(cx, cy);
  2328. }
  2329. if (width.IsAuto && height.IsNotAuto)
  2330. {
  2331. Emu heightInEmus = (Emu)height;
  2332. double percentChange = (float)heightInEmus / (float)cy;
  2333. cy = heightInEmus;
  2334. cx = (long)(cx * percentChange);
  2335. return new SizeEmu(cx, cy);
  2336. }
  2337. if (width.IsNotAuto && height.IsNotAuto)
  2338. {
  2339. return new SizeEmu((Emu)width, (Emu)height);
  2340. }
  2341. return new SizeEmu(cx, cy);
  2342. }
  2343. private static XElement GetImageExtent(XElement img, Bitmap bmp)
  2344. {
  2345. SizeEmu szEmu = GetImageSizeInEmus(img, bmp);
  2346. return new XElement(WP.extent,
  2347. new XAttribute(NoNamespace.cx, (long)szEmu.m_Width), // in EMUs
  2348. new XAttribute(NoNamespace.cy, (long)szEmu.m_Height)); // in EMUs
  2349. }
  2350. private static XElement GetEffectExtent()
  2351. {
  2352. return new XElement(WP.effectExtent,
  2353. new XAttribute(NoNamespace.l, 0),
  2354. new XAttribute(NoNamespace.t, 0),
  2355. new XAttribute(NoNamespace.r, 0),
  2356. new XAttribute(NoNamespace.b, 0));
  2357. }
  2358. private static XElement GetDocPr(XElement element, int pictureId, string pictureDescription)
  2359. {
  2360. return new XElement(WP.docPr,
  2361. new XAttribute(NoNamespace.id, pictureId),
  2362. new XAttribute(NoNamespace.name, pictureDescription),
  2363. new XAttribute(NoNamespace.descr, (string)element.Attribute(NoNamespace.src)));
  2364. }
  2365. private static XElement GetCNvGraphicFramePr()
  2366. {
  2367. return new XElement(WP.cNvGraphicFramePr,
  2368. new XElement(A.graphicFrameLocks,
  2369. new XAttribute(XNamespace.Xmlns + "a", A.a.NamespaceName),
  2370. new XAttribute(NoNamespace.noChangeAspect, 1)));
  2371. }
  2372. private static XElement GetGraphicForImage(XElement element, string rId, Bitmap bmp, int pictureId, string pictureDescription)
  2373. {
  2374. SizeEmu szEmu = GetImageSizeInEmus(element, bmp);
  2375. XElement graphic = new XElement(A.graphic,
  2376. new XAttribute(XNamespace.Xmlns + "a", A.a.NamespaceName),
  2377. new XElement(A.graphicData,
  2378. new XAttribute(NoNamespace.uri, Pic.pic.NamespaceName),
  2379. new XElement(Pic._pic,
  2380. new XAttribute(XNamespace.Xmlns + "pic", Pic.pic.NamespaceName),
  2381. new XElement(Pic.nvPicPr,
  2382. new XElement(Pic.cNvPr,
  2383. new XAttribute(NoNamespace.id, pictureId),
  2384. new XAttribute(NoNamespace.name, pictureDescription),
  2385. new XAttribute(NoNamespace.descr, (string)element.Attribute(NoNamespace.src))),
  2386. new XElement(Pic.cNvPicPr,
  2387. new XElement(A.picLocks,
  2388. new XAttribute(NoNamespace.noChangeAspect, 1),
  2389. new XAttribute(NoNamespace.noChangeArrowheads, 1)))),
  2390. new XElement(Pic.blipFill,
  2391. new XElement(A.blip,
  2392. new XAttribute(R.embed, rId),
  2393. new XElement(A.extLst,
  2394. new XElement(A.ext,
  2395. new XAttribute(NoNamespace.uri, "{28A0092B-C50C-407E-A947-70E740481C1C}"),
  2396. new XElement(A14.useLocalDpi,
  2397. new XAttribute(NoNamespace.val, "0"))))),
  2398. new XElement(A.stretch,
  2399. new XElement(A.fillRect))),
  2400. new XElement(Pic.spPr,
  2401. new XAttribute(NoNamespace.bwMode, "auto"),
  2402. new XElement(A.xfrm,
  2403. new XElement(A.off, new XAttribute(NoNamespace.x, 0), new XAttribute(NoNamespace.y, 0)),
  2404. new XElement(A.ext, new XAttribute(NoNamespace.cx, (long)szEmu.m_Width), new XAttribute(NoNamespace.cy, (long)szEmu.m_Height))),
  2405. new XElement(A.prstGeom, new XAttribute(NoNamespace.prst, "rect"),
  2406. new XElement(A.avLst)),
  2407. new XElement(A.noFill),
  2408. new XElement(A.ln,
  2409. new XElement(A.noFill))))));
  2410. return graphic;
  2411. }
  2412. #if false
  2413. <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
  2414. <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
  2415. <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
  2416. <pic:nvPicPr>
  2417. <pic:cNvPr id="0" name="Picture 1" descr="img.png"/>
  2418. <pic:cNvPicPr>
  2419. <a:picLocks noChangeAspect="1" noChangeArrowheads="1"/>
  2420. </pic:cNvPicPr>
  2421. </pic:nvPicPr>
  2422. <pic:blipFill>
  2423. <a:blip r:link="rId5">
  2424. <a:extLst>
  2425. <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
  2426. <a14:useLocalDpi xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main" val="0"/>
  2427. </a:ext>
  2428. </a:extLst>
  2429. </a:blip>
  2430. <a:srcRect/>
  2431. <a:stretch>
  2432. <a:fillRect/>
  2433. </a:stretch>
  2434. </pic:blipFill>
  2435. <pic:spPr bwMode="auto">
  2436. <a:xfrm>
  2437. <a:off x="0" y="0"/>
  2438. <a:ext cx="1781175" cy="1781175"/>
  2439. </a:xfrm>
  2440. <a:prstGeom prst="rect">
  2441. <a:avLst/>
  2442. </a:prstGeom>
  2443. <a:noFill/>
  2444. <a:ln>
  2445. <a:noFill/>
  2446. </a:ln>
  2447. </pic:spPr>
  2448. </pic:pic>
  2449. </a:graphicData>
  2450. </a:graphic>
  2451. #endif
  2452. private static XElement GetParagraphProperties(XElement blockLevelElement, string styleName, HtmlToWmlConverterSettings settings)
  2453. {
  2454. XElement paragraphMarkRunProperties = GetRunProperties(blockLevelElement, settings);
  2455. XElement backgroundProperty = GetBackgroundProperty(blockLevelElement);
  2456. XElement[] spacingProperty = GetSpacingProperties(blockLevelElement, settings); // spacing, ind, contextualSpacing
  2457. XElement jc = GetJustification(blockLevelElement, settings);
  2458. XElement pStyle = styleName != null ? new XElement(W.pStyle, new XAttribute(W.val, styleName)) : null;
  2459. XElement numPr = GetNumberingProperties(blockLevelElement, settings);
  2460. XElement pBdr = GetBlockContentBorders(blockLevelElement, W.pBdr, true);
  2461. XElement bidi = null;
  2462. string direction = GetDirection(blockLevelElement);
  2463. if (direction == "rtl")
  2464. bidi = new XElement(W.bidi);
  2465. XElement pPr = new XElement(W.pPr,
  2466. pStyle,
  2467. numPr,
  2468. pBdr,
  2469. backgroundProperty,
  2470. bidi,
  2471. spacingProperty,
  2472. jc,
  2473. paragraphMarkRunProperties
  2474. );
  2475. return pPr;
  2476. }
  2477. // vertical-align doesn't really work in the Word rendering - puts space above, but not below. There really are no
  2478. // options in WordprocessingML to specify vertical alignment. I think that the only possible way that this could be
  2479. // implemented would be to specifically calculate the space before and space after. I'm not completely sure that
  2480. // this could be possible. I am pretty sure that this is not worth the effort.
  2481. // Returns the spacing, ind, and contextualSpacing elements
  2482. private static XElement[] GetSpacingProperties(XElement paragraph, HtmlToWmlConverterSettings settings)
  2483. {
  2484. CssExpression marginLeftProperty = paragraph.GetProp("margin-left");
  2485. CssExpression marginRightProperty = paragraph.GetProp("margin-right");
  2486. CssExpression marginTopProperty = paragraph.GetProp("margin-top");
  2487. CssExpression marginBottomProperty = paragraph.GetProp("margin-bottom");
  2488. CssExpression lineHeightProperty = paragraph.GetProp("line-height");
  2489. CssExpression leftPaddingProperty = paragraph.GetProp("padding-left");
  2490. CssExpression rightPaddingProperty = paragraph.GetProp("padding-right");
  2491. /*****************************************************************************************/
  2492. // leftIndent, rightIndent, firstLine
  2493. Twip leftIndent = 0;
  2494. Twip rightIndent = 0;
  2495. Twip firstLine = 0;
  2496. #if false
  2497. // this code is here for some reason. What is it?
  2498. double leftBorderSize = GetBorderSize(paragraph, "left"); // in 1/8 point
  2499. double rightBorderSize = GetBorderSize(paragraph, "right"); // in 1/8 point
  2500. leftIndent += (long)((leftBorderSize / 8d) * 20d);
  2501. rightIndent += (long)((rightBorderSize / 8d) * 20d);
  2502. #endif
  2503. if (leftPaddingProperty != null)
  2504. leftIndent += (Twip)leftPaddingProperty;
  2505. if (rightPaddingProperty != null)
  2506. rightIndent += (Twip)rightPaddingProperty;
  2507. if (paragraph.Name == XhtmlNoNamespace.li)
  2508. {
  2509. leftIndent += 180;
  2510. rightIndent += 180;
  2511. }
  2512. XElement listElement = null;
  2513. NumberedItemAnnotation numberedItemAnnotation = null;
  2514. listElement = paragraph.Ancestors().FirstOrDefault(a => a.Name == XhtmlNoNamespace.ol || a.Name == XhtmlNoNamespace.ul);
  2515. if (listElement != null)
  2516. {
  2517. numberedItemAnnotation = listElement.Annotation<NumberedItemAnnotation>();
  2518. leftIndent += 600 * (numberedItemAnnotation.ilvl + 1);
  2519. }
  2520. int blockQuoteCount = paragraph.Ancestors(XhtmlNoNamespace.blockquote).Count();
  2521. leftIndent += blockQuoteCount * 720;
  2522. if (blockQuoteCount == 0)
  2523. {
  2524. if (marginLeftProperty != null && marginLeftProperty.IsNotAuto && marginLeftProperty.IsNotNormal)
  2525. leftIndent += (Twip)marginLeftProperty;
  2526. if (marginRightProperty != null && marginRightProperty.IsNotAuto && marginRightProperty.IsNotNormal)
  2527. rightIndent += (Twip)marginRightProperty;
  2528. }
  2529. CssExpression textIndentProperty = paragraph.GetProp("text-indent");
  2530. if (textIndentProperty != null)
  2531. {
  2532. Twip twips = (Twip)textIndentProperty;
  2533. firstLine = twips;
  2534. }
  2535. XElement ind = null;
  2536. if (leftIndent > 0 || rightIndent > 0 || firstLine != 0)
  2537. {
  2538. if (firstLine < 0)
  2539. ind = new XElement(W.ind,
  2540. leftIndent != 0 ? new XAttribute(W.left, (long)leftIndent) : null,
  2541. rightIndent != 0 ? new XAttribute(W.right, (long)rightIndent) : null,
  2542. firstLine != 0 ? new XAttribute(W.hanging, -(long)firstLine) : null);
  2543. else
  2544. ind = new XElement(W.ind,
  2545. leftIndent != 0 ? new XAttribute(W.left, (long)leftIndent) : null,
  2546. rightIndent != 0 ? new XAttribute(W.right, (long)rightIndent) : null,
  2547. firstLine != 0 ? new XAttribute(W.firstLine, (long)firstLine) : null);
  2548. }
  2549. /*****************************************************************************************/
  2550. // spacing
  2551. long line = 240;
  2552. string lineRule = "auto";
  2553. string beforeAutospacing = null;
  2554. string afterAutospacing = null;
  2555. long? before = null;
  2556. long? after = null;
  2557. if (paragraph.Name == XhtmlNoNamespace.td || paragraph.Name == XhtmlNoNamespace.th || paragraph.Name == XhtmlNoNamespace.caption)
  2558. {
  2559. line = (long)settings.DefaultSpacingElementForParagraphsInTables.Attribute(W.line);
  2560. lineRule = (string)settings.DefaultSpacingElementForParagraphsInTables.Attribute(W.lineRule);
  2561. before = (long?)settings.DefaultSpacingElementForParagraphsInTables.Attribute(W.before);
  2562. beforeAutospacing = (string)settings.DefaultSpacingElementForParagraphsInTables.Attribute(W.beforeAutospacing);
  2563. after = (long?)settings.DefaultSpacingElementForParagraphsInTables.Attribute(W.after);
  2564. afterAutospacing = (string)settings.DefaultSpacingElementForParagraphsInTables.Attribute(W.afterAutospacing);
  2565. }
  2566. // todo should check based on display property
  2567. bool numItem = paragraph.Name == XhtmlNoNamespace.li;
  2568. if (numItem && marginTopProperty.IsAuto)
  2569. beforeAutospacing = "1";
  2570. if (numItem && marginBottomProperty.IsAuto)
  2571. afterAutospacing = "1";
  2572. if (marginTopProperty != null && marginTopProperty.IsNotAuto)
  2573. {
  2574. before = (long)(Twip)marginTopProperty;
  2575. beforeAutospacing = "0";
  2576. }
  2577. if (marginBottomProperty != null && marginBottomProperty.IsNotAuto)
  2578. {
  2579. after = (long)(Twip)marginBottomProperty;
  2580. afterAutospacing = "0";
  2581. }
  2582. if (lineHeightProperty != null && lineHeightProperty.IsNotAuto && lineHeightProperty.IsNotNormal)
  2583. {
  2584. // line is in twips if lineRule == "atLeast"
  2585. line = (long)(Twip)lineHeightProperty;
  2586. lineRule = "atLeast";
  2587. }
  2588. XElement spacing = new XElement(W.spacing,
  2589. before != null ? new XAttribute(W.before, before) : null,
  2590. beforeAutospacing != null ? new XAttribute(W.beforeAutospacing, beforeAutospacing) : null,
  2591. after != null ? new XAttribute(W.after, after) : null,
  2592. afterAutospacing != null ? new XAttribute(W.afterAutospacing, afterAutospacing) : null,
  2593. new XAttribute(W.line, line),
  2594. new XAttribute(W.lineRule, lineRule));
  2595. /*****************************************************************************************/
  2596. // contextualSpacing
  2597. XElement contextualSpacing = null;
  2598. if (paragraph.Name == XhtmlNoNamespace.li)
  2599. {
  2600. NumberedItemAnnotation thisNumberedItemAnnotation = null;
  2601. XElement listElement2 = paragraph.Ancestors().FirstOrDefault(a => a.Name == XhtmlNoNamespace.ol || a.Name == XhtmlNoNamespace.ul);
  2602. if (listElement2 != null)
  2603. {
  2604. thisNumberedItemAnnotation = listElement2.Annotation<NumberedItemAnnotation>();
  2605. XElement next = paragraph.ElementsAfterSelf().FirstOrDefault();
  2606. if (next != null && next.Name == XhtmlNoNamespace.li)
  2607. {
  2608. XElement nextListElement = next.Ancestors().FirstOrDefault(a => a.Name == XhtmlNoNamespace.ol || a.Name == XhtmlNoNamespace.ul);
  2609. NumberedItemAnnotation nextNumberedItemAnnotation = nextListElement.Annotation<NumberedItemAnnotation>();
  2610. if (nextNumberedItemAnnotation != null && thisNumberedItemAnnotation.numId == nextNumberedItemAnnotation.numId)
  2611. contextualSpacing = new XElement(W.contextualSpacing);
  2612. }
  2613. }
  2614. }
  2615. return new XElement[] { spacing, ind, contextualSpacing };
  2616. }
  2617. private static XElement GetRunProperties(XText textNode, HtmlToWmlConverterSettings settings)
  2618. {
  2619. XElement parent = textNode.Parent;
  2620. XElement rPr = GetRunProperties(parent, settings);
  2621. return rPr;
  2622. }
  2623. private static XElement GetRunProperties(XElement element, HtmlToWmlConverterSettings settings)
  2624. {
  2625. CssExpression colorProperty = element.GetProp("color");
  2626. CssExpression fontFamilyProperty = element.GetProp("font-family");
  2627. CssExpression fontSizeProperty = element.GetProp("font-size");
  2628. CssExpression textDecorationProperty = element.GetProp("text-decoration");
  2629. CssExpression fontStyleProperty = element.GetProp("font-style");
  2630. CssExpression fontWeightProperty = element.GetProp("font-weight");
  2631. CssExpression backgroundColorProperty = element.GetProp("background-color");
  2632. CssExpression letterSpacingProperty = element.GetProp("letter-spacing");
  2633. CssExpression directionProp = element.GetProp("direction");
  2634. string colorPropertyString = colorProperty.ToString();
  2635. string fontFamilyString = GetUsedFontFromFontFamilyProperty(fontFamilyProperty);
  2636. TPoint? fontSizeTPoint = GetUsedSizeFromFontSizeProperty(fontSizeProperty);
  2637. string textDecorationString = textDecorationProperty.ToString();
  2638. string fontStyleString = fontStyleProperty.ToString();
  2639. string fontWeightString = fontWeightProperty.ToString().ToLower();
  2640. string backgroundColorString = backgroundColorProperty.ToString().ToLower();
  2641. string letterSpacingString = letterSpacingProperty.ToString().ToLower();
  2642. string directionString = directionProp.ToString().ToLower();
  2643. bool subAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.sub).Any();
  2644. bool supAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.sup).Any();
  2645. bool bAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.b).Any();
  2646. bool iAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.i).Any();
  2647. bool strongAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.strong).Any();
  2648. bool emAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.em).Any();
  2649. bool uAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.u).Any();
  2650. bool sAncestor = element.AncestorsAndSelf(XhtmlNoNamespace.s).Any();
  2651. XAttribute dirAttribute = element.Attribute(XhtmlNoNamespace.dir);
  2652. string dirAttributeString = "";
  2653. if (dirAttribute != null)
  2654. dirAttributeString = dirAttribute.Value.ToLower();
  2655. XElement shd = null;
  2656. if (backgroundColorString != "transparent")
  2657. shd = new XElement(W.shd, new XAttribute(W.val, "clear"),
  2658. new XAttribute(W.color, "auto"),
  2659. new XAttribute(W.fill, backgroundColorString));
  2660. XElement subSuper = null;
  2661. if (subAncestor)
  2662. subSuper = new XElement(W.vertAlign, new XAttribute(W.val, "subscript"));
  2663. else
  2664. if (supAncestor)
  2665. subSuper = new XElement(W.vertAlign, new XAttribute(W.val, "superscript"));
  2666. XElement rFonts = null;
  2667. if (fontFamilyString != null)
  2668. {
  2669. rFonts = new XElement(W.rFonts,
  2670. fontFamilyString != settings.MinorLatinFont ? new XAttribute(W.ascii, fontFamilyString) : null,
  2671. fontFamilyString != settings.MajorLatinFont ? new XAttribute(W.hAnsi, fontFamilyString) : null,
  2672. new XAttribute(W.cs, fontFamilyString));
  2673. }
  2674. // todo I think this puts a color on every element.
  2675. XElement color = colorPropertyString != null ?
  2676. new XElement(W.color, new XAttribute(W.val, colorPropertyString)) : null;
  2677. XElement sz = null;
  2678. XElement szCs = null;
  2679. if (fontSizeTPoint != null)
  2680. {
  2681. sz = new XElement(W.sz, new XAttribute(W.val, (int)((double)fontSizeTPoint * 2)));
  2682. szCs = new XElement(W.szCs, new XAttribute(W.val, (int)((double)fontSizeTPoint * 2)));
  2683. }
  2684. XElement strike = null;
  2685. if (textDecorationString == "line-through" || sAncestor)
  2686. strike = new XElement(W.strike);
  2687. XElement bold = null;
  2688. XElement boldCs = null;
  2689. if (bAncestor || strongAncestor || fontWeightString == "bold" || fontWeightString == "bolder" || fontWeightString == "600" || fontWeightString == "700" || fontWeightString == "800" || fontWeightString == "900")
  2690. {
  2691. bold = new XElement(W.b);
  2692. boldCs = new XElement(W.bCs);
  2693. }
  2694. XElement italic = null;
  2695. XElement italicCs = null;
  2696. if (iAncestor || emAncestor || fontStyleString == "italic")
  2697. {
  2698. italic = new XElement(W.i);
  2699. italicCs = new XElement(W.iCs);
  2700. }
  2701. XElement underline = null;
  2702. if (uAncestor || textDecorationString == "underline")
  2703. underline = new XElement(W.u, new XAttribute(W.val, "single"));
  2704. XElement rStyle = null;
  2705. if (element.Name == XhtmlNoNamespace.a)
  2706. rStyle = new XElement(W.rStyle,
  2707. new XAttribute(W.val, "Hyperlink"));
  2708. XElement spacing = null;
  2709. if (letterSpacingProperty.IsNotNormal)
  2710. spacing = new XElement(W.spacing,
  2711. new XAttribute(W.val, (long)(Twip)letterSpacingProperty));
  2712. XElement rtl = null;
  2713. if (dirAttributeString == "rtl" || directionString == "rtl")
  2714. rtl = new XElement(W.rtl);
  2715. XElement runProps = new XElement(W.rPr,
  2716. rStyle,
  2717. rFonts,
  2718. bold,
  2719. boldCs,
  2720. italic,
  2721. italicCs,
  2722. strike,
  2723. color,
  2724. spacing,
  2725. sz,
  2726. szCs,
  2727. underline,
  2728. shd,
  2729. subSuper,
  2730. rtl);
  2731. if (runProps.Elements().Any())
  2732. return runProps;
  2733. return null;
  2734. }
  2735. // todo can make this faster
  2736. // todo this is not right - needs to be rationalized for all characters in an entire paragraph.
  2737. // if there is text like <p>abc <em> def </em> ghi</p> then there needs to be just one space between abc and def, and between
  2738. // def and ghi.
  2739. private static string GetDisplayText(XText node, bool preserveWhiteSpace)
  2740. {
  2741. string textTransform = node.Parent.GetProp("text-transform").ToString();
  2742. bool isFirst = node.Parent.Name == XhtmlNoNamespace.p && node == node.Parent.FirstNode;
  2743. bool isLast = node.Parent.Name == XhtmlNoNamespace.p && node == node.Parent.LastNode;
  2744. IEnumerable<IGrouping<bool, char>> groupedCharacters = null;
  2745. if (preserveWhiteSpace)
  2746. groupedCharacters = node.Value.GroupAdjacent(c => c == '\r' || c == '\n');
  2747. else
  2748. groupedCharacters = node.Value.GroupAdjacent(c => c == ' ' || c == '\r' || c == '\n');
  2749. string newString = groupedCharacters.Select(g =>
  2750. {
  2751. if (g.Key == true)
  2752. return " ";
  2753. string x = g.Select(c => c.ToString()).StringConcatenate();
  2754. return x;
  2755. })
  2756. .StringConcatenate();
  2757. if (!preserveWhiteSpace)
  2758. {
  2759. if (isFirst)
  2760. newString = newString.TrimStart();
  2761. if (isLast)
  2762. newString = newString.TrimEnd();
  2763. }
  2764. if (textTransform == "uppercase")
  2765. newString = newString.ToUpper();
  2766. else if (textTransform == "lowercase")
  2767. newString = newString.ToLower();
  2768. else if (textTransform == "capitalize")
  2769. newString = newString.Substring(0, 1).ToUpper() + newString.Substring(1).ToLower();
  2770. return newString;
  2771. }
  2772. private static XElement GetNumberingProperties(XElement paragraph, HtmlToWmlConverterSettings settings)
  2773. {
  2774. // Numbering properties ******************************************************
  2775. NumberedItemAnnotation numberedItemAnnotation = null;
  2776. XElement listElement = paragraph.Ancestors().FirstOrDefault(a => a.Name == XhtmlNoNamespace.ol || a.Name == XhtmlNoNamespace.ul);
  2777. if (listElement != null)
  2778. {
  2779. numberedItemAnnotation = listElement.Annotation<NumberedItemAnnotation>();
  2780. }
  2781. XElement numPr = null;
  2782. if (paragraph.Name == XhtmlNoNamespace.li)
  2783. numPr = new XElement(W.numPr,
  2784. new XElement(W.ilvl, new XAttribute(W.val, numberedItemAnnotation.ilvl)),
  2785. new XElement(W.numId, new XAttribute(W.val, numberedItemAnnotation.numId)));
  2786. return numPr;
  2787. }
  2788. private static XElement GetJustification(XElement blockLevelElement, HtmlToWmlConverterSettings settings)
  2789. {
  2790. // Justify ******************************************************
  2791. CssExpression textAlignProperty = blockLevelElement.GetProp("text-align");
  2792. string textAlign;
  2793. if (blockLevelElement.Name == XhtmlNoNamespace.caption || blockLevelElement.Name == XhtmlNoNamespace.th)
  2794. textAlign = "center";
  2795. else
  2796. textAlign = "left";
  2797. if (textAlignProperty != null)
  2798. textAlign = textAlignProperty.ToString();
  2799. string jc = null;
  2800. if (textAlign == "center")
  2801. jc = "center";
  2802. else
  2803. {
  2804. if (textAlign == "right")
  2805. jc = "right";
  2806. else
  2807. {
  2808. if (textAlign == "justify")
  2809. jc = "both";
  2810. }
  2811. }
  2812. string direction = GetDirection(blockLevelElement);
  2813. if (direction == "rtl")
  2814. {
  2815. if (jc == "left")
  2816. jc = "right";
  2817. else if (jc == "right")
  2818. jc = "left";
  2819. }
  2820. XElement jcElement = null;
  2821. if (jc != null)
  2822. jcElement = new XElement(W.jc, new XAttribute(W.val, jc));
  2823. return jcElement;
  2824. }
  2825. private class HeadingInfo
  2826. {
  2827. public XName Name;
  2828. public string StyleName;
  2829. };
  2830. private static HeadingInfo[] HeadingTagMap = new[]
  2831. {
  2832. new HeadingInfo { Name = XhtmlNoNamespace.h1, StyleName = "Heading1" },
  2833. new HeadingInfo { Name = XhtmlNoNamespace.h2, StyleName = "Heading2" },
  2834. new HeadingInfo { Name = XhtmlNoNamespace.h3, StyleName = "Heading3" },
  2835. new HeadingInfo { Name = XhtmlNoNamespace.h4, StyleName = "Heading4" },
  2836. new HeadingInfo { Name = XhtmlNoNamespace.h5, StyleName = "Heading5" },
  2837. new HeadingInfo { Name = XhtmlNoNamespace.h6, StyleName = "Heading6" },
  2838. new HeadingInfo { Name = XhtmlNoNamespace.h7, StyleName = "Heading7" },
  2839. new HeadingInfo { Name = XhtmlNoNamespace.h8, StyleName = "Heading8" },
  2840. };
  2841. private static string GetDirection(XElement element)
  2842. {
  2843. string retValue = "ltr";
  2844. string dirString = (string)element.Attribute(XhtmlNoNamespace.dir);
  2845. if (dirString != null && dirString.ToLower() == "rtl")
  2846. retValue = "rtl";
  2847. CssExpression directionProp = element.GetProp("direction");
  2848. if (directionProp != null)
  2849. {
  2850. string directionValue = directionProp.ToString();
  2851. if (directionValue.ToLower() == "rtl")
  2852. retValue = "rtl";
  2853. }
  2854. return retValue;
  2855. }
  2856. private static XElement GetTableProperties(XElement element)
  2857. {
  2858. XElement bidiVisual = null;
  2859. string direction = GetDirection(element);
  2860. if (direction == "rtl")
  2861. bidiVisual = new XElement(W.bidiVisual);
  2862. XElement tblPr = new XElement(W.tblPr,
  2863. bidiVisual,
  2864. GetTableWidth(element),
  2865. GetTableCellSpacing(element),
  2866. GetBlockContentBorders(element, W.tblBorders, false),
  2867. GetTableShading(element),
  2868. GetTableCellMargins(element),
  2869. GetTableLook(element));
  2870. return tblPr;
  2871. }
  2872. private static XElement GetTableShading(XElement element)
  2873. {
  2874. // todo this is not done.
  2875. // needs to work for W.tbl and W.tc
  2876. //XElement shd = new XElement(W.shd,
  2877. // new XAttribute(W.val, "clear"),
  2878. // new XAttribute(W.color, "auto"),
  2879. // new XAttribute(W.fill, "ffffff"));
  2880. //return shd;
  2881. return null;
  2882. }
  2883. private static XElement GetTableWidth(XElement element)
  2884. {
  2885. CssExpression width = element.GetProp("width");
  2886. if (width.IsAuto)
  2887. {
  2888. return new XElement(W.tblW,
  2889. new XAttribute(W._w, "0"),
  2890. new XAttribute(W.type, "auto"));
  2891. }
  2892. XElement widthElement = new XElement(W.tblW,
  2893. new XAttribute(W._w, (long)(Twip)width),
  2894. new XAttribute(W.type, "dxa"));
  2895. return widthElement;
  2896. }
  2897. private static XElement GetCellWidth(XElement element)
  2898. {
  2899. CssExpression width = element.GetProp("width");
  2900. if (width.IsAuto)
  2901. {
  2902. return new XElement(W.tcW,
  2903. new XAttribute(W._w, "0"),
  2904. new XAttribute(W.type, "auto"));
  2905. }
  2906. XElement widthElement = new XElement(W.tcW,
  2907. new XAttribute(W._w, (long)(Twip)width),
  2908. new XAttribute(W.type, "dxa"));
  2909. return widthElement;
  2910. }
  2911. private static XElement GetBlockContentBorders(XElement element, XName borderXName, bool forParagraph)
  2912. {
  2913. if ((element.Name == XhtmlNoNamespace.td || element.Name == XhtmlNoNamespace.th || element.Name == XhtmlNoNamespace.caption) && forParagraph)
  2914. return null;
  2915. XElement borders = new XElement(borderXName,
  2916. new XElement(W.top, GetBorderAttributes(element, "top")),
  2917. new XElement(W.left, GetBorderAttributes(element, "left")),
  2918. new XElement(W.bottom, GetBorderAttributes(element, "bottom")),
  2919. new XElement(W.right, GetBorderAttributes(element, "right")));
  2920. if (borders.Elements().Attributes(W.val).Where(v => (string)v == "none").Count() == 4)
  2921. return null;
  2922. return borders;
  2923. }
  2924. private static Dictionary<string, string> BorderStyleMap = new Dictionary<string, string>()
  2925. {
  2926. { "none", "none" },
  2927. { "hidden", "none" },
  2928. { "dotted", "dotted" },
  2929. { "dashed", "dashed" },
  2930. { "solid", "single" },
  2931. { "double", "double" },
  2932. { "groove", "inset" },
  2933. { "ridge", "outset" },
  2934. { "inset", "inset" },
  2935. { "outset", "outset" },
  2936. };
  2937. private static List<XAttribute> GetBorderAttributes(XElement element, string whichBorder)
  2938. {
  2939. //if (whichBorder == "right")
  2940. // Console.WriteLine(1);
  2941. CssExpression styleProp = element.GetProp(string.Format("border-{0}-style", whichBorder));
  2942. CssExpression colorProp = element.GetProp(string.Format("border-{0}-color", whichBorder));
  2943. CssExpression paddingProp = element.GetProp(string.Format("padding-{0}", whichBorder));
  2944. CssExpression marginProp = element.GetProp(string.Format("margin-{0}", whichBorder));
  2945. // The space attribute is equivalent to the margin properties of CSS
  2946. // the ind element of the parent is more or less equivalent to the padding properties of CSS, except that ind takes space
  2947. // AWAY from the space attribute, therefore ind needs to be increased by the amount of padding.
  2948. // if there is no border, and yet there is padding, then need to create a thin border so that word will display the background
  2949. // color of the paragraph properly (including padding).
  2950. XAttribute val = null;
  2951. XAttribute sz = null;
  2952. XAttribute space = null;
  2953. XAttribute color = null;
  2954. if (styleProp != null)
  2955. {
  2956. if (BorderStyleMap.ContainsKey(styleProp.ToString()))
  2957. val = new XAttribute(W.val, BorderStyleMap[styleProp.ToString()]);
  2958. else
  2959. val = new XAttribute(W.val, "none");
  2960. }
  2961. double borderSizeInTwips = GetBorderSize(element, whichBorder);
  2962. double borderSizeInOneEighthPoint = borderSizeInTwips / 20 * 8;
  2963. sz = new XAttribute(W.sz, (int)borderSizeInOneEighthPoint);
  2964. if (element.Name == XhtmlNoNamespace.td || element.Name == XhtmlNoNamespace.th)
  2965. {
  2966. space = new XAttribute(W.space, "0");
  2967. #if false
  2968. // 2012-05-14 todo alternative algorithm for margin for cells
  2969. if (marginProp != null)
  2970. {
  2971. // space is specified in points, not twips
  2972. TPoint points = 0;
  2973. if (marginProp.IsNotAuto)
  2974. points = (TPoint)marginProp;
  2975. space = new XAttribute(W.space, Math.Min(31, (double)points));
  2976. }
  2977. #endif
  2978. }
  2979. else
  2980. {
  2981. space = new XAttribute(W.space, "0");
  2982. if (paddingProp != null)
  2983. {
  2984. // space is specified in points, not twips
  2985. TPoint points = (TPoint)paddingProp;
  2986. space = new XAttribute(W.space, (int)(Math.Min(31, (double)points)));
  2987. }
  2988. }
  2989. if (colorProp != null)
  2990. color = new XAttribute(W.color, colorProp.ToString());
  2991. // no default yet
  2992. if ((string)val == "none" && (double)space != 0d)
  2993. {
  2994. val.Value = "single";
  2995. sz.Value = "0";
  2996. //color.Value = "FF0000";
  2997. }
  2998. // sz is in 1/8 of a point
  2999. // space is in 1/20 of a point
  3000. List<XAttribute> attList = new List<XAttribute>()
  3001. {
  3002. val,
  3003. sz,
  3004. space,
  3005. color,
  3006. };
  3007. return attList;
  3008. }
  3009. private static Twip GetBorderSize(XElement element, string whichBorder)
  3010. {
  3011. CssExpression widthProp = element.GetProp(string.Format("border-{0}-width", whichBorder));
  3012. if (widthProp != null && widthProp.Terms.Count() == 1)
  3013. {
  3014. CssTerm term = widthProp.Terms.First();
  3015. Twip twips = (Twip)widthProp;
  3016. return twips;
  3017. }
  3018. return 12;
  3019. }
  3020. private static XElement GetTableLook(XElement element)
  3021. {
  3022. XElement tblLook = XElement.Parse(
  3023. //@"<w:tblLook w:val='0600'
  3024. // w:firstRow='0'
  3025. // w:lastRow='0'
  3026. // w:firstColumn='0'
  3027. // w:lastColumn='0'
  3028. // w:noHBand='1'
  3029. // w:noVBand='1'
  3030. // xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'/>"
  3031. @"<w:tblLook w:val='0600' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'/>"
  3032. );
  3033. tblLook.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
  3034. return tblLook;
  3035. }
  3036. private static XElement GetTableGrid(XElement element, HtmlToWmlConverterSettings settings)
  3037. {
  3038. Twip? pageWidthInTwips = (int?)settings.SectPr.Elements(W.pgSz).Attributes(W._w).FirstOrDefault();
  3039. Twip? marginLeft = (int?)settings.SectPr.Elements(W.pgMar).Attributes(W.left).FirstOrDefault();
  3040. Twip? marginRight = (int?)settings.SectPr.Elements(W.pgMar).Attributes(W.right).FirstOrDefault();
  3041. Twip printable = (long)pageWidthInTwips - (long)marginLeft - (long)marginRight;
  3042. XElement[][] tableArray = GetTableArray(element);
  3043. int numberColumns = tableArray[0].Length;
  3044. CssExpression[] columnWidths = new CssExpression[numberColumns];
  3045. for (int c = 0; c < numberColumns; c++)
  3046. {
  3047. CssExpression columnWidth = new CssExpression { Terms = new List<CssTerm> { new CssTerm { Value = "auto" } } };
  3048. for (int r = 0; r < tableArray.Length; ++r)
  3049. {
  3050. if (tableArray[r][c] != null)
  3051. {
  3052. XElement cell = tableArray[r][c];
  3053. CssExpression width = cell.GetProp("width");
  3054. XAttribute colSpan = cell.Attribute(XhtmlNoNamespace.colspan);
  3055. if (colSpan == null && columnWidth.ToString() == "auto" && width.ToString() != "auto")
  3056. {
  3057. columnWidth = width;
  3058. break;
  3059. }
  3060. }
  3061. }
  3062. columnWidths[c] = columnWidth;
  3063. }
  3064. XElement tblGrid = new XElement(W.tblGrid,
  3065. columnWidths.Select(cw => new XElement(W.gridCol,
  3066. new XAttribute(W._w, (long)GetTwipWidth(cw, (int)printable)))));
  3067. return tblGrid;
  3068. }
  3069. private static Twip GetTwipWidth(CssExpression columnWidth, int printable)
  3070. {
  3071. Twip defaultTwipWidth = 1440;
  3072. if (columnWidth.Terms.Count() == 1)
  3073. {
  3074. CssTerm term = columnWidth.Terms.First();
  3075. if (term.Unit == CssUnit.PT)
  3076. {
  3077. Double ptValue;
  3078. if (Double.TryParse(term.Value, out ptValue))
  3079. {
  3080. Twip twips = (long)(ptValue * 20);
  3081. return twips;
  3082. }
  3083. return defaultTwipWidth;
  3084. }
  3085. }
  3086. return defaultTwipWidth;
  3087. }
  3088. private static XElement[][] GetTableArray(XElement table)
  3089. {
  3090. List<XElement> rowList = table.DescendantsTrimmed(XhtmlNoNamespace.table).Where(e => e.Name == XhtmlNoNamespace.tr).ToList();
  3091. int numberColumns = rowList.Select(r => r.Elements().Where(e => e.Name == XhtmlNoNamespace.td || e.Name == XhtmlNoNamespace.th).Count()).Max();
  3092. XElement[][] tableArray = new XElement[rowList.Count()][];
  3093. int rowNumber = 0;
  3094. foreach (var row in rowList)
  3095. {
  3096. tableArray[rowNumber] = new XElement[numberColumns];
  3097. int columnNumber = 0;
  3098. foreach (var cell in row.Elements(XhtmlNoNamespace.td))
  3099. {
  3100. tableArray[rowNumber][columnNumber] = cell;
  3101. columnNumber++;
  3102. }
  3103. rowNumber++;
  3104. }
  3105. return tableArray;
  3106. }
  3107. private static XElement GetCellPropertiesForCaption(XElement element)
  3108. {
  3109. XElement gridSpan = new XElement(W.gridSpan,
  3110. new XAttribute(W.val, 3));
  3111. XElement tcBorders = GetBlockContentBorders(element, W.tcBorders, false);
  3112. if (tcBorders == null)
  3113. tcBorders = new XElement(W.tcBorders,
  3114. new XElement(W.top, new XAttribute(W.val, "nil")),
  3115. new XElement(W.left, new XAttribute(W.val, "nil")),
  3116. new XElement(W.bottom, new XAttribute(W.val, "nil")),
  3117. new XElement(W.right, new XAttribute(W.val, "nil")));
  3118. XElement shd = GetCellShading(element);
  3119. //XElement hideMark = new XElement(W.hideMark);
  3120. XElement hideMark = null;
  3121. XElement tcMar = GetCellMargins(element);
  3122. XElement vAlign = new XElement(W.vAlign, new XAttribute(W.val, "center"));
  3123. return new XElement(W.tcPr,
  3124. gridSpan,
  3125. tcBorders,
  3126. shd,
  3127. tcMar,
  3128. vAlign,
  3129. hideMark);
  3130. }
  3131. private static XElement GetCellProperties(XElement element)
  3132. {
  3133. int? colspan = (int?)element.Attribute(XhtmlNoNamespace.colspan);
  3134. XElement gridSpan = null;
  3135. if (colspan != null)
  3136. gridSpan = new XElement(W.gridSpan,
  3137. new XAttribute(W.val, colspan));
  3138. XElement tblW = GetCellWidth(element);
  3139. XElement tcBorders = GetBlockContentBorders(element, W.tcBorders, false);
  3140. XElement shd = GetCellShading(element);
  3141. //XElement hideMark = new XElement(W.hideMark);
  3142. XElement hideMark = null;
  3143. XElement tcMar = GetCellMargins(element);
  3144. XElement vAlign = new XElement(W.vAlign, new XAttribute(W.val, "center"));
  3145. XElement vMerge = null;
  3146. if (element.Attribute("HtmlToWmlVMergeNoRestart") != null)
  3147. vMerge = new XElement(W.vMerge);
  3148. else
  3149. if (element.Attribute("HtmlToWmlVMergeRestart") != null)
  3150. vMerge = new XElement(W.vMerge,
  3151. new XAttribute(W.val, "restart"));
  3152. string vAlignValue = (string)element.Attribute(XhtmlNoNamespace.valign);
  3153. CssExpression verticalAlignmentProp = element.GetProp("vertical-align");
  3154. if (verticalAlignmentProp != null && verticalAlignmentProp.ToString() != "inherit")
  3155. vAlignValue = verticalAlignmentProp.ToString();
  3156. if (vAlignValue != null)
  3157. {
  3158. if (vAlignValue == "middle" || (vAlignValue != "top" && vAlignValue != "bottom"))
  3159. vAlignValue = "center";
  3160. vAlign = new XElement(W.vAlign, new XAttribute(W.val, vAlignValue));
  3161. }
  3162. return new XElement(W.tcPr,
  3163. tblW,
  3164. gridSpan,
  3165. vMerge,
  3166. tcBorders,
  3167. shd,
  3168. tcMar,
  3169. vAlign,
  3170. hideMark);
  3171. }
  3172. private static XElement GetCellHeaderProperties(XElement element)
  3173. {
  3174. //int? colspan = (int?)element.Attribute(Xhtml.colspan);
  3175. //XElement gridSpan = null;
  3176. //if (colspan != null)
  3177. // gridSpan = new XElement(W.gridSpan,
  3178. // new XAttribute(W.val, colspan));
  3179. XElement tblW = GetCellWidth(element);
  3180. XElement tcBorders = GetBlockContentBorders(element, W.tcBorders, false);
  3181. XElement shd = GetCellShading(element);
  3182. //XElement hideMark = new XElement(W.hideMark);
  3183. XElement hideMark = null;
  3184. XElement tcMar = GetCellMargins(element);
  3185. XElement vAlign = new XElement(W.vAlign, new XAttribute(W.val, "center"));
  3186. return new XElement(W.tcPr,
  3187. tblW,
  3188. tcBorders,
  3189. shd,
  3190. tcMar,
  3191. vAlign,
  3192. hideMark);
  3193. }
  3194. private static XElement GetCellShading(XElement element)
  3195. {
  3196. CssExpression backgroundColorProp = element.GetProp("background-color");
  3197. if (backgroundColorProp != null && (string)backgroundColorProp != "transparent")
  3198. {
  3199. XElement shd = new XElement(W.shd,
  3200. new XAttribute(W.val, "clear"),
  3201. new XAttribute(W.color, "auto"),
  3202. new XAttribute(W.fill, backgroundColorProp));
  3203. return shd;
  3204. }
  3205. return null;
  3206. }
  3207. private static XElement GetCellMargins(XElement element)
  3208. {
  3209. CssExpression topProp = element.GetProp("padding-top");
  3210. CssExpression leftProp = element.GetProp("padding-left");
  3211. CssExpression bottomProp = element.GetProp("padding-bottom");
  3212. CssExpression rightProp = element.GetProp("padding-right");
  3213. if ((long)topProp == 0 &&
  3214. (long)leftProp == 0 &&
  3215. (long)bottomProp == 0 &&
  3216. (long)rightProp == 0)
  3217. return null;
  3218. XElement top = null;
  3219. if (topProp != null)
  3220. top = new XElement(W.top,
  3221. new XAttribute(W._w, (long)(Twip)topProp),
  3222. new XAttribute(W.type, "dxa"));
  3223. XElement left = null;
  3224. if (leftProp != null)
  3225. left = new XElement(W.left,
  3226. new XAttribute(W._w, (long)(Twip)leftProp),
  3227. new XAttribute(W.type, "dxa"));
  3228. XElement bottom = null;
  3229. if (bottomProp != null)
  3230. bottom = new XElement(W.bottom,
  3231. new XAttribute(W._w, (long)(Twip)bottomProp),
  3232. new XAttribute(W.type, "dxa"));
  3233. XElement right = null;
  3234. if (rightProp != null)
  3235. right = new XElement(W.right,
  3236. new XAttribute(W._w, (long)(Twip)rightProp),
  3237. new XAttribute(W.type, "dxa"));
  3238. XElement tcMar = new XElement(W.tcMar,
  3239. top, left, bottom, right);
  3240. if (tcMar.Elements().Any())
  3241. return tcMar;
  3242. return null;
  3243. }
  3244. #if false
  3245. <w:tcMar>
  3246. <w:top w:w="720"
  3247. w:type="dxa" />
  3248. <w:left w:w="720"
  3249. w:type="dxa" />
  3250. <w:bottom w:w="720"
  3251. w:type="dxa" />
  3252. <w:right w:w="720"
  3253. w:type="dxa" />
  3254. </w:tcMar>
  3255. #endif
  3256. private static XElement GetTableCellSpacing(XElement element)
  3257. {
  3258. XElement table = element.AncestorsAndSelf(XhtmlNoNamespace.table).FirstOrDefault();
  3259. XElement tblCellSpacing = null;
  3260. if (table != null)
  3261. {
  3262. CssExpression borderCollapse = table.GetProp("border-collapse");
  3263. if (borderCollapse == null || (string)borderCollapse != "collapse")
  3264. {
  3265. // todo very incomplete
  3266. CssExpression borderSpacing = table.GetProp("border-spacing");
  3267. CssExpression marginTopProperty = element.GetProp("margin-top");
  3268. if (marginTopProperty == null)
  3269. marginTopProperty = new CssExpression { Terms = new List<CssTerm> { new CssTerm { Value = "0", Type = CssTermType.Number, Unit = CssUnit.PT } } };
  3270. CssExpression marginBottomProperty = element.GetProp("margin-bottom");
  3271. if (marginBottomProperty == null)
  3272. marginBottomProperty = new CssExpression { Terms = new List<CssTerm> { new CssTerm { Value = "0", Type = CssTermType.Number, Unit = CssUnit.PT } } };
  3273. Twip twips1 = (Twip)marginTopProperty;
  3274. Twip twips2 = (Twip)marginBottomProperty;
  3275. Twip minTwips = 15;
  3276. if (borderSpacing != null)
  3277. minTwips = (Twip)borderSpacing;
  3278. long twipToUse = Math.Max((long)twips1, (long)twips2);
  3279. twipToUse = Math.Max(twipToUse, (long)minTwips);
  3280. // have to divide twipToUse by 2 because border-spacing specifies the space between the border of once cell and its adjacent.
  3281. // tblCellSpacing specifies the distance between the border and the half way point between two cells.
  3282. long twipToUseOverTwo = (long)twipToUse / 2;
  3283. tblCellSpacing = new XElement(W.tblCellSpacing, new XAttribute(W._w, twipToUseOverTwo),
  3284. new XAttribute(W.type, "dxa"));
  3285. }
  3286. }
  3287. return tblCellSpacing;
  3288. }
  3289. private static XElement GetTableCellMargins(XElement element)
  3290. {
  3291. // todo very incomplete
  3292. XElement tblCellMar = XElement.Parse(
  3293. @"<w:tblCellMar xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  3294. <w:top w:w='15'
  3295. w:type='dxa'/>
  3296. <w:left w:w='15'
  3297. w:type='dxa'/>
  3298. <w:bottom w:w='15'
  3299. w:type='dxa'/>
  3300. <w:right w:w='15'
  3301. w:type='dxa'/>
  3302. </w:tblCellMar>");
  3303. tblCellMar.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
  3304. return tblCellMar;
  3305. }
  3306. private static XElement GetTableRowProperties(XElement element)
  3307. {
  3308. XElement trPr = null;
  3309. XElement table = element.AncestorsAndSelf(XhtmlNoNamespace.table).FirstOrDefault();
  3310. if (table != null)
  3311. {
  3312. CssExpression heightProperty = element.GetProp("height");
  3313. //long? maxCellHeight = element.Elements(Xhtml.td).Aggregate((long?)null,
  3314. // (XElement td, long? last) =>
  3315. // {
  3316. // Expression heightProp2 = td.GetProp("height");
  3317. // if (heightProp2 == null)
  3318. // return last;
  3319. // if (last == null)
  3320. // return (long)(Twip)heightProp2;
  3321. // return last + (long?)(long)(Twip)heightProp2;
  3322. // });
  3323. var cellHeights = element
  3324. .Elements(XhtmlNoNamespace.td)
  3325. .Select(td => td.GetProp("height"))
  3326. .Concat(new[] { heightProperty })
  3327. .Where(d => d != null)
  3328. .Select(e => (long)(Twip)e)
  3329. .ToList();
  3330. XElement trHeight = null;
  3331. if (cellHeights.Any())
  3332. {
  3333. long max = cellHeights.Max();
  3334. trHeight = new XElement(W.trHeight,
  3335. new XAttribute(W.val, max));
  3336. }
  3337. CssExpression borderCollapseProperty = table.GetProp("border-collapse");
  3338. XElement borderCollapse = null;
  3339. if (borderCollapseProperty != null && (string)borderCollapseProperty != "collapse")
  3340. borderCollapse = GetTableCellSpacing(element);
  3341. trPr = new XElement(W.trPr,
  3342. GetTableCellSpacing(element),
  3343. trHeight);
  3344. if (trPr.Elements().Any())
  3345. return trPr;
  3346. }
  3347. return trPr;
  3348. }
  3349. private static XAttribute GetXmlSpaceAttribute(string value)
  3350. {
  3351. if (value.StartsWith(" ") || value.EndsWith(" "))
  3352. return new XAttribute(XNamespace.Xml + "space", "preserve");
  3353. return null;
  3354. }
  3355. private static Dictionary<string, string> InstalledFonts = new Dictionary<string, string>
  3356. {
  3357. {"serif", "Times New Roman"},
  3358. {"sans-serif", "Arial"},
  3359. {"cursive", "Kunstler Script"},
  3360. {"fantasy", "Curlz MT"},
  3361. {"monospace", "Courier New"},
  3362. {"agency fb", "Agency FB"},
  3363. {"agencyfb", "Agency FB"},
  3364. {"aharoni", "Aharoni"},
  3365. {"algerian", "Algerian"},
  3366. {"andalus", "Andalus"},
  3367. {"angsana new", "Angsana New"},
  3368. {"angsananew", "Angsana New"},
  3369. {"angsanaupc", "AngsanaUPC"},
  3370. {"aparajita", "Aparajita"},
  3371. {"arabic typesetting", "Arabic Typesetting"},
  3372. {"arabictypesetting", "Arabic Typesetting"},
  3373. {"arial", "Arial"},
  3374. {"arial black", "Arial Black"},
  3375. {"arial narrow", "Arial Narrow"},
  3376. {"arial rounded mt bold", "Arial Rounded MT Bold"},
  3377. {"arial unicode ms", "Arial Unicode MS"},
  3378. {"arialblack", "Arial Black"},
  3379. {"arialnarrow", "Arial Narrow"},
  3380. {"arialroundedmtbold", "Arial Rounded MT Bold"},
  3381. {"arialunicodems", "Arial Unicode MS"},
  3382. {"baskerville old face", "Baskerville Old Face"},
  3383. {"baskervilleoldface", "Baskerville Old Face"},
  3384. {"batang", "Batang"},
  3385. {"batangche", "BatangChe"},
  3386. {"bauhaus 93", "Bauhaus 93"},
  3387. {"bauhaus93", "Bauhaus 93"},
  3388. {"bell mt", "Bell MT"},
  3389. {"bellmt", "Bell MT"},
  3390. {"berlin sans fb", "Berlin Sans FB"},
  3391. {"berlin sans fb demi", "Berlin Sans FB Demi"},
  3392. {"berlinsansfb", "Berlin Sans FB"},
  3393. {"berlinsansfbdemi", "Berlin Sans FB Demi"},
  3394. {"bernard mt condensed", "Bernard MT Condensed"},
  3395. {"bernardmtcondensed", "Bernard MT Condensed"},
  3396. {"blackadder itc", "Blackadder ITC"},
  3397. {"blackadderitc", "Blackadder ITC"},
  3398. {"bodoni mt", "Bodoni MT"},
  3399. {"bodoni mt black", "Bodoni MT Black"},
  3400. {"bodoni mt condensed", "Bodoni MT Condensed"},
  3401. {"bodoni mt poster compressed", "Bodoni MT Poster Compressed"},
  3402. {"bodonimt", "Bodoni MT"},
  3403. {"bodonimtblack", "Bodoni MT Black"},
  3404. {"bodonimtcondensed", "Bodoni MT Condensed"},
  3405. {"bodonimtpostercompressed", "Bodoni MT Poster Compressed"},
  3406. {"book antiqua", "Book Antiqua"},
  3407. {"bookantiqua", "Book Antiqua"},
  3408. {"bookman old style", "Bookman Old Style"},
  3409. {"bookmanoldstyle", "Bookman Old Style"},
  3410. {"bookshelf symbol 7", "Bookshelf Symbol 7"},
  3411. {"bookshelfsymbol7", "Bookshelf Symbol 7"},
  3412. {"bradley hand itc", "Bradley Hand ITC"},
  3413. {"bradleyhanditc", "Bradley Hand ITC"},
  3414. {"britannic bold", "Britannic Bold"},
  3415. {"britannicbold", "Britannic Bold"},
  3416. {"broadway", "Broadway"},
  3417. {"browallia new", "Browallia New"},
  3418. {"browallianew", "Browallia New"},
  3419. {"browalliaupc", "BrowalliaUPC"},
  3420. {"brush script mt", "Brush Script MT"},
  3421. {"brushscriptmt", "Brush Script MT"},
  3422. {"calibri", "Calibri"},
  3423. {"californian fb", "Californian FB"},
  3424. {"californianfb", "Californian FB"},
  3425. {"calisto mt", "Calisto MT"},
  3426. {"calistomt", "Calisto MT"},
  3427. {"cambria", "Cambria"},
  3428. {"cambria math", "Cambria Math"},
  3429. {"cambriamath", "Cambria Math"},
  3430. {"candara", "Candara"},
  3431. {"castellar", "Castellar"},
  3432. {"centaur", "Centaur"},
  3433. {"century", "Century"},
  3434. {"century gothic", "Century Gothic"},
  3435. {"century schoolbook", "Century Schoolbook"},
  3436. {"centurygothic", "Century Gothic"},
  3437. {"centuryschoolbook", "Century Schoolbook"},
  3438. {"chiller", "Chiller"},
  3439. {"colonna mt", "Colonna MT"},
  3440. {"colonnamt", "Colonna MT"},
  3441. {"comic sans ms", "Comic Sans MS"},
  3442. {"comicsansms", "Comic Sans MS"},
  3443. {"consolas", "Consolas"},
  3444. {"constantia", "Constantia"},
  3445. {"cooper black", "Cooper Black"},
  3446. {"cooperblack", "Cooper Black"},
  3447. {"copperplate gothic bold", "Copperplate Gothic Bold"},
  3448. {"copperplate gothic light", "Copperplate Gothic Light"},
  3449. {"copperplategothicbold", "Copperplate Gothic Bold"},
  3450. {"copperplategothiclight", "Copperplate Gothic Light"},
  3451. {"corbel", "Corbel"},
  3452. {"cordia new", "Cordia New"},
  3453. {"cordianew", "Cordia New"},
  3454. {"cordiaupc", "CordiaUPC"},
  3455. {"courier new", "Courier New"},
  3456. {"couriernew", "Courier New"},
  3457. {"curlz mt", "Curlz MT"},
  3458. {"curlzmt", "Curlz MT"},
  3459. {"daunpenh", "DaunPenh"},
  3460. {"david", "David"},
  3461. {"dfkai-sb", "DFKai-SB"},
  3462. {"dilleniaupc", "DilleniaUPC"},
  3463. {"dokchampa", "DokChampa"},
  3464. {"dotum", "Dotum"},
  3465. {"dotumche", "DotumChe"},
  3466. {"ebrima", "Ebrima"},
  3467. {"edwardian script itc", "Edwardian Script ITC"},
  3468. {"edwardianscriptitc", "Edwardian Script ITC"},
  3469. {"elephant", "Elephant"},
  3470. {"engravers mt", "Engravers MT"},
  3471. {"engraversmt", "Engravers MT"},
  3472. {"eras bold itc", "Eras Bold ITC"},
  3473. {"eras demi itc", "Eras Demi ITC"},
  3474. {"eras light itc", "Eras Light ITC"},
  3475. {"eras medium itc", "Eras Medium ITC"},
  3476. {"erasbolditc", "Eras Bold ITC"},
  3477. {"erasdemiitc", "Eras Demi ITC"},
  3478. {"eraslightitc", "Eras Light ITC"},
  3479. {"erasmediumitc", "Eras Medium ITC"},
  3480. {"estrangelo edessa", "Estrangelo Edessa"},
  3481. {"estrangeloedessa", "Estrangelo Edessa"},
  3482. {"eucrosiaupc", "EucrosiaUPC"},
  3483. {"euphemia", "Euphemia"},
  3484. {"fangsong", "FangSong"},
  3485. {"felix titling", "Felix Titling"},
  3486. {"felixtitling", "Felix Titling"},
  3487. {"footlight mt light", "Footlight MT Light"},
  3488. {"footlightmtlight", "Footlight MT Light"},
  3489. {"forte", "Forte"},
  3490. {"franklin gothic book", "Franklin Gothic Book"},
  3491. {"franklin gothic demi", "Franklin Gothic Demi"},
  3492. {"franklin gothic demi cond", "Franklin Gothic Demi Cond"},
  3493. {"franklin gothic heavy", "Franklin Gothic Heavy"},
  3494. {"franklin gothic medium", "Franklin Gothic Medium"},
  3495. {"franklin gothic medium cond", "Franklin Gothic Medium Cond"},
  3496. {"franklingothicbook", "Franklin Gothic Book"},
  3497. {"franklingothicdemi", "Franklin Gothic Demi"},
  3498. {"franklingothicdemicond", "Franklin Gothic Demi Cond"},
  3499. {"franklingothicheavy", "Franklin Gothic Heavy"},
  3500. {"franklingothicmedium", "Franklin Gothic Medium"},
  3501. {"franklingothicmediumcond", "Franklin Gothic Medium Cond"},
  3502. {"frankruehl", "FrankRuehl"},
  3503. {"freesiaupc", "FreesiaUPC"},
  3504. {"freestyle script", "Freestyle Script"},
  3505. {"freestylescript", "Freestyle Script"},
  3506. {"french script mt", "French Script MT"},
  3507. {"frenchscriptmt", "French Script MT"},
  3508. {"gabriola", "Gabriola"},
  3509. {"garamond", "Garamond"},
  3510. {"gautami", "Gautami"},
  3511. {"georgia", "Georgia"},
  3512. {"gigi", "Gigi"},
  3513. {"gill sans mt", "Gill Sans MT"},
  3514. {"gill sans mt condensed", "Gill Sans MT Condensed"},
  3515. {"gill sans mt ext condensed bold", "Gill Sans MT Ext Condensed Bold"},
  3516. {"gill sans ultra bold", "Gill Sans Ultra Bold"},
  3517. {"gill sans ultra bold condensed", "Gill Sans Ultra Bold Condensed"},
  3518. {"gillsansmt", "Gill Sans MT"},
  3519. {"gillsansmtcondensed", "Gill Sans MT Condensed"},
  3520. {"gillsansmtextcondensedbold", "Gill Sans MT Ext Condensed Bold"},
  3521. {"gillsansultrabold", "Gill Sans Ultra Bold"},
  3522. {"gillsansultraboldcondensed", "Gill Sans Ultra Bold Condensed"},
  3523. {"gisha", "Gisha"},
  3524. {"gloucester mt extra condensed", "Gloucester MT Extra Condensed"},
  3525. {"gloucestermtextracondensed", "Gloucester MT Extra Condensed"},
  3526. {"goudy old style", "Goudy Old Style"},
  3527. {"goudy stout", "Goudy Stout"},
  3528. {"goudyoldstyle", "Goudy Old Style"},
  3529. {"goudystout", "Goudy Stout"},
  3530. {"gulim", "Gulim"},
  3531. {"gulimche", "GulimChe"},
  3532. {"gungsuh", "Gungsuh"},
  3533. {"gungsuhche", "GungsuhChe"},
  3534. {"haettenschweiler", "Haettenschweiler"},
  3535. {"harlow solid italic", "Harlow Solid Italic"},
  3536. {"harlowsoliditalic", "Harlow Solid Italic"},
  3537. {"harrington", "Harrington"},
  3538. {"high tower text", "High Tower Text"},
  3539. {"hightowertext", "High Tower Text"},
  3540. {"impact", "Impact"},
  3541. {"imprint mt shadow", "Imprint MT Shadow"},
  3542. {"imprintmtshadow", "Imprint MT Shadow"},
  3543. {"informal roman", "Informal Roman"},
  3544. {"informalroman", "Informal Roman"},
  3545. {"irisupc", "IrisUPC"},
  3546. {"iskoola pota", "Iskoola Pota"},
  3547. {"iskoolapota", "Iskoola Pota"},
  3548. {"jasmineupc", "JasmineUPC"},
  3549. {"jokerman", "Jokerman"},
  3550. {"juice itc", "Juice ITC"},
  3551. {"juiceitc", "Juice ITC"},
  3552. {"kaiti", "KaiTi"},
  3553. {"kalinga", "Kalinga"},
  3554. {"kartika", "Kartika"},
  3555. {"khmer ui", "Khmer UI"},
  3556. {"khmerui", "Khmer UI"},
  3557. {"kodchiangupc", "KodchiangUPC"},
  3558. {"kokila", "Kokila"},
  3559. {"kristen itc", "Kristen ITC"},
  3560. {"kristenitc", "Kristen ITC"},
  3561. {"kunstler script", "Kunstler Script"},
  3562. {"kunstlerscript", "Kunstler Script"},
  3563. {"lao ui", "Lao UI"},
  3564. {"laoui", "Lao UI"},
  3565. {"latha", "Latha"},
  3566. {"leelawadee", "Leelawadee"},
  3567. {"levenim mt", "Levenim MT"},
  3568. {"levenimmt", "Levenim MT"},
  3569. {"lilyupc", "LilyUPC"},
  3570. {"lucida bright", "Lucida Bright"},
  3571. {"lucida calligraphy", "Lucida Calligraphy"},
  3572. {"lucida console", "Lucida Console"},
  3573. {"lucida fax", "Lucida Fax"},
  3574. {"lucida handwriting", "Lucida Handwriting"},
  3575. {"lucida sans", "Lucida Sans"},
  3576. {"lucida sans typewriter", "Lucida Sans Typewriter"},
  3577. {"lucida sans unicode", "Lucida Sans Unicode"},
  3578. {"lucidabright", "Lucida Bright"},
  3579. {"lucidacalligraphy", "Lucida Calligraphy"},
  3580. {"lucidaconsole", "Lucida Console"},
  3581. {"lucidafax", "Lucida Fax"},
  3582. {"lucidahandwriting", "Lucida Handwriting"},
  3583. {"lucidasans", "Lucida Sans"},
  3584. {"lucidasanstypewriter", "Lucida Sans Typewriter"},
  3585. {"lucidasansunicode", "Lucida Sans Unicode"},
  3586. {"magneto", "Magneto"},
  3587. {"maiandra gd", "Maiandra GD"},
  3588. {"maiandragd", "Maiandra GD"},
  3589. {"malgun gothic", "Malgun Gothic"},
  3590. {"malgungothic", "Malgun Gothic"},
  3591. {"mangal", "Mangal"},
  3592. {"marlett", "Marlett"},
  3593. {"matura mt script capitals", "Matura MT Script Capitals"},
  3594. {"maturamtscriptcapitals", "Matura MT Script Capitals"},
  3595. {"meiryo", "Meiryo"},
  3596. {"meiryo ui", "Meiryo UI"},
  3597. {"meiryoui", "Meiryo UI"},
  3598. {"microsoft himalaya", "Microsoft Himalaya"},
  3599. {"microsoft jhenghei", "Microsoft JhengHei"},
  3600. {"microsoft new tai lue", "Microsoft New Tai Lue"},
  3601. {"microsoft phagspa", "Microsoft PhagsPa"},
  3602. {"microsoft sans serif", "Microsoft Sans Serif"},
  3603. {"microsoft tai le", "Microsoft Tai Le"},
  3604. {"microsoft uighur", "Microsoft Uighur"},
  3605. {"microsoft yahei", "Microsoft YaHei"},
  3606. {"microsoft yi baiti", "Microsoft Yi Baiti"},
  3607. {"microsofthimalaya", "Microsoft Himalaya"},
  3608. {"microsoftjhenghei", "Microsoft JhengHei"},
  3609. {"microsoftnewtailue", "Microsoft New Tai Lue"},
  3610. {"microsoftphagspa", "Microsoft PhagsPa"},
  3611. {"microsoftsansserif", "Microsoft Sans Serif"},
  3612. {"microsofttaile", "Microsoft Tai Le"},
  3613. {"microsoftuighur", "Microsoft Uighur"},
  3614. {"microsoftyahei", "Microsoft YaHei"},
  3615. {"microsoftyibaiti", "Microsoft Yi Baiti"},
  3616. {"mingliu", "MingLiU"},
  3617. {"mingliu_hkscs", "MingLiU_HKSCS"},
  3618. {"mingliu_hkscs-extb", "MingLiU_HKSCS-ExtB"},
  3619. {"mingliu-extb", "MingLiU-ExtB"},
  3620. {"miriam", "Miriam"},
  3621. {"miriam fixed", "Miriam Fixed"},
  3622. {"miriamfixed", "Miriam Fixed"},
  3623. {"mistral", "Mistral"},
  3624. {"modern no. 20", "Modern No. 20"},
  3625. {"modernno.20", "Modern No. 20"},
  3626. {"mongolian baiti", "Mongolian Baiti"},
  3627. {"mongolianbaiti", "Mongolian Baiti"},
  3628. {"monotype corsiva", "Monotype Corsiva"},
  3629. {"monotypecorsiva", "Monotype Corsiva"},
  3630. {"moolboran", "MoolBoran"},
  3631. {"ms gothic", "MS Gothic"},
  3632. {"ms mincho", "MS Mincho"},
  3633. {"ms pgothic", "MS PGothic"},
  3634. {"ms pmincho", "MS PMincho"},
  3635. {"ms reference sans serif", "MS Reference Sans Serif"},
  3636. {"ms reference specialty", "MS Reference Specialty"},
  3637. {"ms ui gothic", "MS UI Gothic"},
  3638. {"msgothic", "MS Gothic"},
  3639. {"msmincho", "MS Mincho"},
  3640. {"mspgothic", "MS PGothic"},
  3641. {"mspmincho", "MS PMincho"},
  3642. {"msreferencesansserif", "MS Reference Sans Serif"},
  3643. {"msreferencespecialty", "MS Reference Specialty"},
  3644. {"msuigothic", "MS UI Gothic"},
  3645. {"mt extra", "MT Extra"},
  3646. {"mtextra", "MT Extra"},
  3647. {"mv boli", "MV Boli"},
  3648. {"mvboli", "MV Boli"},
  3649. {"narkisim", "Narkisim"},
  3650. {"niagara engraved", "Niagara Engraved"},
  3651. {"niagara solid", "Niagara Solid"},
  3652. {"niagaraengraved", "Niagara Engraved"},
  3653. {"niagarasolid", "Niagara Solid"},
  3654. {"nsimsun", "NSimSun"},
  3655. {"nyala", "Nyala"},
  3656. {"ocr a extended", "OCR A Extended"},
  3657. {"ocraextended", "OCR A Extended"},
  3658. {"old english text mt", "Old English Text MT"},
  3659. {"oldenglishtextmt", "Old English Text MT"},
  3660. {"onyx", "Onyx"},
  3661. {"palace script mt", "Palace Script MT"},
  3662. {"palacescriptmt", "Palace Script MT"},
  3663. {"palatino linotype", "Palatino Linotype"},
  3664. {"palatinolinotype", "Palatino Linotype"},
  3665. {"papyrus", "Papyrus"},
  3666. {"parchment", "Parchment"},
  3667. {"perpetua", "Perpetua"},
  3668. {"perpetua titling mt", "Perpetua Titling MT"},
  3669. {"perpetuatitlingmt", "Perpetua Titling MT"},
  3670. {"plantagenet cherokee", "Plantagenet Cherokee"},
  3671. {"plantagenetcherokee", "Plantagenet Cherokee"},
  3672. {"playbill", "Playbill"},
  3673. {"pmingliu", "PMingLiU"},
  3674. {"pmingliu-extb", "PMingLiU-ExtB"},
  3675. {"poor richard", "Poor Richard"},
  3676. {"poorrichard", "Poor Richard"},
  3677. {"pristina", "Pristina"},
  3678. {"raavi", "Raavi"},
  3679. {"rage italic", "Rage Italic"},
  3680. {"rageitalic", "Rage Italic"},
  3681. {"ravie", "Ravie"},
  3682. {"rockwell", "Rockwell"},
  3683. {"rockwell condensed", "Rockwell Condensed"},
  3684. {"rockwell extra bold", "Rockwell Extra Bold"},
  3685. {"rockwellcondensed", "Rockwell Condensed"},
  3686. {"rockwellextrabold", "Rockwell Extra Bold"},
  3687. {"rod", "Rod"},
  3688. {"sakkal majalla", "Sakkal Majalla"},
  3689. {"sakkalmajalla", "Sakkal Majalla"},
  3690. {"script mt bold", "Script MT Bold"},
  3691. {"scriptmtbold", "Script MT Bold"},
  3692. {"segoe print", "Segoe Print"},
  3693. {"segoe script", "Segoe Script"},
  3694. {"segoe ui", "Segoe UI"},
  3695. {"segoe ui light", "Segoe UI Light"},
  3696. {"segoe ui semibold", "Segoe UI Semibold"},
  3697. {"segoe ui symbol", "Segoe UI Symbol"},
  3698. {"segoeprint", "Segoe Print"},
  3699. {"segoescript", "Segoe Script"},
  3700. {"segoeui", "Segoe UI"},
  3701. {"segoeuilight", "Segoe UI Light"},
  3702. {"segoeuisemibold", "Segoe UI Semibold"},
  3703. {"segoeuisymbol", "Segoe UI Symbol"},
  3704. {"shonar bangla", "Shonar Bangla"},
  3705. {"shonarbangla", "Shonar Bangla"},
  3706. {"showcard gothic", "Showcard Gothic"},
  3707. {"showcardgothic", "Showcard Gothic"},
  3708. {"shruti", "Shruti"},
  3709. {"simhei", "SimHei"},
  3710. {"simplified arabic", "Simplified Arabic"},
  3711. {"simplified arabic fixed", "Simplified Arabic Fixed"},
  3712. {"simplifiedarabic", "Simplified Arabic"},
  3713. {"simplifiedarabicfixed", "Simplified Arabic Fixed"},
  3714. {"simsun", "SimSun"},
  3715. {"simsun-extb", "SimSun-ExtB"},
  3716. {"snap itc", "Snap ITC"},
  3717. {"snapitc", "Snap ITC"},
  3718. {"stencil", "Stencil"},
  3719. {"swgamekeys mt", "SWGamekeys MT"},
  3720. {"swgamekeysmt", "SWGamekeys MT"},
  3721. {"swmacro", "SWMacro"},
  3722. {"sylfaen", "Sylfaen"},
  3723. {"symbol", "Symbol"},
  3724. {"tahoma", "Tahoma"},
  3725. {"tempus sans itc", "Tempus Sans ITC"},
  3726. {"tempussansitc", "Tempus Sans ITC"},
  3727. {"times new roman", "Times New Roman"},
  3728. {"timesnewroman", "Times New Roman"},
  3729. {"traditional arabic", "Traditional Arabic"},
  3730. {"traditionalarabic", "Traditional Arabic"},
  3731. {"trebuchet ms", "Trebuchet MS"},
  3732. {"trebuchetms", "Trebuchet MS"},
  3733. {"tunga", "Tunga"},
  3734. {"tw cen mt", "Tw Cen MT"},
  3735. {"tw cen mt condensed", "Tw Cen MT Condensed"},
  3736. {"tw cen mt condensed extra bold", "Tw Cen MT Condensed Extra Bold"},
  3737. {"twcenmt", "Tw Cen MT"},
  3738. {"twcenmtcondensed", "Tw Cen MT Condensed"},
  3739. {"twcenmtcondensedextrabold", "Tw Cen MT Condensed Extra Bold"},
  3740. {"utsaah", "Utsaah"},
  3741. {"vani", "Vani"},
  3742. {"verdana", "Verdana"},
  3743. {"vijaya", "Vijaya"},
  3744. {"viner hand itc", "Viner Hand ITC"},
  3745. {"vinerhanditc", "Viner Hand ITC"},
  3746. {"vivaldi", "Vivaldi"},
  3747. {"vladimir script", "Vladimir Script"},
  3748. {"vladimirscript", "Vladimir Script"},
  3749. {"vrinda", "Vrinda"},
  3750. {"webdings", "Webdings"},
  3751. {"wide latin", "Wide Latin"},
  3752. {"widelatin", "Wide Latin"},
  3753. {"wingdings", "Wingdings"},
  3754. {"wingdings 2", "Wingdings 2"},
  3755. {"wingdings 3", "Wingdings 3"},
  3756. {"wingdings2", "Wingdings 2"},
  3757. {"wingdings3", "Wingdings 3"},
  3758. };
  3759. private static TPoint? GetUsedSizeFromFontSizeProperty(CssExpression fontSize)
  3760. {
  3761. if (fontSize == null)
  3762. return null;
  3763. if (fontSize.Terms.Count() == 1)
  3764. {
  3765. CssTerm term = fontSize.Terms.First();
  3766. double size = 0;
  3767. if (term.Unit == CssUnit.PT)
  3768. {
  3769. if (double.TryParse(term.Value, out size))
  3770. return new TPoint(size);
  3771. return null;
  3772. }
  3773. return null;
  3774. }
  3775. return null;
  3776. }
  3777. private static string GetUsedFontFromFontFamilyProperty(CssExpression fontFamily)
  3778. {
  3779. if (fontFamily == null)
  3780. return null;
  3781. string fullFontFamily = fontFamily.Terms.Select(t => t + " ").StringConcatenate().Trim();
  3782. string lcfont = fullFontFamily.ToLower();
  3783. if (InstalledFonts.ContainsKey(lcfont))
  3784. return InstalledFonts[lcfont];
  3785. return null;
  3786. }
  3787. private static XElement GetBackgroundProperty(XElement element)
  3788. {
  3789. CssExpression color = element.GetProp("background-color");
  3790. // todo this really should test against default background color
  3791. if (color.ToString() != "transparent")
  3792. {
  3793. string hexString = color.ToString();
  3794. XElement shd = new XElement(W.shd,
  3795. new XAttribute(W.val, "clear"),
  3796. new XAttribute(W.color, "auto"),
  3797. new XAttribute(W.fill, hexString));
  3798. return shd;
  3799. }
  3800. return null;
  3801. }
  3802. }
  3803. public class PictureId
  3804. {
  3805. public int Id;
  3806. }
  3807. class HtmlToWmlFontUpdater
  3808. {
  3809. public static void UpdateFontsPart(WordprocessingDocument wDoc, XElement html, HtmlToWmlConverterSettings settings)
  3810. {
  3811. XDocument fontXDoc = wDoc.MainDocumentPart.FontTablePart.GetXDocument();
  3812. PtUtils.AddElementIfMissing(fontXDoc,
  3813. fontXDoc
  3814. .Root
  3815. .Elements(W.style)
  3816. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading1")
  3817. .FirstOrDefault(),
  3818. @"<w:font w:name='Verdana' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  3819. <w:panose1 w:val='020B0604030504040204'/>
  3820. <w:charset w:val='00'/>
  3821. <w:family w:val='swiss'/>
  3822. <w:pitch w:val='variable'/>
  3823. <w:sig w:usb0='A10006FF'
  3824. w:usb1='4000205B'
  3825. w:usb2='00000010'
  3826. w:usb3='00000000'
  3827. w:csb0='0000019F'
  3828. w:csb1='00000000'/>
  3829. </w:font>");
  3830. wDoc.MainDocumentPart.FontTablePart.PutXDocument();
  3831. }
  3832. }
  3833. class NumberingUpdater
  3834. {
  3835. public static void InitializeNumberingPart(WordprocessingDocument wDoc)
  3836. {
  3837. NumberingDefinitionsPart numberingPart = wDoc.MainDocumentPart.NumberingDefinitionsPart;
  3838. if (numberingPart == null)
  3839. {
  3840. wDoc.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>();
  3841. XDocument npXDoc = new XDocument(
  3842. new XElement(W.numbering,
  3843. new XAttribute(XNamespace.Xmlns + "w", W.w)));
  3844. wDoc.MainDocumentPart.NumberingDefinitionsPart.PutXDocument(npXDoc);
  3845. }
  3846. }
  3847. public static void GetNextNumId(WordprocessingDocument wDoc, out int nextNumId)
  3848. {
  3849. InitializeNumberingPart(wDoc);
  3850. NumberingDefinitionsPart numberingPart = wDoc.MainDocumentPart.NumberingDefinitionsPart;
  3851. XDocument numberingXDoc = numberingPart.GetXDocument();
  3852. nextNumId = numberingXDoc.Root.Elements(W.num).Attributes(W.numId).Select(ni => (int)ni).Concat(new[] { 1 }).Max();
  3853. }
  3854. // decimal, lowerLetter
  3855. private static string OrderedListAbstractXml =
  3856. @"<w:abstractNum w:abstractNumId='{0}' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  3857. <w:multiLevelType w:val='multilevel'/>
  3858. <w:tmpl w:val='7D26959A'/>
  3859. <w:lvl w:ilvl='0'>
  3860. <w:start w:val='1'/>
  3861. <w:numFmt w:val='{1}'/>
  3862. <w:lvlText w:val='%1.'/>
  3863. <w:lvlJc w:val='{2}'/>
  3864. <w:pPr>
  3865. <w:tabs>
  3866. <w:tab w:val='num'
  3867. w:pos='720'/>
  3868. </w:tabs>
  3869. <w:ind w:left='720'
  3870. w:hanging='360'/>
  3871. </w:pPr>
  3872. </w:lvl>
  3873. <w:lvl w:ilvl='1'
  3874. w:tentative='1'>
  3875. <w:start w:val='1'/>
  3876. <w:numFmt w:val='{3}'/>
  3877. <w:lvlText w:val='%2.'/>
  3878. <w:lvlJc w:val='{4}'/>
  3879. <w:pPr>
  3880. <w:tabs>
  3881. <w:tab w:val='num'
  3882. w:pos='1440'/>
  3883. </w:tabs>
  3884. <w:ind w:left='1440'
  3885. w:hanging='360'/>
  3886. </w:pPr>
  3887. </w:lvl>
  3888. <w:lvl w:ilvl='2'
  3889. w:tentative='1'>
  3890. <w:start w:val='1'/>
  3891. <w:numFmt w:val='{5}'/>
  3892. <w:lvlText w:val='%3.'/>
  3893. <w:lvlJc w:val='{6}'/>
  3894. <w:pPr>
  3895. <w:tabs>
  3896. <w:tab w:val='num'
  3897. w:pos='2160'/>
  3898. </w:tabs>
  3899. <w:ind w:left='2160'
  3900. w:hanging='360'/>
  3901. </w:pPr>
  3902. </w:lvl>
  3903. <w:lvl w:ilvl='3'
  3904. w:tentative='1'>
  3905. <w:start w:val='1'/>
  3906. <w:numFmt w:val='{7}'/>
  3907. <w:lvlText w:val='%4.'/>
  3908. <w:lvlJc w:val='{8}'/>
  3909. <w:pPr>
  3910. <w:tabs>
  3911. <w:tab w:val='num'
  3912. w:pos='2880'/>
  3913. </w:tabs>
  3914. <w:ind w:left='2880'
  3915. w:hanging='360'/>
  3916. </w:pPr>
  3917. </w:lvl>
  3918. <w:lvl w:ilvl='4'
  3919. w:tentative='1'>
  3920. <w:start w:val='1'/>
  3921. <w:numFmt w:val='{9}'/>
  3922. <w:lvlText w:val='%5.'/>
  3923. <w:lvlJc w:val='{10}'/>
  3924. <w:pPr>
  3925. <w:tabs>
  3926. <w:tab w:val='num'
  3927. w:pos='3600'/>
  3928. </w:tabs>
  3929. <w:ind w:left='3600'
  3930. w:hanging='360'/>
  3931. </w:pPr>
  3932. </w:lvl>
  3933. <w:lvl w:ilvl='5'
  3934. w:tentative='1'>
  3935. <w:start w:val='1'/>
  3936. <w:numFmt w:val='{11}'/>
  3937. <w:lvlText w:val='%6.'/>
  3938. <w:lvlJc w:val='{12}'/>
  3939. <w:pPr>
  3940. <w:tabs>
  3941. <w:tab w:val='num'
  3942. w:pos='4320'/>
  3943. </w:tabs>
  3944. <w:ind w:left='4320'
  3945. w:hanging='360'/>
  3946. </w:pPr>
  3947. </w:lvl>
  3948. <w:lvl w:ilvl='6'
  3949. w:tentative='1'>
  3950. <w:start w:val='1'/>
  3951. <w:numFmt w:val='{13}'/>
  3952. <w:lvlText w:val='%7.'/>
  3953. <w:lvlJc w:val='{14}'/>
  3954. <w:pPr>
  3955. <w:tabs>
  3956. <w:tab w:val='num'
  3957. w:pos='5040'/>
  3958. </w:tabs>
  3959. <w:ind w:left='5040'
  3960. w:hanging='360'/>
  3961. </w:pPr>
  3962. </w:lvl>
  3963. <w:lvl w:ilvl='7'
  3964. w:tentative='1'>
  3965. <w:start w:val='1'/>
  3966. <w:numFmt w:val='{15}'/>
  3967. <w:lvlText w:val='%8.'/>
  3968. <w:lvlJc w:val='{16}'/>
  3969. <w:pPr>
  3970. <w:tabs>
  3971. <w:tab w:val='num'
  3972. w:pos='5760'/>
  3973. </w:tabs>
  3974. <w:ind w:left='5760'
  3975. w:hanging='360'/>
  3976. </w:pPr>
  3977. </w:lvl>
  3978. <w:lvl w:ilvl='8'
  3979. w:tentative='1'>
  3980. <w:start w:val='1'/>
  3981. <w:numFmt w:val='{17}'/>
  3982. <w:lvlText w:val='%9.'/>
  3983. <w:lvlJc w:val='{18}'/>
  3984. <w:pPr>
  3985. <w:tabs>
  3986. <w:tab w:val='num'
  3987. w:pos='6480'/>
  3988. </w:tabs>
  3989. <w:ind w:left='6480'
  3990. w:hanging='360'/>
  3991. </w:pPr>
  3992. </w:lvl>
  3993. </w:abstractNum>";
  3994. private static string BulletAbstractXml =
  3995. @"<w:abstractNum w:abstractNumId='{0}' xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  3996. <w:multiLevelType w:val='multilevel' />
  3997. <w:tmpl w:val='02BEA0DA' />
  3998. <w:lvl w:ilvl='0'>
  3999. <w:start w:val='1' />
  4000. <w:numFmt w:val='bullet' />
  4001. <w:lvlText w:val='' />
  4002. <w:lvlJc w:val='left' />
  4003. <w:pPr>
  4004. <w:tabs>
  4005. <w:tab w:val='num' w:pos='720' />
  4006. </w:tabs>
  4007. <w:ind w:left='720' w:hanging='360' />
  4008. </w:pPr>
  4009. <w:rPr>
  4010. <w:rFonts w:ascii='Symbol' w:hAnsi='Symbol' w:hint='default' />
  4011. <w:sz w:val='20' />
  4012. </w:rPr>
  4013. </w:lvl>
  4014. <w:lvl w:ilvl='1'>
  4015. <w:start w:val='1' />
  4016. <w:numFmt w:val='bullet' />
  4017. <w:lvlText w:val='o' />
  4018. <w:lvlJc w:val='left' />
  4019. <w:pPr>
  4020. <w:tabs>
  4021. <w:tab w:val='num' w:pos='1440' />
  4022. </w:tabs>
  4023. <w:ind w:left='1440' w:hanging='360' />
  4024. </w:pPr>
  4025. <w:rPr>
  4026. <w:rFonts w:ascii='Courier New' w:hAnsi='Courier New' w:hint='default' />
  4027. <w:sz w:val='20' />
  4028. </w:rPr>
  4029. </w:lvl>
  4030. <w:lvl w:ilvl='2' w:tentative='1'>
  4031. <w:start w:val='1' />
  4032. <w:numFmt w:val='bullet' />
  4033. <w:lvlText w:val='' />
  4034. <w:lvlJc w:val='left' />
  4035. <w:pPr>
  4036. <w:tabs>
  4037. <w:tab w:val='num' w:pos='2160' />
  4038. </w:tabs>
  4039. <w:ind w:left='2160' w:hanging='360' />
  4040. </w:pPr>
  4041. <w:rPr>
  4042. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4043. <w:sz w:val='20' />
  4044. </w:rPr>
  4045. </w:lvl>
  4046. <w:lvl w:ilvl='3' w:tentative='1'>
  4047. <w:start w:val='1' />
  4048. <w:numFmt w:val='bullet' />
  4049. <w:lvlText w:val='' />
  4050. <w:lvlJc w:val='left' />
  4051. <w:pPr>
  4052. <w:tabs>
  4053. <w:tab w:val='num' w:pos='2880' />
  4054. </w:tabs>
  4055. <w:ind w:left='2880' w:hanging='360' />
  4056. </w:pPr>
  4057. <w:rPr>
  4058. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4059. <w:sz w:val='20' />
  4060. </w:rPr>
  4061. </w:lvl>
  4062. <w:lvl w:ilvl='4' w:tentative='1'>
  4063. <w:start w:val='1' />
  4064. <w:numFmt w:val='bullet' />
  4065. <w:lvlText w:val='' />
  4066. <w:lvlJc w:val='left' />
  4067. <w:pPr>
  4068. <w:tabs>
  4069. <w:tab w:val='num' w:pos='3600' />
  4070. </w:tabs>
  4071. <w:ind w:left='3600' w:hanging='360' />
  4072. </w:pPr>
  4073. <w:rPr>
  4074. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4075. <w:sz w:val='20' />
  4076. </w:rPr>
  4077. </w:lvl>
  4078. <w:lvl w:ilvl='5' w:tentative='1'>
  4079. <w:start w:val='1' />
  4080. <w:numFmt w:val='bullet' />
  4081. <w:lvlText w:val='' />
  4082. <w:lvlJc w:val='left' />
  4083. <w:pPr>
  4084. <w:tabs>
  4085. <w:tab w:val='num' w:pos='4320' />
  4086. </w:tabs>
  4087. <w:ind w:left='4320' w:hanging='360' />
  4088. </w:pPr>
  4089. <w:rPr>
  4090. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4091. <w:sz w:val='20' />
  4092. </w:rPr>
  4093. </w:lvl>
  4094. <w:lvl w:ilvl='6' w:tentative='1'>
  4095. <w:start w:val='1' />
  4096. <w:numFmt w:val='bullet' />
  4097. <w:lvlText w:val='' />
  4098. <w:lvlJc w:val='left' />
  4099. <w:pPr>
  4100. <w:tabs>
  4101. <w:tab w:val='num' w:pos='5040' />
  4102. </w:tabs>
  4103. <w:ind w:left='5040' w:hanging='360' />
  4104. </w:pPr>
  4105. <w:rPr>
  4106. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4107. <w:sz w:val='20' />
  4108. </w:rPr>
  4109. </w:lvl>
  4110. <w:lvl w:ilvl='7' w:tentative='1'>
  4111. <w:start w:val='1' />
  4112. <w:numFmt w:val='bullet' />
  4113. <w:lvlText w:val='' />
  4114. <w:lvlJc w:val='left' />
  4115. <w:pPr>
  4116. <w:tabs>
  4117. <w:tab w:val='num' w:pos='5760' />
  4118. </w:tabs>
  4119. <w:ind w:left='5760' w:hanging='360' />
  4120. </w:pPr>
  4121. <w:rPr>
  4122. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4123. <w:sz w:val='20' />
  4124. </w:rPr>
  4125. </w:lvl>
  4126. <w:lvl w:ilvl='8' w:tentative='1'>
  4127. <w:start w:val='1' />
  4128. <w:numFmt w:val='bullet' />
  4129. <w:lvlText w:val='' />
  4130. <w:lvlJc w:val='left' />
  4131. <w:pPr>
  4132. <w:tabs>
  4133. <w:tab w:val='num' w:pos='6480' />
  4134. </w:tabs>
  4135. <w:ind w:left='6480' w:hanging='360' />
  4136. </w:pPr>
  4137. <w:rPr>
  4138. <w:rFonts w:ascii='Wingdings' w:hAnsi='Wingdings' w:hint='default' />
  4139. <w:sz w:val='20' />
  4140. </w:rPr>
  4141. </w:lvl>
  4142. </w:abstractNum>";
  4143. public static void UpdateNumberingPart(WordprocessingDocument wDoc, XElement html, HtmlToWmlConverterSettings settings)
  4144. {
  4145. InitializeNumberingPart(wDoc);
  4146. NumberingDefinitionsPart numberingPart = wDoc.MainDocumentPart.NumberingDefinitionsPart;
  4147. XDocument numberingXDoc = numberingPart.GetXDocument();
  4148. int nextAbstractId, nextNumId;
  4149. nextNumId = numberingXDoc.Root.Elements(W.num).Attributes(W.numId).Select(ni => (int)ni).Concat(new[] { 1 }).Max();
  4150. nextAbstractId = numberingXDoc.Root.Elements(W.abstractNum).Attributes(W.abstractNumId).Select(ani => (int)ani).Concat(new[] { 0 }).Max();
  4151. var numberingElements = html.DescendantsAndSelf().Where(d => d.Name == XhtmlNoNamespace.ol || d.Name == XhtmlNoNamespace.ul).ToList();
  4152. Dictionary<int, int> numToAbstractNum = new Dictionary<int, int>();
  4153. // add abstract numbering elements
  4154. int currentNumId = nextNumId;
  4155. int currentAbstractId = nextAbstractId;
  4156. foreach (var list in numberingElements)
  4157. {
  4158. HtmlToWmlConverterCore.NumberedItemAnnotation nia = list.Annotation<HtmlToWmlConverterCore.NumberedItemAnnotation>();
  4159. if (!numToAbstractNum.ContainsKey(nia.numId))
  4160. {
  4161. numToAbstractNum.Add(nia.numId, currentAbstractId);
  4162. if (list.Name == XhtmlNoNamespace.ul)
  4163. {
  4164. XElement bulletAbstract = XElement.Parse(String.Format(BulletAbstractXml, currentAbstractId++));
  4165. numberingXDoc.Root.Add(bulletAbstract);
  4166. }
  4167. if (list.Name == XhtmlNoNamespace.ol)
  4168. {
  4169. string[] numFmt = new string[9];
  4170. string[] just = new string[9];
  4171. for (int i = 0; i < numFmt.Length; ++i)
  4172. {
  4173. numFmt[i] = "decimal";
  4174. just[i] = "left";
  4175. XElement itemAtLevel = numberingElements
  4176. .FirstOrDefault(nf =>
  4177. {
  4178. HtmlToWmlConverterCore.NumberedItemAnnotation n = nf.Annotation<HtmlToWmlConverterCore.NumberedItemAnnotation>();
  4179. if (n != null && n.numId == nia.numId && n.ilvl == i)
  4180. return true;
  4181. return false;
  4182. });
  4183. if (itemAtLevel != null)
  4184. {
  4185. HtmlToWmlConverterCore.NumberedItemAnnotation thisLevelNia = itemAtLevel.Annotation<HtmlToWmlConverterCore.NumberedItemAnnotation>();
  4186. string thisLevelNumFmt = thisLevelNia.listStyleType;
  4187. if (thisLevelNumFmt == "lower-alpha" || thisLevelNumFmt == "lower-latin")
  4188. {
  4189. numFmt[i] = "lowerLetter";
  4190. //just[i] = "left";
  4191. }
  4192. if (thisLevelNumFmt == "upper-alpha" || thisLevelNumFmt == "upper-latin")
  4193. {
  4194. numFmt[i] = "upperLetter";
  4195. //just[i] = "left";
  4196. }
  4197. if (thisLevelNumFmt == "decimal-leading-zero")
  4198. {
  4199. numFmt[i] = "decimalZero";
  4200. //just[i] = "left";
  4201. }
  4202. if (thisLevelNumFmt == "lower-roman")
  4203. {
  4204. numFmt[i] = "lowerRoman";
  4205. just[i] = "right";
  4206. }
  4207. if (thisLevelNumFmt == "upper-roman")
  4208. {
  4209. numFmt[i] = "upperRoman";
  4210. just[i] = "right";
  4211. }
  4212. }
  4213. }
  4214. XElement simpleNumAbstract = XElement.Parse(String.Format(OrderedListAbstractXml, currentAbstractId++,
  4215. numFmt[0], just[0], numFmt[1], just[1], numFmt[2], just[2], numFmt[3], just[3], numFmt[4], just[4], numFmt[5], just[5], numFmt[6], just[6], numFmt[7], just[7], numFmt[8], just[8]));
  4216. numberingXDoc.Root.Add(simpleNumAbstract);
  4217. }
  4218. }
  4219. }
  4220. foreach (var list in numToAbstractNum)
  4221. {
  4222. numberingXDoc.Root.Add(
  4223. new XElement(W.num, new XAttribute(W.numId, list.Key),
  4224. new XElement(W.abstractNumId, new XAttribute(W.val, list.Value))));
  4225. }
  4226. wDoc.MainDocumentPart.NumberingDefinitionsPart.PutXDocument();
  4227. #if false
  4228. <w:num w:numId='1'>
  4229. <w:abstractNumId w:val='0'/>
  4230. </w:num>
  4231. #endif
  4232. }
  4233. }
  4234. class StylesUpdater
  4235. {
  4236. public static void UpdateStylesPart(
  4237. WordprocessingDocument wDoc,
  4238. XElement html,
  4239. HtmlToWmlConverterSettings settings,
  4240. CssDocument defaultCssDoc,
  4241. CssDocument authorCssDoc,
  4242. CssDocument userCssDoc)
  4243. {
  4244. XDocument styleXDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  4245. if (settings.DefaultSpacingElement != null)
  4246. {
  4247. XElement spacingElement = styleXDoc.Root.Elements(W.docDefaults).Elements(W.pPrDefault).Elements(W.pPr).Elements(W.spacing).FirstOrDefault();
  4248. if (spacingElement != null)
  4249. spacingElement.ReplaceWith(settings.DefaultSpacingElement);
  4250. }
  4251. var classes = html
  4252. .DescendantsAndSelf()
  4253. .Where(d => d.Attribute(XhtmlNoNamespace._class) != null && ((string)d.Attribute(XhtmlNoNamespace._class)).Split().Length == 1)
  4254. .Select(d => (string)d.Attribute(XhtmlNoNamespace._class));
  4255. foreach (var item in classes)
  4256. {
  4257. //string item = "ms-rteStyle-Byline";
  4258. foreach (var ruleSet in authorCssDoc.RuleSets)
  4259. {
  4260. var selector = ruleSet.Selectors.Where(
  4261. sel =>
  4262. {
  4263. bool found = sel.SimpleSelectors.Count() == 1 &&
  4264. sel.SimpleSelectors.First().Class == item &&
  4265. (sel.SimpleSelectors.First().ElementName == "" ||
  4266. sel.SimpleSelectors.First().ElementName == null);
  4267. return found;
  4268. }).FirstOrDefault();
  4269. var color = ruleSet.Declarations.FirstOrDefault(d => d.Name == "color");
  4270. if (selector != null)
  4271. {
  4272. //Console.WriteLine("found ruleset and selector for {0}", item);
  4273. string styleName = item.ToLower();
  4274. XElement newStyle = new XElement(W.style,
  4275. new XAttribute(W.type, "paragraph"),
  4276. new XAttribute(W.customStyle, "1"),
  4277. new XAttribute(W.styleId, styleName),
  4278. new XElement(W.name, new XAttribute(W.val, styleName)),
  4279. new XElement(W.basedOn, new XAttribute(W.val, "Normal")),
  4280. new XElement(W.pPr,
  4281. new XElement(W.spacing, new XAttribute(W.before, "100"),
  4282. new XAttribute(W.beforeAutospacing, "1"),
  4283. new XAttribute(W.after, "100"),
  4284. new XAttribute(W.afterAutospacing, "1"),
  4285. new XAttribute(W.line, "240"),
  4286. new XAttribute(W.lineRule, "auto"))),
  4287. new XElement(W.rPr,
  4288. new XElement(W.rFonts, new XAttribute(W.ascii, "Times New Roman"),
  4289. new XAttribute(W.eastAsiaTheme, "minorEastAsia"),
  4290. new XAttribute(W.hAnsi, "Times New Roman"),
  4291. new XAttribute(W.cs, "Times New Roman")),
  4292. color != null ? new XElement(W.color, new XAttribute(W.val, "this should be a color")) : null,
  4293. new XElement(W.sz, new XAttribute(W.val, "24")),
  4294. new XElement(W.szCs, new XAttribute(W.val, "24"))));
  4295. if (styleXDoc
  4296. .Root
  4297. .Elements(W.style)
  4298. .Where(e => (string)e.Attribute(W.type) == "paragraph" && ((string)e.Attribute(W.styleId)).ToLower() == styleName)
  4299. .FirstOrDefault() == null)
  4300. styleXDoc.Root.Add(newStyle);
  4301. }
  4302. }
  4303. }
  4304. if (html.Descendants(XhtmlNoNamespace.h1).Any())
  4305. PtUtils.AddElementIfMissing(styleXDoc,
  4306. styleXDoc
  4307. .Root
  4308. .Elements(W.style)
  4309. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading1")
  4310. .FirstOrDefault(),
  4311. @"<w:style w:type='paragraph'
  4312. w:styleId='Heading1'
  4313. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4314. <w:name w:val='heading 1'/>
  4315. <w:basedOn w:val='Normal'/>
  4316. <w:next w:val='Normal'/>
  4317. <w:link w:val='Heading1Char'/>
  4318. <w:uiPriority w:val='9'/>
  4319. <w:qFormat/>
  4320. <w:pPr>
  4321. <w:keepNext/>
  4322. <w:keepLines/>
  4323. <w:spacing w:before='480'
  4324. w:after='0'/>
  4325. <w:outlineLvl w:val='0'/>
  4326. </w:pPr>
  4327. <w:rPr>
  4328. <w:rFonts w:asciiTheme='majorHAnsi'
  4329. w:eastAsiaTheme='majorEastAsia'
  4330. w:hAnsiTheme='majorHAnsi'
  4331. w:cstheme='majorBidi'/>
  4332. <w:b/>
  4333. <w:bCs/>
  4334. <w:color w:val='365F91'
  4335. w:themeColor='accent1'
  4336. w:themeShade='BF'/>
  4337. <w:sz w:val='28'/>
  4338. <w:szCs w:val='28'/>
  4339. </w:rPr>
  4340. </w:style>");
  4341. if (html.Descendants(XhtmlNoNamespace.h2).Any())
  4342. PtUtils.AddElementIfMissing(styleXDoc,
  4343. styleXDoc
  4344. .Root
  4345. .Elements(W.style)
  4346. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading2")
  4347. .FirstOrDefault(),
  4348. @"<w:style w:type='paragraph'
  4349. w:styleId='Heading2'
  4350. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4351. <w:name w:val='heading 2'/>
  4352. <w:basedOn w:val='Normal'/>
  4353. <w:next w:val='Normal'/>
  4354. <w:link w:val='Heading2Char'/>
  4355. <w:uiPriority w:val='9'/>
  4356. <w:unhideWhenUsed/>
  4357. <w:qFormat/>
  4358. <w:pPr>
  4359. <w:keepNext/>
  4360. <w:keepLines/>
  4361. <w:spacing w:before='200'
  4362. w:after='0'/>
  4363. <w:outlineLvl w:val='1'/>
  4364. </w:pPr>
  4365. <w:rPr>
  4366. <w:rFonts w:asciiTheme='majorHAnsi'
  4367. w:eastAsiaTheme='majorEastAsia'
  4368. w:hAnsiTheme='majorHAnsi'
  4369. w:cstheme='majorBidi'/>
  4370. <w:b/>
  4371. <w:bCs/>
  4372. <w:color w:val='4F81BD'
  4373. w:themeColor='accent1'/>
  4374. <w:sz w:val='26'/>
  4375. <w:szCs w:val='26'/>
  4376. </w:rPr>
  4377. </w:style>");
  4378. if (html.Descendants(XhtmlNoNamespace.h3).Any())
  4379. PtUtils.AddElementIfMissing(styleXDoc,
  4380. styleXDoc
  4381. .Root
  4382. .Elements(W.style)
  4383. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading3")
  4384. .FirstOrDefault(),
  4385. @"<w:style w:type='paragraph'
  4386. w:styleId='Heading3'
  4387. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4388. <w:name w:val='heading 3'/>
  4389. <w:basedOn w:val='Normal'/>
  4390. <w:next w:val='Normal'/>
  4391. <w:link w:val='Heading3Char'/>
  4392. <w:uiPriority w:val='9'/>
  4393. <w:unhideWhenUsed/>
  4394. <w:qFormat/>
  4395. <w:pPr>
  4396. <w:keepNext/>
  4397. <w:keepLines/>
  4398. <w:spacing w:before='200'
  4399. w:after='0'/>
  4400. <w:outlineLvl w:val='2'/>
  4401. </w:pPr>
  4402. <w:rPr>
  4403. <w:rFonts w:asciiTheme='majorHAnsi'
  4404. w:eastAsiaTheme='majorEastAsia'
  4405. w:hAnsiTheme='majorHAnsi'
  4406. w:cstheme='majorBidi'/>
  4407. <w:b/>
  4408. <w:bCs/>
  4409. <w:color w:val='4F81BD'
  4410. w:themeColor='accent1'/>
  4411. </w:rPr>
  4412. </w:style>");
  4413. if (html.Descendants(XhtmlNoNamespace.h4).Any())
  4414. PtUtils.AddElementIfMissing(styleXDoc,
  4415. styleXDoc
  4416. .Root
  4417. .Elements(W.style)
  4418. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading4")
  4419. .FirstOrDefault(),
  4420. @"<w:style w:type='paragraph'
  4421. w:styleId='Heading4'
  4422. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4423. <w:name w:val='heading 4'/>
  4424. <w:basedOn w:val='Normal'/>
  4425. <w:next w:val='Normal'/>
  4426. <w:link w:val='Heading4Char'/>
  4427. <w:uiPriority w:val='9'/>
  4428. <w:unhideWhenUsed/>
  4429. <w:qFormat/>
  4430. <w:pPr>
  4431. <w:keepNext/>
  4432. <w:keepLines/>
  4433. <w:spacing w:before='200'
  4434. w:after='0'/>
  4435. <w:outlineLvl w:val='3'/>
  4436. </w:pPr>
  4437. <w:rPr>
  4438. <w:rFonts w:asciiTheme='majorHAnsi'
  4439. w:eastAsiaTheme='majorEastAsia'
  4440. w:hAnsiTheme='majorHAnsi'
  4441. w:cstheme='majorBidi'/>
  4442. <w:b/>
  4443. <w:bCs/>
  4444. <w:i/>
  4445. <w:iCs/>
  4446. <w:color w:val='4F81BD'
  4447. w:themeColor='accent1'/>
  4448. </w:rPr>
  4449. </w:style>");
  4450. if (html.Descendants(XhtmlNoNamespace.h5).Any())
  4451. PtUtils.AddElementIfMissing(styleXDoc,
  4452. styleXDoc
  4453. .Root
  4454. .Elements(W.style)
  4455. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading5")
  4456. .FirstOrDefault(),
  4457. @"<w:style w:type='paragraph'
  4458. w:styleId='Heading5'
  4459. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4460. <w:name w:val='heading 5'/>
  4461. <w:basedOn w:val='Normal'/>
  4462. <w:next w:val='Normal'/>
  4463. <w:link w:val='Heading5Char'/>
  4464. <w:uiPriority w:val='9'/>
  4465. <w:unhideWhenUsed/>
  4466. <w:qFormat/>
  4467. <w:pPr>
  4468. <w:keepNext/>
  4469. <w:keepLines/>
  4470. <w:spacing w:before='200'
  4471. w:after='0'/>
  4472. <w:outlineLvl w:val='4'/>
  4473. </w:pPr>
  4474. <w:rPr>
  4475. <w:rFonts w:asciiTheme='majorHAnsi'
  4476. w:eastAsiaTheme='majorEastAsia'
  4477. w:hAnsiTheme='majorHAnsi'
  4478. w:cstheme='majorBidi'/>
  4479. <w:color w:val='243F60'
  4480. w:themeColor='accent1'
  4481. w:themeShade='7F'/>
  4482. </w:rPr>
  4483. </w:style>");
  4484. if (html.Descendants(XhtmlNoNamespace.h6).Any())
  4485. PtUtils.AddElementIfMissing(styleXDoc,
  4486. styleXDoc
  4487. .Root
  4488. .Elements(W.style)
  4489. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading6")
  4490. .FirstOrDefault(),
  4491. @"<w:style w:type='paragraph'
  4492. w:styleId='Heading6'
  4493. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4494. <w:name w:val='heading 6'/>
  4495. <w:basedOn w:val='Normal'/>
  4496. <w:next w:val='Normal'/>
  4497. <w:link w:val='Heading6Char'/>
  4498. <w:uiPriority w:val='9'/>
  4499. <w:unhideWhenUsed/>
  4500. <w:qFormat/>
  4501. <w:pPr>
  4502. <w:keepNext/>
  4503. <w:keepLines/>
  4504. <w:spacing w:before='200'
  4505. w:after='0'/>
  4506. <w:outlineLvl w:val='5'/>
  4507. </w:pPr>
  4508. <w:rPr>
  4509. <w:rFonts w:asciiTheme='majorHAnsi'
  4510. w:eastAsiaTheme='majorEastAsia'
  4511. w:hAnsiTheme='majorHAnsi'
  4512. w:cstheme='majorBidi'/>
  4513. <w:i/>
  4514. <w:iCs/>
  4515. <w:color w:val='243F60'
  4516. w:themeColor='accent1'
  4517. w:themeShade='7F'/>
  4518. </w:rPr>
  4519. </w:style>");
  4520. if (html.Descendants(XhtmlNoNamespace.h7).Any())
  4521. PtUtils.AddElementIfMissing(styleXDoc,
  4522. styleXDoc
  4523. .Root
  4524. .Elements(W.style)
  4525. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading7")
  4526. .FirstOrDefault(),
  4527. @"<w:style w:type='paragraph'
  4528. w:styleId='Heading7'
  4529. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4530. <w:name w:val='heading 7'/>
  4531. <w:basedOn w:val='Normal'/>
  4532. <w:next w:val='Normal'/>
  4533. <w:link w:val='Heading7Char'/>
  4534. <w:uiPriority w:val='9'/>
  4535. <w:unhideWhenUsed/>
  4536. <w:qFormat/>
  4537. <w:pPr>
  4538. <w:keepNext/>
  4539. <w:keepLines/>
  4540. <w:spacing w:before='200'
  4541. w:after='0'/>
  4542. <w:outlineLvl w:val='6'/>
  4543. </w:pPr>
  4544. <w:rPr>
  4545. <w:rFonts w:asciiTheme='majorHAnsi'
  4546. w:eastAsiaTheme='majorEastAsia'
  4547. w:hAnsiTheme='majorHAnsi'
  4548. w:cstheme='majorBidi'/>
  4549. <w:i/>
  4550. <w:iCs/>
  4551. <w:color w:val='404040'
  4552. w:themeColor='text1'
  4553. w:themeTint='BF'/>
  4554. </w:rPr>
  4555. </w:style>");
  4556. if (html.Descendants(XhtmlNoNamespace.h8).Any())
  4557. PtUtils.AddElementIfMissing(styleXDoc,
  4558. styleXDoc
  4559. .Root
  4560. .Elements(W.style)
  4561. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading8")
  4562. .FirstOrDefault(),
  4563. @"<w:style w:type='paragraph'
  4564. w:styleId='Heading8'
  4565. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4566. <w:name w:val='heading 8'/>
  4567. <w:basedOn w:val='Normal'/>
  4568. <w:next w:val='Normal'/>
  4569. <w:link w:val='Heading8Char'/>
  4570. <w:uiPriority w:val='9'/>
  4571. <w:unhideWhenUsed/>
  4572. <w:qFormat/>
  4573. <w:pPr>
  4574. <w:keepNext/>
  4575. <w:keepLines/>
  4576. <w:spacing w:before='200'
  4577. w:after='0'/>
  4578. <w:outlineLvl w:val='7'/>
  4579. </w:pPr>
  4580. <w:rPr>
  4581. <w:rFonts w:asciiTheme='majorHAnsi'
  4582. w:eastAsiaTheme='majorEastAsia'
  4583. w:hAnsiTheme='majorHAnsi'
  4584. w:cstheme='majorBidi'/>
  4585. <w:color w:val='404040'
  4586. w:themeColor='text1'
  4587. w:themeTint='BF'/>
  4588. <w:sz w:val='20'/>
  4589. <w:szCs w:val='20'/>
  4590. </w:rPr>
  4591. </w:style>");
  4592. if (html.Descendants(XhtmlNoNamespace.h9).Any())
  4593. PtUtils.AddElementIfMissing(styleXDoc,
  4594. styleXDoc
  4595. .Root
  4596. .Elements(W.style)
  4597. .Where(e => (string)e.Attribute(W.type) == "paragraph" && (string)e.Attribute(W.styleId) == "Heading9")
  4598. .FirstOrDefault(),
  4599. @"<w:style w:type='paragraph'
  4600. w:styleId='Heading9'
  4601. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4602. <w:name w:val='heading 9'/>
  4603. <w:basedOn w:val='Normal'/>
  4604. <w:next w:val='Normal'/>
  4605. <w:link w:val='Heading9Char'/>
  4606. <w:uiPriority w:val='9'/>
  4607. <w:unhideWhenUsed/>
  4608. <w:qFormat/>
  4609. <w:pPr>
  4610. <w:keepNext/>
  4611. <w:keepLines/>
  4612. <w:spacing w:before='200'
  4613. w:after='0'/>
  4614. <w:outlineLvl w:val='8'/>
  4615. </w:pPr>
  4616. <w:rPr>
  4617. <w:rFonts w:asciiTheme='majorHAnsi'
  4618. w:eastAsiaTheme='majorEastAsia'
  4619. w:hAnsiTheme='majorHAnsi'
  4620. w:cstheme='majorBidi'/>
  4621. <w:i/>
  4622. <w:iCs/>
  4623. <w:color w:val='404040'
  4624. w:themeColor='text1'
  4625. w:themeTint='BF'/>
  4626. <w:sz w:val='20'/>
  4627. <w:szCs w:val='20'/>
  4628. </w:rPr>
  4629. </w:style>");
  4630. if (html.Descendants(XhtmlNoNamespace.h1).Any())
  4631. PtUtils.AddElementIfMissing(styleXDoc,
  4632. styleXDoc
  4633. .Root
  4634. .Elements(W.style)
  4635. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading1Char")
  4636. .FirstOrDefault(),
  4637. @"<w:style w:type='character'
  4638. w:customStyle='1'
  4639. w:styleId='Heading1Char'
  4640. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4641. <w:name w:val='Heading 1 Char'/>
  4642. <w:basedOn w:val='DefaultParagraphFont'/>
  4643. <w:link w:val='Heading1'/>
  4644. <w:uiPriority w:val='9'/>
  4645. <w:rPr>
  4646. <w:rFonts w:asciiTheme='majorHAnsi'
  4647. w:eastAsiaTheme='majorEastAsia'
  4648. w:hAnsiTheme='majorHAnsi'
  4649. w:cstheme='majorBidi'/>
  4650. <w:b/>
  4651. <w:bCs/>
  4652. <w:color w:val='365F91'
  4653. w:themeColor='accent1'
  4654. w:themeShade='BF'/>
  4655. <w:sz w:val='28'/>
  4656. <w:szCs w:val='28'/>
  4657. </w:rPr>
  4658. </w:style>");
  4659. if (html.Descendants(XhtmlNoNamespace.h2).Any())
  4660. PtUtils.AddElementIfMissing(styleXDoc,
  4661. styleXDoc
  4662. .Root
  4663. .Elements(W.style)
  4664. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading2Char")
  4665. .FirstOrDefault(),
  4666. @"<w:style w:type='character'
  4667. w:customStyle='1'
  4668. w:styleId='Heading2Char'
  4669. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4670. <w:name w:val='Heading 2 Char'/>
  4671. <w:basedOn w:val='DefaultParagraphFont'/>
  4672. <w:link w:val='Heading2'/>
  4673. <w:uiPriority w:val='9'/>
  4674. <w:rPr>
  4675. <w:rFonts w:asciiTheme='majorHAnsi'
  4676. w:eastAsiaTheme='majorEastAsia'
  4677. w:hAnsiTheme='majorHAnsi'
  4678. w:cstheme='majorBidi'/>
  4679. <w:b/>
  4680. <w:bCs/>
  4681. <w:color w:val='4F81BD'
  4682. w:themeColor='accent1'/>
  4683. <w:sz w:val='26'/>
  4684. <w:szCs w:val='26'/>
  4685. </w:rPr>
  4686. </w:style>");
  4687. if (html.Descendants(XhtmlNoNamespace.h3).Any())
  4688. PtUtils.AddElementIfMissing(styleXDoc,
  4689. styleXDoc
  4690. .Root
  4691. .Elements(W.style)
  4692. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading3Char")
  4693. .FirstOrDefault(),
  4694. @"<w:style w:type='character'
  4695. w:customStyle='1'
  4696. w:styleId='Heading3Char'
  4697. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4698. <w:name w:val='Heading 3 Char'/>
  4699. <w:basedOn w:val='DefaultParagraphFont'/>
  4700. <w:link w:val='Heading3'/>
  4701. <w:uiPriority w:val='9'/>
  4702. <w:rPr>
  4703. <w:rFonts w:asciiTheme='majorHAnsi'
  4704. w:eastAsiaTheme='majorEastAsia'
  4705. w:hAnsiTheme='majorHAnsi'
  4706. w:cstheme='majorBidi'/>
  4707. <w:b/>
  4708. <w:bCs/>
  4709. <w:color w:val='4F81BD'
  4710. w:themeColor='accent1'/>
  4711. </w:rPr>
  4712. </w:style>");
  4713. if (html.Descendants(XhtmlNoNamespace.h4).Any())
  4714. PtUtils.AddElementIfMissing(styleXDoc,
  4715. styleXDoc
  4716. .Root
  4717. .Elements(W.style)
  4718. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading4Char")
  4719. .FirstOrDefault(),
  4720. @"<w:style w:type='character'
  4721. w:customStyle='1'
  4722. w:styleId='Heading4Char'
  4723. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4724. <w:name w:val='Heading 4 Char'/>
  4725. <w:basedOn w:val='DefaultParagraphFont'/>
  4726. <w:link w:val='Heading4'/>
  4727. <w:uiPriority w:val='9'/>
  4728. <w:rPr>
  4729. <w:rFonts w:asciiTheme='majorHAnsi'
  4730. w:eastAsiaTheme='majorEastAsia'
  4731. w:hAnsiTheme='majorHAnsi'
  4732. w:cstheme='majorBidi'/>
  4733. <w:b/>
  4734. <w:bCs/>
  4735. <w:i/>
  4736. <w:iCs/>
  4737. <w:color w:val='4F81BD'
  4738. w:themeColor='accent1'/>
  4739. </w:rPr>
  4740. </w:style>");
  4741. if (html.Descendants(XhtmlNoNamespace.h5).Any())
  4742. PtUtils.AddElementIfMissing(styleXDoc,
  4743. styleXDoc
  4744. .Root
  4745. .Elements(W.style)
  4746. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading5Char")
  4747. .FirstOrDefault(),
  4748. @"<w:style w:type='character'
  4749. w:customStyle='1'
  4750. w:styleId='Heading5Char'
  4751. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4752. <w:name w:val='Heading 5 Char'/>
  4753. <w:basedOn w:val='DefaultParagraphFont'/>
  4754. <w:link w:val='Heading5'/>
  4755. <w:uiPriority w:val='9'/>
  4756. <w:rPr>
  4757. <w:rFonts w:asciiTheme='majorHAnsi'
  4758. w:eastAsiaTheme='majorEastAsia'
  4759. w:hAnsiTheme='majorHAnsi'
  4760. w:cstheme='majorBidi'/>
  4761. <w:color w:val='243F60'
  4762. w:themeColor='accent1'
  4763. w:themeShade='7F'/>
  4764. </w:rPr>
  4765. </w:style>");
  4766. if (html.Descendants(XhtmlNoNamespace.h6).Any())
  4767. PtUtils.AddElementIfMissing(styleXDoc,
  4768. styleXDoc
  4769. .Root
  4770. .Elements(W.style)
  4771. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading6Char")
  4772. .FirstOrDefault(),
  4773. @"<w:style w:type='character'
  4774. w:customStyle='1'
  4775. w:styleId='Heading6Char'
  4776. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4777. <w:name w:val='Heading 6 Char'/>
  4778. <w:basedOn w:val='DefaultParagraphFont'/>
  4779. <w:link w:val='Heading6'/>
  4780. <w:uiPriority w:val='9'/>
  4781. <w:rPr>
  4782. <w:rFonts w:asciiTheme='majorHAnsi'
  4783. w:eastAsiaTheme='majorEastAsia'
  4784. w:hAnsiTheme='majorHAnsi'
  4785. w:cstheme='majorBidi'/>
  4786. <w:i/>
  4787. <w:iCs/>
  4788. <w:color w:val='243F60'
  4789. w:themeColor='accent1'
  4790. w:themeShade='7F'/>
  4791. </w:rPr>
  4792. </w:style>");
  4793. if (html.Descendants(XhtmlNoNamespace.h7).Any())
  4794. PtUtils.AddElementIfMissing(styleXDoc,
  4795. styleXDoc
  4796. .Root
  4797. .Elements(W.style)
  4798. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading7Char")
  4799. .FirstOrDefault(),
  4800. @"<w:style w:type='character'
  4801. w:customStyle='1'
  4802. w:styleId='Heading7Char'
  4803. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4804. <w:name w:val='Heading 7 Char'/>
  4805. <w:basedOn w:val='DefaultParagraphFont'/>
  4806. <w:link w:val='Heading7'/>
  4807. <w:uiPriority w:val='9'/>
  4808. <w:rPr>
  4809. <w:rFonts w:asciiTheme='majorHAnsi'
  4810. w:eastAsiaTheme='majorEastAsia'
  4811. w:hAnsiTheme='majorHAnsi'
  4812. w:cstheme='majorBidi'/>
  4813. <w:i/>
  4814. <w:iCs/>
  4815. <w:color w:val='404040'
  4816. w:themeColor='text1'
  4817. w:themeTint='BF'/>
  4818. </w:rPr>
  4819. </w:style>");
  4820. if (html.Descendants(XhtmlNoNamespace.h8).Any())
  4821. PtUtils.AddElementIfMissing(styleXDoc,
  4822. styleXDoc
  4823. .Root
  4824. .Elements(W.style)
  4825. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading8Char")
  4826. .FirstOrDefault(),
  4827. @"<w:style w:type='character'
  4828. w:customStyle='1'
  4829. w:styleId='Heading8Char'
  4830. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4831. <w:name w:val='Heading 8 Char'/>
  4832. <w:basedOn w:val='DefaultParagraphFont'/>
  4833. <w:link w:val='Heading8'/>
  4834. <w:uiPriority w:val='9'/>
  4835. <w:rPr>
  4836. <w:rFonts w:asciiTheme='majorHAnsi'
  4837. w:eastAsiaTheme='majorEastAsia'
  4838. w:hAnsiTheme='majorHAnsi'
  4839. w:cstheme='majorBidi'/>
  4840. <w:color w:val='404040'
  4841. w:themeColor='text1'
  4842. w:themeTint='BF'/>
  4843. <w:sz w:val='20'/>
  4844. <w:szCs w:val='20'/>
  4845. </w:rPr>
  4846. </w:style>");
  4847. if (html.Descendants(XhtmlNoNamespace.h9).Any())
  4848. PtUtils.AddElementIfMissing(styleXDoc,
  4849. styleXDoc
  4850. .Root
  4851. .Elements(W.style)
  4852. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Heading9Char")
  4853. .FirstOrDefault(),
  4854. @"<w:style w:type='character'
  4855. w:customStyle='1'
  4856. w:styleId='Heading9Char'
  4857. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4858. <w:name w:val='Heading 9 Char'/>
  4859. <w:basedOn w:val='DefaultParagraphFont'/>
  4860. <w:link w:val='Heading9'/>
  4861. <w:uiPriority w:val='9'/>
  4862. <w:rPr>
  4863. <w:rFonts w:asciiTheme='majorHAnsi'
  4864. w:eastAsiaTheme='majorEastAsia'
  4865. w:hAnsiTheme='majorHAnsi'
  4866. w:cstheme='majorBidi'/>
  4867. <w:i/>
  4868. <w:iCs/>
  4869. <w:color w:val='404040'
  4870. w:themeColor='text1'
  4871. w:themeTint='BF'/>
  4872. <w:sz w:val='20'/>
  4873. <w:szCs w:val='20'/>
  4874. </w:rPr>
  4875. </w:style>");
  4876. if (html.Descendants(XhtmlNoNamespace.a).Any())
  4877. PtUtils.AddElementIfMissing(styleXDoc,
  4878. styleXDoc
  4879. .Root
  4880. .Elements(W.style)
  4881. .Where(e => (string)e.Attribute(W.type) == "character" && (string)e.Attribute(W.styleId) == "Hyperlink")
  4882. .FirstOrDefault(),
  4883. @"<w:style w:type='character'
  4884. w:styleId='Hyperlink'
  4885. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>
  4886. <w:name w:val='Hyperlink' />
  4887. <w:basedOn w:val='DefaultParagraphFont' />
  4888. <w:uiPriority w:val='99' />
  4889. <w:semiHidden />
  4890. <w:unhideWhenUsed />
  4891. <w:rPr>
  4892. <w:color w:val='0000FF' />
  4893. <w:u w:val='single' />
  4894. </w:rPr>
  4895. </w:style>");
  4896. wDoc.MainDocumentPart.StyleDefinitionsPart.PutXDocument();
  4897. }
  4898. }
  4899. class ThemeUpdater
  4900. {
  4901. public static void UpdateThemePart(WordprocessingDocument wDoc, XElement html, HtmlToWmlConverterSettings settings)
  4902. {
  4903. XDocument themeXDoc = wDoc.MainDocumentPart.ThemePart.GetXDocument();
  4904. CssExpression minorFont = html.Descendants(XhtmlNoNamespace.body).FirstOrDefault().GetProp("font-family");
  4905. XElement majorFontElement = html.Descendants().Where(e =>
  4906. e.Name == XhtmlNoNamespace.h1 ||
  4907. e.Name == XhtmlNoNamespace.h2 ||
  4908. e.Name == XhtmlNoNamespace.h3 ||
  4909. e.Name == XhtmlNoNamespace.h4 ||
  4910. e.Name == XhtmlNoNamespace.h5 ||
  4911. e.Name == XhtmlNoNamespace.h6 ||
  4912. e.Name == XhtmlNoNamespace.h7 ||
  4913. e.Name == XhtmlNoNamespace.h8 ||
  4914. e.Name == XhtmlNoNamespace.h9).FirstOrDefault();
  4915. CssExpression majorFont = null;
  4916. if (majorFontElement != null)
  4917. majorFont = majorFontElement.GetProp("font-family");
  4918. XAttribute majorTypeface = themeXDoc
  4919. .Root
  4920. .Elements(A.themeElements)
  4921. .Elements(A.fontScheme)
  4922. .Elements(A.majorFont)
  4923. .Elements(A.latin)
  4924. .Attributes(NoNamespace.typeface)
  4925. .FirstOrDefault();
  4926. if (majorTypeface != null && majorFont != null)
  4927. {
  4928. CssTerm term = majorFont.Terms.FirstOrDefault();
  4929. if (term != null)
  4930. majorTypeface.Value = term.Value;
  4931. }
  4932. XAttribute minorTypeface = themeXDoc
  4933. .Root
  4934. .Elements(A.themeElements)
  4935. .Elements(A.fontScheme)
  4936. .Elements(A.minorFont)
  4937. .Elements(A.latin)
  4938. .Attributes(NoNamespace.typeface)
  4939. .FirstOrDefault();
  4940. if (minorTypeface != null && minorFont != null)
  4941. {
  4942. CssTerm term = minorFont.Terms.FirstOrDefault();
  4943. if (term != null)
  4944. minorTypeface.Value = term.Value;
  4945. }
  4946. wDoc.MainDocumentPart.ThemePart.PutXDocument();
  4947. }
  4948. }
  4949. }