No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TextMeshProUGUI.cs 275KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570
  1. using System;
  2. using System.Collections;
  3. using UnityEngine;
  4. using UnityEngine.Rendering;
  5. using UnityEngine.UI;
  6. using System.Collections.Generic;
  7. using Unity.Profiling;
  8. using UnityEngine.TextCore;
  9. using UnityEngine.TextCore.LowLevel;
  10. using Object = UnityEngine.Object;
  11. #pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor.
  12. #pragma warning disable 0618 // Disabled warning due to SetVertices being deprecated until new release with SetMesh() is available.
  13. namespace TMPro
  14. {
  15. [DisallowMultipleComponent]
  16. [RequireComponent(typeof(RectTransform))]
  17. [RequireComponent(typeof(CanvasRenderer))]
  18. [AddComponentMenu("UI/TextMeshPro - Text (UI)", 11)]
  19. [ExecuteAlways]
  20. [HelpURL("https://docs.unity3d.com/Packages/com.unity.textmeshpro@3.2")]
  21. public class TextMeshProUGUI : TMP_Text, ILayoutElement
  22. {
  23. /// <summary>
  24. /// Get the material that will be used for rendering.
  25. /// </summary>
  26. public override Material materialForRendering
  27. {
  28. get { return TMP_MaterialManager.GetMaterialForRendering(this, m_sharedMaterial); }
  29. }
  30. /// <summary>
  31. /// Determines if the size of the text container will be adjusted to fit the text object when it is first created.
  32. /// </summary>
  33. public override bool autoSizeTextContainer
  34. {
  35. get { return m_autoSizeTextContainer; }
  36. set { if (m_autoSizeTextContainer == value) return; m_autoSizeTextContainer = value; if (m_autoSizeTextContainer) { CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this); SetLayoutDirty(); } }
  37. }
  38. /// <summary>
  39. /// Reference to the Mesh used by the text object.
  40. /// </summary>
  41. public override Mesh mesh
  42. {
  43. get { return m_mesh; }
  44. }
  45. /// <summary>
  46. /// Reference to the CanvasRenderer used by the text object.
  47. /// </summary>
  48. public new CanvasRenderer canvasRenderer
  49. {
  50. get
  51. {
  52. if (m_canvasRenderer == null) m_canvasRenderer = GetComponent<CanvasRenderer>();
  53. return m_canvasRenderer;
  54. }
  55. }
  56. /// <summary>
  57. /// Anchor dampening prevents the anchor position from being adjusted unless the positional change exceeds about 40% of the width of the underline character. This essentially stabilizes the anchor position.
  58. /// </summary>
  59. //public bool anchorDampening
  60. //{
  61. // get { return m_anchorDampening; }
  62. // set { if (m_anchorDampening != value) { havePropertiesChanged = true; m_anchorDampening = value; /* ScheduleUpdate(); */ } }
  63. //}
  64. #if !UNITY_2019_3_OR_NEWER
  65. [SerializeField]
  66. private bool m_Maskable = true;
  67. #endif
  68. private bool m_isRebuildingLayout = false;
  69. private Coroutine m_DelayedGraphicRebuild;
  70. private Coroutine m_DelayedMaterialRebuild;
  71. /// <summary>
  72. /// Function called by Unity when the horizontal layout needs to be recalculated.
  73. /// </summary>
  74. public void CalculateLayoutInputHorizontal()
  75. {
  76. //Debug.Log("*** CalculateLayoutHorizontal() on Object ID: " + GetInstanceID() + " at frame: " + Time.frameCount + "***");
  77. }
  78. /// <summary>
  79. /// Function called by Unity when the vertical layout needs to be recalculated.
  80. /// </summary>
  81. public void CalculateLayoutInputVertical()
  82. {
  83. //Debug.Log("*** CalculateLayoutInputVertical() on Object ID: " + GetInstanceID() + " at frame: " + Time.frameCount + "***");
  84. }
  85. public override void SetVerticesDirty()
  86. {
  87. if (this == null || !this.IsActive())
  88. return;
  89. if (CanvasUpdateRegistry.IsRebuildingGraphics())
  90. return;
  91. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
  92. if (m_OnDirtyVertsCallback != null)
  93. m_OnDirtyVertsCallback();
  94. }
  95. /// <summary>
  96. ///
  97. /// </summary>
  98. public override void SetLayoutDirty()
  99. {
  100. m_isPreferredWidthDirty = true;
  101. m_isPreferredHeightDirty = true;
  102. if (this == null || !this.IsActive())
  103. return;
  104. LayoutRebuilder.MarkLayoutForRebuild(this.rectTransform);
  105. m_isLayoutDirty = true;
  106. if (m_OnDirtyLayoutCallback != null)
  107. m_OnDirtyLayoutCallback();
  108. }
  109. /// <summary>
  110. ///
  111. /// </summary>
  112. public override void SetMaterialDirty()
  113. {
  114. if (this == null || !this.IsActive())
  115. return;
  116. if (CanvasUpdateRegistry.IsRebuildingGraphics())
  117. return;
  118. m_isMaterialDirty = true;
  119. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
  120. if (m_OnDirtyMaterialCallback != null)
  121. m_OnDirtyMaterialCallback();
  122. }
  123. /// <summary>
  124. ///
  125. /// </summary>
  126. public override void SetAllDirty()
  127. {
  128. SetLayoutDirty();
  129. SetVerticesDirty();
  130. SetMaterialDirty();
  131. }
  132. /// <summary>
  133. /// Delay registration of text object for graphic rebuild by one frame.
  134. /// </summary>
  135. /// <returns></returns>
  136. IEnumerator DelayedGraphicRebuild()
  137. {
  138. yield return null;
  139. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
  140. if (m_OnDirtyVertsCallback != null)
  141. m_OnDirtyVertsCallback();
  142. m_DelayedGraphicRebuild = null;
  143. }
  144. /// <summary>
  145. /// Delay registration of text object for graphic rebuild by one frame.
  146. /// </summary>
  147. /// <returns></returns>
  148. IEnumerator DelayedMaterialRebuild()
  149. {
  150. yield return null;
  151. m_isMaterialDirty = true;
  152. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
  153. if (m_OnDirtyMaterialCallback != null)
  154. m_OnDirtyMaterialCallback();
  155. m_DelayedMaterialRebuild = null;
  156. }
  157. /// <summary>
  158. ///
  159. /// </summary>
  160. /// <param name="update"></param>
  161. public override void Rebuild(CanvasUpdate update)
  162. {
  163. if (this == null) return;
  164. if (update == CanvasUpdate.Prelayout)
  165. {
  166. if (m_autoSizeTextContainer)
  167. {
  168. m_rectTransform.sizeDelta = GetPreferredValues(Mathf.Infinity, Mathf.Infinity);
  169. }
  170. }
  171. else if (update == CanvasUpdate.PreRender)
  172. {
  173. OnPreRenderCanvas();
  174. if (!m_isMaterialDirty) return;
  175. UpdateMaterial();
  176. m_isMaterialDirty = false;
  177. }
  178. }
  179. /// <summary>
  180. /// Method to keep the pivot of the sub text objects in sync with the parent pivot.
  181. /// </summary>
  182. private void UpdateSubObjectPivot()
  183. {
  184. if (m_textInfo == null) return;
  185. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  186. {
  187. m_subTextObjects[i].SetPivotDirty();
  188. }
  189. //m_isPivotDirty = false;
  190. }
  191. /// <summary>
  192. ///
  193. /// </summary>
  194. /// <param name="baseMaterial"></param>
  195. /// <returns></returns>
  196. public override Material GetModifiedMaterial(Material baseMaterial)
  197. {
  198. Material mat = baseMaterial;
  199. if (m_ShouldRecalculateStencil)
  200. {
  201. var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);
  202. m_StencilValue = maskable ? MaskUtilities.GetStencilDepth(transform, rootCanvas) : 0;
  203. m_ShouldRecalculateStencil = false;
  204. }
  205. if (m_StencilValue > 0)
  206. {
  207. var maskMat = StencilMaterial.Add(mat, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0);
  208. StencilMaterial.Remove(m_MaskMaterial);
  209. m_MaskMaterial = maskMat;
  210. mat = m_MaskMaterial;
  211. }
  212. return mat;
  213. }
  214. /// <summary>
  215. ///
  216. /// </summary>
  217. protected override void UpdateMaterial()
  218. {
  219. //Debug.Log("*** UpdateMaterial() ***");
  220. //if (!this.IsActive())
  221. // return;
  222. if (m_sharedMaterial == null || canvasRenderer == null) return;
  223. m_canvasRenderer.materialCount = 1;
  224. m_canvasRenderer.SetMaterial(materialForRendering, 0);
  225. //m_canvasRenderer.SetTexture(materialForRendering.mainTexture);
  226. }
  227. //public override void OnRebuildRequested()
  228. //{
  229. // //Debug.Log("OnRebuildRequested");
  230. // base.OnRebuildRequested();
  231. //}
  232. //public override bool Raycast(Vector2 sp, Camera eventCamera)
  233. //{
  234. // //Debug.Log("Raycast Event. ScreenPoint: " + sp);
  235. // return base.Raycast(sp, eventCamera);
  236. //}
  237. // MASKING RELATED PROPERTIES
  238. /// <summary>
  239. /// Sets the masking offset from the bounds of the object
  240. /// </summary>
  241. public Vector4 maskOffset
  242. {
  243. get { return m_maskOffset; }
  244. set { m_maskOffset = value; UpdateMask(); m_havePropertiesChanged = true; }
  245. }
  246. //public override Material defaultMaterial
  247. //{
  248. // get { Debug.Log("Default Material called."); return m_sharedMaterial; }
  249. //}
  250. //protected override void OnCanvasHierarchyChanged()
  251. //{
  252. // //Debug.Log("OnCanvasHierarchyChanged...");
  253. //}
  254. // IClippable implementation
  255. /// <summary>
  256. /// Method called when the state of a parent changes.
  257. /// </summary>
  258. public override void RecalculateClipping()
  259. {
  260. //Debug.Log("***** RecalculateClipping() *****");
  261. base.RecalculateClipping();
  262. }
  263. // IMaskable Implementation
  264. /// <summary>
  265. /// Method called when Stencil Mask needs to be updated on this element and parents.
  266. /// </summary>
  267. // public override void RecalculateMasking()
  268. // {
  269. // //Debug.Log("***** RecalculateMasking() *****");
  270. //
  271. // this.m_ShouldRecalculateStencil = true;
  272. // SetMaterialDirty();
  273. // }
  274. //public override void SetClipRect(Rect clipRect, bool validRect)
  275. //{
  276. // //Debug.Log("***** SetClipRect (" + clipRect + ", " + validRect + ") *****");
  277. // base.SetClipRect(clipRect, validRect);
  278. //}
  279. /// <summary>
  280. /// Override of the Cull function to provide for the ability to override the culling of the text object.
  281. /// </summary>
  282. /// <param name="clipRect"></param>
  283. /// <param name="validRect"></param>
  284. public override void Cull(Rect clipRect, bool validRect)
  285. {
  286. m_ShouldUpdateCulling = false;
  287. // Delay culling check in the event the text layout is dirty and geometry has to be updated.
  288. if (m_isLayoutDirty)
  289. {
  290. m_ShouldUpdateCulling = true;
  291. m_ClipRect = clipRect;
  292. m_ValidRect = validRect;
  293. return;
  294. }
  295. // Get compound rect for the text object and sub text objects in local canvas space.
  296. Rect rect = GetCanvasSpaceClippingRect();
  297. // No point culling if geometry bounds have no width or height.
  298. //if (rect.width == 0 || rect.height == 0)
  299. // return;
  300. var cull = !validRect || !clipRect.Overlaps(rect, true);
  301. if (m_canvasRenderer.cull != cull)
  302. {
  303. m_canvasRenderer.cull = cull;
  304. onCullStateChanged.Invoke(cull);
  305. OnCullingChanged();
  306. // Update any potential sub mesh objects
  307. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  308. {
  309. m_subTextObjects[i].canvasRenderer.cull = cull;
  310. }
  311. }
  312. }
  313. private bool m_ShouldUpdateCulling;
  314. private Rect m_ClipRect;
  315. private bool m_ValidRect;
  316. /// <summary>
  317. /// Internal function to allow delay of culling until the text geometry has been updated.
  318. /// </summary>
  319. internal override void UpdateCulling()
  320. {
  321. // Get compound rect for the text object and sub text objects in local canvas space.
  322. Rect rect = GetCanvasSpaceClippingRect();
  323. // No point culling if geometry bounds have no width or height.
  324. //if (rect.width == 0 || rect.height == 0)
  325. // return;
  326. var cull = !m_ValidRect || !m_ClipRect.Overlaps(rect, true);
  327. if (m_canvasRenderer.cull != cull)
  328. {
  329. m_canvasRenderer.cull = cull;
  330. onCullStateChanged.Invoke(cull);
  331. OnCullingChanged();
  332. // Update any potential sub mesh objects
  333. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  334. {
  335. m_subTextObjects[i].canvasRenderer.cull = cull;
  336. }
  337. }
  338. m_ShouldUpdateCulling = false;
  339. }
  340. /*
  341. /// <summary>
  342. /// Sets the mask type
  343. /// </summary>
  344. public MaskingTypes mask
  345. {
  346. get { return m_mask; }
  347. set { m_mask = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  348. }
  349. /// <summary>
  350. /// Set the masking offset mode (as percentage or pixels)
  351. /// </summary>
  352. public MaskingOffsetMode maskOffsetMode
  353. {
  354. get { return m_maskOffsetMode; }
  355. set { m_maskOffsetMode = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  356. }
  357. */
  358. /*
  359. /// <summary>
  360. /// Sets the softness of the mask
  361. /// </summary>
  362. public Vector2 maskSoftness
  363. {
  364. get { return m_maskSoftness; }
  365. set { m_maskSoftness = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  366. }
  367. /// <summary>
  368. /// Allows to move / offset the mesh vertices by a set amount
  369. /// </summary>
  370. public Vector2 vertexOffset
  371. {
  372. get { return m_vertexOffset; }
  373. set { m_vertexOffset = value; havePropertiesChanged = true; isMaskUpdateRequired = true; }
  374. }
  375. */
  376. /// <summary>
  377. /// Function to be used to force recomputing of character padding when Shader / Material properties have been changed via script.
  378. /// </summary>
  379. public override void UpdateMeshPadding()
  380. {
  381. m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  382. m_isMaskingEnabled = ShaderUtilities.IsMaskingEnabled(m_sharedMaterial);
  383. m_havePropertiesChanged = true;
  384. checkPaddingRequired = false;
  385. // Return if text object is not awake yet.
  386. if (m_textInfo == null) return;
  387. // Update sub text objects
  388. for (int i = 1; i < m_textInfo.materialCount; i++)
  389. m_subTextObjects[i].UpdateMeshPadding(m_enableExtraPadding, m_isUsingBold);
  390. }
  391. /// <summary>
  392. /// Tweens the CanvasRenderer color associated with this Graphic.
  393. /// </summary>
  394. /// <param name="targetColor">Target color.</param>
  395. /// <param name="duration">Tween duration.</param>
  396. /// <param name="ignoreTimeScale">Should ignore Time.scale?</param>
  397. /// <param name="useAlpha">Should also Tween the alpha channel?</param>
  398. protected override void InternalCrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha)
  399. {
  400. if (m_textInfo == null)
  401. return;
  402. int materialCount = m_textInfo.materialCount;
  403. for (int i = 1; i < materialCount; i++)
  404. {
  405. m_subTextObjects[i].CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha);
  406. }
  407. }
  408. /// <summary>
  409. /// Tweens the alpha of the CanvasRenderer color associated with this Graphic.
  410. /// </summary>
  411. /// <param name="alpha">Target alpha.</param>
  412. /// <param name="duration">Duration of the tween in seconds.</param>
  413. /// <param name="ignoreTimeScale">Should ignore Time.scale?</param>
  414. protected override void InternalCrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale)
  415. {
  416. if (m_textInfo == null)
  417. return;
  418. int materialCount = m_textInfo.materialCount;
  419. for (int i = 1; i < materialCount; i++)
  420. {
  421. m_subTextObjects[i].CrossFadeAlpha(alpha, duration, ignoreTimeScale);
  422. }
  423. }
  424. /// <summary>
  425. /// Function to force regeneration of the text object before its normal process time. This is useful when changes to the text object properties need to be applied immediately.
  426. /// </summary>
  427. /// <param name="ignoreActiveState">Ignore Active State of text objects. Inactive objects are ignored by default.</param>
  428. /// <param name="forceTextReparsing">Force re-parsing of the text.</param>
  429. public override void ForceMeshUpdate(bool ignoreActiveState = false, bool forceTextReparsing = false)
  430. {
  431. m_havePropertiesChanged = true;
  432. m_ignoreActiveState = ignoreActiveState;
  433. // Special handling in the event the Canvas is only disabled
  434. if (m_canvas == null)
  435. m_canvas = GetComponentInParent<Canvas>();
  436. OnPreRenderCanvas();
  437. }
  438. /// <summary>
  439. /// Function used to evaluate the length of a text string.
  440. /// </summary>
  441. /// <param name="text"></param>
  442. /// <returns></returns>
  443. public override TMP_TextInfo GetTextInfo(string text)
  444. {
  445. SetText(text);
  446. SetArraySizes(m_TextProcessingArray);
  447. m_renderMode = TextRenderFlags.DontRender;
  448. ComputeMarginSize();
  449. // Need to make sure we have a valid reference to a Canvas.
  450. if (m_canvas == null) m_canvas = this.canvas;
  451. GenerateTextMesh();
  452. m_renderMode = TextRenderFlags.Render;
  453. return this.textInfo;
  454. }
  455. /// <summary>
  456. /// Function to clear the geometry of the Primary and Sub Text objects.
  457. /// </summary>
  458. public override void ClearMesh()
  459. {
  460. m_canvasRenderer.SetMesh(null);
  461. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  462. m_subTextObjects[i].canvasRenderer.SetMesh(null);
  463. }
  464. /// <summary>
  465. /// Event to allow users to modify the content of the text info before the text is rendered.
  466. /// </summary>
  467. public override event Action<TMP_TextInfo> OnPreRenderText;
  468. /// <summary>
  469. /// Function to update the geometry of the main and sub text objects.
  470. /// </summary>
  471. /// <param name="mesh"></param>
  472. /// <param name="index"></param>
  473. public override void UpdateGeometry(Mesh mesh, int index)
  474. {
  475. mesh.RecalculateBounds();
  476. if (index == 0)
  477. {
  478. m_canvasRenderer.SetMesh(mesh);
  479. }
  480. else
  481. {
  482. m_subTextObjects[index].canvasRenderer.SetMesh(mesh);
  483. }
  484. }
  485. /// <summary>
  486. /// Function to upload the updated vertex data and renderer.
  487. /// </summary>
  488. public override void UpdateVertexData(TMP_VertexDataUpdateFlags flags)
  489. {
  490. int materialCount = m_textInfo.materialCount;
  491. for (int i = 0; i < materialCount; i++)
  492. {
  493. Mesh mesh;
  494. if (i == 0)
  495. mesh = m_mesh;
  496. else
  497. {
  498. // Clear unused vertices
  499. // TODO: Causes issues when sorting geometry as last vertex data attribute get wiped out.
  500. //m_textInfo.meshInfo[i].ClearUnusedVertices();
  501. mesh = m_subTextObjects[i].mesh;
  502. }
  503. if ((flags & TMP_VertexDataUpdateFlags.Vertices) == TMP_VertexDataUpdateFlags.Vertices)
  504. mesh.vertices = m_textInfo.meshInfo[i].vertices;
  505. if ((flags & TMP_VertexDataUpdateFlags.Uv0) == TMP_VertexDataUpdateFlags.Uv0)
  506. mesh.SetUVs(0, m_textInfo.meshInfo[i].uvs0);
  507. if ((flags & TMP_VertexDataUpdateFlags.Uv2) == TMP_VertexDataUpdateFlags.Uv2)
  508. mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  509. //if ((flags & TMP_VertexDataUpdateFlags.Uv4) == TMP_VertexDataUpdateFlags.Uv4)
  510. // mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  511. if ((flags & TMP_VertexDataUpdateFlags.Colors32) == TMP_VertexDataUpdateFlags.Colors32)
  512. mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  513. mesh.RecalculateBounds();
  514. if (i == 0)
  515. m_canvasRenderer.SetMesh(mesh);
  516. else
  517. m_subTextObjects[i].canvasRenderer.SetMesh(mesh);
  518. }
  519. }
  520. /// <summary>
  521. /// Function to upload the updated vertex data and renderer.
  522. /// </summary>
  523. public override void UpdateVertexData()
  524. {
  525. int materialCount = m_textInfo.materialCount;
  526. for (int i = 0; i < materialCount; i++)
  527. {
  528. Mesh mesh;
  529. if (i == 0)
  530. mesh = m_mesh;
  531. else
  532. {
  533. // Clear unused vertices
  534. m_textInfo.meshInfo[i].ClearUnusedVertices();
  535. mesh = m_subTextObjects[i].mesh;
  536. }
  537. //mesh.MarkDynamic();
  538. mesh.vertices = m_textInfo.meshInfo[i].vertices;
  539. mesh.SetUVs(0, m_textInfo.meshInfo[i].uvs0);
  540. mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  541. //mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  542. mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  543. mesh.RecalculateBounds();
  544. if (i == 0)
  545. m_canvasRenderer.SetMesh(mesh);
  546. else
  547. m_subTextObjects[i].canvasRenderer.SetMesh(mesh);
  548. }
  549. }
  550. public void UpdateFontAsset()
  551. {
  552. LoadFontAsset();
  553. }
  554. #region TMPro_UGUI_Private
  555. [SerializeField]
  556. private bool m_hasFontAssetChanged = false; // Used to track when font properties have changed.
  557. protected TMP_SubMeshUI[] m_subTextObjects = new TMP_SubMeshUI[8];
  558. private float m_previousLossyScaleY = -1; // Used for Tracking lossy scale changes in the transform;
  559. private Vector3[] m_RectTransformCorners = new Vector3[4];
  560. private CanvasRenderer m_canvasRenderer;
  561. private Canvas m_canvas;
  562. private float m_CanvasScaleFactor;
  563. private bool m_isFirstAllocation; // Flag to determine if this is the first allocation of the buffers.
  564. private int m_max_characters = 8; // Determines the initial allocation and size of the character array / buffer.
  565. //private int m_max_numberOfLines = 4; // Determines the initial allocation and maximum number of lines of text.
  566. // MASKING RELATED PROPERTIES
  567. // This property is now obsolete and used for compatibility with previous releases (prior to release 0.1.54).
  568. [SerializeField]
  569. private Material m_baseMaterial;
  570. private bool m_isScrollRegionSet;
  571. //private Mask m_mask;
  572. [SerializeField]
  573. private Vector4 m_maskOffset;
  574. // Matrix used to animated Env Map
  575. private Matrix4x4 m_EnvMapMatrix = new Matrix4x4();
  576. //private bool m_isEnabled;
  577. [NonSerialized]
  578. private bool m_isRegisteredForEvents;
  579. // Profiler Marker declarations
  580. private static ProfilerMarker k_GenerateTextMarker = new ProfilerMarker("TMP.GenerateText");
  581. private static ProfilerMarker k_SetArraySizesMarker = new ProfilerMarker("TMP.SetArraySizes");
  582. private static ProfilerMarker k_GenerateTextPhaseIMarker = new ProfilerMarker("TMP GenerateText - Phase I");
  583. private static ProfilerMarker k_ParseMarkupTextMarker = new ProfilerMarker("TMP Parse Markup Text");
  584. private static ProfilerMarker k_CharacterLookupMarker = new ProfilerMarker("TMP Lookup Character & Glyph Data");
  585. private static ProfilerMarker k_HandleGPOSFeaturesMarker = new ProfilerMarker("TMP Handle GPOS Features");
  586. private static ProfilerMarker k_CalculateVerticesPositionMarker = new ProfilerMarker("TMP Calculate Vertices Position");
  587. private static ProfilerMarker k_ComputeTextMetricsMarker = new ProfilerMarker("TMP Compute Text Metrics");
  588. private static ProfilerMarker k_HandleVisibleCharacterMarker = new ProfilerMarker("TMP Handle Visible Character");
  589. private static ProfilerMarker k_HandleWhiteSpacesMarker = new ProfilerMarker("TMP Handle White Space & Control Character");
  590. private static ProfilerMarker k_HandleHorizontalLineBreakingMarker = new ProfilerMarker("TMP Handle Horizontal Line Breaking");
  591. private static ProfilerMarker k_HandleVerticalLineBreakingMarker = new ProfilerMarker("TMP Handle Vertical Line Breaking");
  592. private static ProfilerMarker k_SaveGlyphVertexDataMarker = new ProfilerMarker("TMP Save Glyph Vertex Data");
  593. private static ProfilerMarker k_ComputeCharacterAdvanceMarker = new ProfilerMarker("TMP Compute Character Advance");
  594. private static ProfilerMarker k_HandleCarriageReturnMarker = new ProfilerMarker("TMP Handle Carriage Return");
  595. private static ProfilerMarker k_HandleLineTerminationMarker = new ProfilerMarker("TMP Handle Line Termination");
  596. private static ProfilerMarker k_SavePageInfoMarker = new ProfilerMarker("TMP Save Page Info");
  597. private static ProfilerMarker k_SaveTextExtentMarker = new ProfilerMarker("TMP Save Text Extent");
  598. private static ProfilerMarker k_SaveProcessingStatesMarker = new ProfilerMarker("TMP Save Processing States");
  599. private static ProfilerMarker k_GenerateTextPhaseIIMarker = new ProfilerMarker("TMP GenerateText - Phase II");
  600. private static ProfilerMarker k_GenerateTextPhaseIIIMarker = new ProfilerMarker("TMP GenerateText - Phase III");
  601. protected override void Awake()
  602. {
  603. //Debug.Log("***** Awake() called on object ID " + GetInstanceID() + ". *****");
  604. #if UNITY_EDITOR
  605. // Special handling for TMP Settings and importing Essential Resources
  606. if (TMP_Settings.instance == null)
  607. {
  608. if (m_isWaitingOnResourceLoad == false)
  609. TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED);
  610. m_isWaitingOnResourceLoad = true;
  611. return;
  612. }
  613. #endif
  614. // Cache Reference to the Canvas
  615. m_canvas = this.canvas;
  616. m_isOrthographic = true;
  617. // Cache Reference to RectTransform.
  618. m_rectTransform = gameObject.GetComponent<RectTransform>();
  619. if (m_rectTransform == null)
  620. m_rectTransform = gameObject.AddComponent<RectTransform>();
  621. // Cache a reference to the CanvasRenderer.
  622. m_canvasRenderer = GetComponent<CanvasRenderer>();
  623. if (m_canvasRenderer == null)
  624. m_canvasRenderer = gameObject.AddComponent<CanvasRenderer> ();
  625. if (m_mesh == null)
  626. {
  627. m_mesh = new Mesh();
  628. m_mesh.hideFlags = HideFlags.HideAndDontSave;
  629. #if DEVELOPMENT_BUILD || UNITY_EDITOR
  630. m_mesh.name = "TextMeshPro UI Mesh";
  631. #endif
  632. // Create new TextInfo for the text object.
  633. m_textInfo = new TMP_TextInfo(this);
  634. }
  635. // Load TMP Settings for new text object instances.
  636. LoadDefaultSettings();
  637. // Load the font asset and assign material to renderer.
  638. LoadFontAsset();
  639. // Allocate our initial buffers.
  640. if (m_TextProcessingArray == null)
  641. m_TextProcessingArray = new TextProcessingElement[m_max_characters];
  642. m_cached_TextElement = new TMP_Character();
  643. m_isFirstAllocation = true;
  644. // Set flags to ensure our text is parsed and redrawn.
  645. m_havePropertiesChanged = true;
  646. m_isAwake = true;
  647. }
  648. protected override void OnEnable()
  649. {
  650. //Debug.Log("***** OnEnable() called on object ID " + GetInstanceID() + ". *****");
  651. // Return if Awake() has not been called on the text object.
  652. if (m_isAwake == false)
  653. return;
  654. if (!m_isRegisteredForEvents)
  655. {
  656. //Debug.Log("Registering for Events.");
  657. #if UNITY_EDITOR
  658. // Register Callbacks for various events.
  659. TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Add(ON_MATERIAL_PROPERTY_CHANGED);
  660. TMPro_EventManager.FONT_PROPERTY_EVENT.Add(ON_FONT_PROPERTY_CHANGED);
  661. TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Add(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
  662. TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Add(ON_DRAG_AND_DROP_MATERIAL);
  663. TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Add(ON_TEXT_STYLE_CHANGED);
  664. TMPro_EventManager.COLOR_GRADIENT_PROPERTY_EVENT.Add(ON_COLOR_GRADIENT_CHANGED);
  665. TMPro_EventManager.TMP_SETTINGS_PROPERTY_EVENT.Add(ON_TMP_SETTINGS_CHANGED);
  666. UnityEditor.PrefabUtility.prefabInstanceUpdated += OnPrefabInstanceUpdate;
  667. #endif
  668. m_isRegisteredForEvents = true;
  669. }
  670. // Cache Reference to the Canvas
  671. m_canvas = GetCanvas();
  672. SetActiveSubMeshes(true);
  673. // Register Graphic Component to receive event triggers
  674. GraphicRegistry.RegisterGraphicForCanvas(m_canvas, this);
  675. // Register text object for internal updates
  676. if (m_IsTextObjectScaleStatic == false)
  677. TMP_UpdateManager.RegisterTextObjectForUpdate(this);
  678. ComputeMarginSize();
  679. SetAllDirty();
  680. RecalculateClipping();
  681. RecalculateMasking();
  682. }
  683. protected override void OnDisable()
  684. {
  685. //Debug.Log("***** OnDisable() called on object ID " + GetInstanceID() + ". *****");
  686. // Return if Awake() has not been called on the text object.
  687. if (m_isAwake == false)
  688. return;
  689. //if (m_MaskMaterial != null)
  690. //{
  691. // TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  692. // m_MaskMaterial = null;
  693. //}
  694. // UnRegister Graphic Component
  695. GraphicRegistry.UnregisterGraphicForCanvas(m_canvas, this);
  696. CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild((ICanvasElement)this);
  697. TMP_UpdateManager.UnRegisterTextObjectForUpdate(this);
  698. if (m_canvasRenderer != null)
  699. m_canvasRenderer.Clear();
  700. SetActiveSubMeshes(false);
  701. LayoutRebuilder.MarkLayoutForRebuild(m_rectTransform);
  702. RecalculateClipping();
  703. RecalculateMasking();
  704. }
  705. protected override void OnDestroy()
  706. {
  707. //Debug.Log("***** OnDestroy() called on object ID " + GetInstanceID() + ". *****");
  708. // UnRegister Graphic Component
  709. GraphicRegistry.UnregisterGraphicForCanvas(m_canvas, this);
  710. TMP_UpdateManager.UnRegisterTextObjectForUpdate(this);
  711. // Clean up remaining mesh
  712. if (m_mesh != null)
  713. DestroyImmediate(m_mesh);
  714. // Clean up mask material
  715. if (m_MaskMaterial != null)
  716. {
  717. TMP_MaterialManager.ReleaseStencilMaterial(m_MaskMaterial);
  718. m_MaskMaterial = null;
  719. }
  720. #if UNITY_EDITOR
  721. // Unregister the event this object was listening to
  722. TMPro_EventManager.MATERIAL_PROPERTY_EVENT.Remove(ON_MATERIAL_PROPERTY_CHANGED);
  723. TMPro_EventManager.FONT_PROPERTY_EVENT.Remove(ON_FONT_PROPERTY_CHANGED);
  724. TMPro_EventManager.TEXTMESHPRO_UGUI_PROPERTY_EVENT.Remove(ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED);
  725. TMPro_EventManager.DRAG_AND_DROP_MATERIAL_EVENT.Remove(ON_DRAG_AND_DROP_MATERIAL);
  726. TMPro_EventManager.TEXT_STYLE_PROPERTY_EVENT.Remove(ON_TEXT_STYLE_CHANGED);
  727. TMPro_EventManager.COLOR_GRADIENT_PROPERTY_EVENT.Remove(ON_COLOR_GRADIENT_CHANGED);
  728. TMPro_EventManager.TMP_SETTINGS_PROPERTY_EVENT.Remove(ON_TMP_SETTINGS_CHANGED);
  729. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  730. UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabInstanceUpdate;
  731. #endif
  732. m_isRegisteredForEvents = false;
  733. }
  734. #if UNITY_EDITOR
  735. protected override void Reset()
  736. {
  737. //Debug.Log("***** Reset() *****"); //has been called.");
  738. // Return if Awake() has not been called on the text object.
  739. if (m_isAwake == false)
  740. return;
  741. LoadDefaultSettings();
  742. LoadFontAsset();
  743. m_havePropertiesChanged = true;
  744. }
  745. protected override void OnValidate()
  746. {
  747. //Debug.Log("***** OnValidate() ***** Frame:" + Time.frameCount); // ID " + GetInstanceID()); // New Material [" + m_sharedMaterial.name + "] with ID " + m_sharedMaterial.GetInstanceID() + ". Base Material is [" + m_baseMaterial.name + "] with ID " + m_baseMaterial.GetInstanceID() + ". Previous Base Material is [" + (m_lastBaseMaterial == null ? "Null" : m_lastBaseMaterial.name) + "].");
  748. if (m_isAwake == false)
  749. return;
  750. // Handle Font Asset changes in the inspector.
  751. if (m_fontAsset == null || m_hasFontAssetChanged)
  752. {
  753. LoadFontAsset();
  754. m_hasFontAssetChanged = false;
  755. }
  756. if (m_canvasRenderer == null || m_canvasRenderer.GetMaterial() == null || m_canvasRenderer.GetMaterial().GetTexture(ShaderUtilities.ID_MainTex) == null || m_fontAsset == null || m_fontAsset.atlasTexture.GetInstanceID() != m_canvasRenderer.GetMaterial().GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  757. {
  758. LoadFontAsset();
  759. m_hasFontAssetChanged = false;
  760. }
  761. m_padding = GetPaddingForMaterial();
  762. ComputeMarginSize();
  763. m_inputSource = TextInputSources.TextInputBox;
  764. m_havePropertiesChanged = true;
  765. m_isPreferredWidthDirty = true;
  766. m_isPreferredHeightDirty = true;
  767. SetAllDirty();
  768. }
  769. /// <summary>
  770. /// Callback received when Prefabs are updated.
  771. /// </summary>
  772. /// <param name="go">The affected GameObject</param>
  773. void OnPrefabInstanceUpdate(GameObject go)
  774. {
  775. // Remove Callback if this prefab has been deleted.
  776. if (this == null)
  777. {
  778. UnityEditor.PrefabUtility.prefabInstanceUpdated -= OnPrefabInstanceUpdate;
  779. return;
  780. }
  781. if (go == this.gameObject)
  782. {
  783. TMP_SubMeshUI[] subTextObjects = GetComponentsInChildren<TMP_SubMeshUI>();
  784. if (subTextObjects.Length > 0)
  785. {
  786. for (int i = 0; i < subTextObjects.Length; i++)
  787. m_subTextObjects[i + 1] = subTextObjects[i];
  788. }
  789. }
  790. }
  791. // Event received when TMP resources have been loaded.
  792. void ON_RESOURCES_LOADED()
  793. {
  794. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  795. if (this == null)
  796. return;
  797. m_isWaitingOnResourceLoad = false;
  798. Awake();
  799. OnEnable();
  800. }
  801. // Event received when custom material editor properties are changed.
  802. void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat)
  803. {
  804. //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED event received."); // Targeted Material is: " + mat.name + " m_sharedMaterial: " + m_sharedMaterial.name + " with ID:" + m_sharedMaterial.GetInstanceID() + " m_renderer.sharedMaterial: " + m_canvasRenderer.GetMaterial() + " Masking Material:" + m_MaskMaterial.GetInstanceID());
  805. ShaderUtilities.GetShaderPropertyIDs(); // Initialize ShaderUtilities and get shader property IDs.
  806. int materialID = mat.GetInstanceID();
  807. int sharedMaterialID = m_sharedMaterial.GetInstanceID();
  808. int maskingMaterialID = m_MaskMaterial == null ? 0 : m_MaskMaterial.GetInstanceID();
  809. if (m_canvasRenderer == null || m_canvasRenderer.GetMaterial() == null)
  810. {
  811. if (m_canvasRenderer == null) return;
  812. if (m_fontAsset != null)
  813. {
  814. m_canvasRenderer.SetMaterial(m_fontAsset.material, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  815. //Debug.LogWarning("No Material was assigned to " + name + ". " + m_fontAsset.material.name + " was assigned.");
  816. }
  817. else
  818. Debug.LogWarning("No Font Asset assigned to " + name + ". Please assign a Font Asset.", this);
  819. }
  820. if (m_canvasRenderer.GetMaterial() != m_sharedMaterial && m_fontAsset == null) // || m_renderer.sharedMaterials.Contains(mat))
  821. {
  822. //Debug.Log("ON_MATERIAL_PROPERTY_CHANGED Called on Target ID: " + GetInstanceID() + ". Previous Material:" + m_sharedMaterial + " New Material:" + m_uiRenderer.GetMaterial()); // on Object ID:" + GetInstanceID() + ". m_sharedMaterial: " + m_sharedMaterial.name + " m_renderer.sharedMaterial: " + m_renderer.sharedMaterial.name);
  823. m_sharedMaterial = m_canvasRenderer.GetMaterial();
  824. }
  825. // Make sure material properties are synchronized between the assigned material and masking material.
  826. if (m_MaskMaterial != null)
  827. {
  828. UnityEditor.Undo.RecordObject(m_MaskMaterial, "Material Property Changes");
  829. UnityEditor.Undo.RecordObject(m_sharedMaterial, "Material Property Changes");
  830. if (materialID == sharedMaterialID)
  831. {
  832. //Debug.Log("Copy base material properties to masking material if not null.");
  833. float stencilID = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilID);
  834. float stencilComp = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilComp);
  835. //float stencilOp = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilOp);
  836. //float stencilRead = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilReadMask);
  837. //float stencilWrite = m_MaskMaterial.GetFloat(ShaderUtilities.ID_StencilWriteMask);
  838. m_MaskMaterial.CopyPropertiesFromMaterial(mat);
  839. m_MaskMaterial.shaderKeywords = mat.shaderKeywords;
  840. m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilID, stencilID);
  841. m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilComp, stencilComp);
  842. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilOp, stencilOp);
  843. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilReadMask, stencilID);
  844. //m_MaskMaterial.SetFloat(ShaderUtilities.ID_StencilWriteMask, 0);
  845. }
  846. else if (materialID == maskingMaterialID)
  847. {
  848. // Update the padding
  849. GetPaddingForMaterial(mat);
  850. m_sharedMaterial.CopyPropertiesFromMaterial(mat);
  851. m_sharedMaterial.shaderKeywords = mat.shaderKeywords;
  852. m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilID, 0);
  853. m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilComp, 8);
  854. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilOp, 0);
  855. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilReadMask, 255);
  856. //m_sharedMaterial.SetFloat(ShaderUtilities.ID_StencilWriteMask, 255);
  857. }
  858. }
  859. m_padding = GetPaddingForMaterial();
  860. m_havePropertiesChanged = true;
  861. SetVerticesDirty();
  862. //SetMaterialDirty();
  863. }
  864. // Event received when font asset properties are changed in Font Inspector
  865. void ON_FONT_PROPERTY_CHANGED(bool isChanged, Object font)
  866. {
  867. //if (MaterialReference.Contains(m_materialReferences, (TMP_FontAsset) font))
  868. {
  869. //Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
  870. m_havePropertiesChanged = true;
  871. UpdateMeshPadding();
  872. SetLayoutDirty();
  873. SetVerticesDirty();
  874. }
  875. }
  876. // Event received when UNDO / REDO Event alters the properties of the object.
  877. void ON_TEXTMESHPRO_UGUI_PROPERTY_CHANGED(bool isChanged, Object obj)
  878. {
  879. //Debug.Log("Event Received by " + obj);
  880. if (obj == this)
  881. {
  882. //Debug.Log("Undo / Redo Event Received by Object ID:" + GetInstanceID());
  883. m_havePropertiesChanged = true;
  884. ComputeMarginSize(); // Review this change
  885. SetVerticesDirty();
  886. }
  887. }
  888. // Event to Track Material Changed resulting from Drag-n-drop.
  889. void ON_DRAG_AND_DROP_MATERIAL(GameObject obj, Material currentMaterial, Material newMaterial)
  890. {
  891. //Debug.Log("Drag-n-Drop Event - Receiving Object ID " + GetInstanceID() + ". Sender ID " + obj.GetInstanceID()); // + ". Prefab Parent is " + UnityEditor.PrefabUtility.GetPrefabParent(gameObject).GetInstanceID()); // + ". New Material is " + newMaterial.name + " with ID " + newMaterial.GetInstanceID() + ". Base Material is " + m_baseMaterial.name + " with ID " + m_baseMaterial.GetInstanceID());
  892. // Check if event applies to this current object
  893. if (obj == gameObject || UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(gameObject) == obj)
  894. {
  895. UnityEditor.Undo.RecordObject(this, "Material Assignment");
  896. UnityEditor.Undo.RecordObject(m_canvasRenderer, "Material Assignment");
  897. m_sharedMaterial = newMaterial;
  898. m_padding = GetPaddingForMaterial();
  899. m_havePropertiesChanged = true;
  900. SetVerticesDirty();
  901. SetMaterialDirty();
  902. }
  903. }
  904. // Event received when Text Styles are changed.
  905. void ON_TEXT_STYLE_CHANGED(bool isChanged)
  906. {
  907. m_havePropertiesChanged = true;
  908. SetVerticesDirty();
  909. }
  910. /// <summary>
  911. /// Event received when a Color Gradient Preset is modified.
  912. /// </summary>
  913. /// <param name="textObject"></param>
  914. void ON_COLOR_GRADIENT_CHANGED(Object gradient)
  915. {
  916. m_havePropertiesChanged = true;
  917. SetVerticesDirty();
  918. }
  919. /// <summary>
  920. /// Event received when the TMP Settings are changed.
  921. /// </summary>
  922. void ON_TMP_SETTINGS_CHANGED()
  923. {
  924. m_defaultSpriteAsset = null;
  925. m_havePropertiesChanged = true;
  926. SetAllDirty();
  927. }
  928. #endif
  929. // Function which loads either the default font or a newly assigned font asset. This function also assigned the appropriate material to the renderer.
  930. protected override void LoadFontAsset()
  931. {
  932. //Debug.Log("***** LoadFontAsset() *****"); //TextMeshPro LoadFontAsset() has been called."); // Current Font Asset is " + (font != null ? font.name: "Null") );
  933. ShaderUtilities.GetShaderPropertyIDs(); // Initialize & Get shader property IDs.
  934. if (m_fontAsset == null)
  935. {
  936. if (TMP_Settings.defaultFontAsset != null)
  937. m_fontAsset = TMP_Settings.defaultFontAsset;
  938. if (m_fontAsset == null)
  939. {
  940. Debug.LogWarning("The LiberationSans SDF Font Asset was not found. There is no Font Asset assigned to " + gameObject.name + ".", this);
  941. return;
  942. }
  943. if (m_fontAsset.characterLookupTable == null)
  944. {
  945. Debug.Log("Dictionary is Null!");
  946. }
  947. m_sharedMaterial = m_fontAsset.material;
  948. }
  949. else
  950. {
  951. // Read font definition if needed.
  952. if (m_fontAsset.characterLookupTable == null)
  953. m_fontAsset.ReadFontAssetDefinition();
  954. // Added for compatibility with previous releases.
  955. if (m_sharedMaterial == null && m_baseMaterial != null)
  956. {
  957. m_sharedMaterial = m_baseMaterial;
  958. m_baseMaterial = null;
  959. }
  960. // If font atlas texture doesn't match the assigned material font atlas, switch back to default material specified in the Font Asset.
  961. if (m_sharedMaterial == null || m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex) == null || m_fontAsset.atlasTexture.GetInstanceID() != m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  962. {
  963. if (m_fontAsset.material == null)
  964. Debug.LogWarning("The Font Atlas Texture of the Font Asset " + m_fontAsset.name + " assigned to " + gameObject.name + " is missing.", this);
  965. else
  966. m_sharedMaterial = m_fontAsset.material;
  967. }
  968. }
  969. // Find and cache Underline & Ellipsis characters.
  970. GetSpecialCharacters(m_fontAsset);
  971. m_padding = GetPaddingForMaterial();
  972. SetMaterialDirty();
  973. }
  974. /// <summary>
  975. /// Method to retrieve the parent Canvas.
  976. /// </summary>
  977. private Canvas GetCanvas()
  978. {
  979. Canvas canvas = null;
  980. var list = TMP_ListPool<Canvas>.Get();
  981. gameObject.GetComponentsInParent(false, list);
  982. if (list.Count > 0)
  983. {
  984. // Find the first active and enabled canvas.
  985. for (int i = 0; i < list.Count; ++i)
  986. {
  987. if (list[i].isActiveAndEnabled)
  988. {
  989. canvas = list[i];
  990. break;
  991. }
  992. }
  993. }
  994. TMP_ListPool<Canvas>.Release(list);
  995. return canvas;
  996. }
  997. /// <summary>
  998. /// Method used when animating the Env Map on the material.
  999. /// </summary>
  1000. void UpdateEnvMapMatrix()
  1001. {
  1002. if (!m_sharedMaterial.HasProperty(ShaderUtilities.ID_EnvMap) || m_sharedMaterial.GetTexture(ShaderUtilities.ID_EnvMap) == null)
  1003. return;
  1004. //Debug.Log("Updating Env Matrix...");
  1005. Vector3 rotation = m_sharedMaterial.GetVector(ShaderUtilities.ID_EnvMatrixRotation);
  1006. m_EnvMapMatrix = Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(rotation), Vector3.one);
  1007. m_sharedMaterial.SetMatrix(ShaderUtilities.ID_EnvMatrix, m_EnvMapMatrix);
  1008. }
  1009. // Enable Masking in the Shader
  1010. void EnableMasking()
  1011. {
  1012. if (m_fontMaterial == null)
  1013. {
  1014. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  1015. m_canvasRenderer.SetMaterial(m_fontMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  1016. }
  1017. m_sharedMaterial = m_fontMaterial;
  1018. if (m_sharedMaterial.HasProperty(ShaderUtilities.ID_ClipRect))
  1019. {
  1020. m_sharedMaterial.EnableKeyword(ShaderUtilities.Keyword_MASK_SOFT);
  1021. m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_HARD);
  1022. m_sharedMaterial.DisableKeyword(ShaderUtilities.Keyword_MASK_TEX);
  1023. UpdateMask(); // Update Masking Coordinates
  1024. }
  1025. m_isMaskingEnabled = true;
  1026. //m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  1027. //m_padding = ShaderUtilities.GetPadding(m_sharedMaterial, m_enableExtraPadding, m_isUsingBold);
  1028. //m_alignmentPadding = ShaderUtilities.GetFontExtent(m_sharedMaterial);
  1029. /*
  1030. Material mat = m_uiRenderer.GetMaterial();
  1031. if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
  1032. {
  1033. mat.EnableKeyword("MASK_SOFT");
  1034. mat.DisableKeyword("MASK_HARD");
  1035. mat.DisableKeyword("MASK_OFF");
  1036. m_isMaskingEnabled = true;
  1037. UpdateMask();
  1038. }
  1039. */
  1040. }
  1041. // Enable Masking in the Shader
  1042. void DisableMasking()
  1043. {
  1044. /*
  1045. if (m_fontMaterial != null)
  1046. {
  1047. if (m_stencilID > 0)
  1048. m_sharedMaterial = m_MaskMaterial;
  1049. else
  1050. m_sharedMaterial = m_baseMaterial;
  1051. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  1052. DestroyImmediate(m_fontMaterial);
  1053. }
  1054. m_isMaskingEnabled = false;
  1055. */
  1056. /*
  1057. if (m_maskingMaterial != null && m_stencilID == 0)
  1058. {
  1059. m_sharedMaterial = m_baseMaterial;
  1060. m_uiRenderer.SetMaterial(m_sharedMaterial, null);
  1061. }
  1062. else if (m_stencilID > 0)
  1063. {
  1064. m_sharedMaterial.EnableKeyword("MASK_OFF");
  1065. m_sharedMaterial.DisableKeyword("MASK_HARD");
  1066. m_sharedMaterial.DisableKeyword("MASK_SOFT");
  1067. }
  1068. */
  1069. /*
  1070. Material mat = m_uiRenderer.GetMaterial();
  1071. if (mat.HasProperty(ShaderUtilities.ID_MaskCoord))
  1072. {
  1073. mat.EnableKeyword("MASK_OFF");
  1074. mat.DisableKeyword("MASK_HARD");
  1075. mat.DisableKeyword("MASK_SOFT");
  1076. m_isMaskingEnabled = false;
  1077. UpdateMask();
  1078. }
  1079. */
  1080. }
  1081. // Update & recompute Mask offset
  1082. void UpdateMask()
  1083. {
  1084. //Debug.Log("Updating Mask...");
  1085. if (m_rectTransform != null)
  1086. {
  1087. //Material mat = m_uiRenderer.GetMaterial();
  1088. //if (mat == null || (m_overflowMode == TextOverflowModes.ScrollRect && m_isScrollRegionSet))
  1089. // return;
  1090. if (!ShaderUtilities.isInitialized)
  1091. ShaderUtilities.GetShaderPropertyIDs();
  1092. //Debug.Log("Setting Mask for the first time.");
  1093. m_isScrollRegionSet = true;
  1094. float softnessX = Mathf.Min(Mathf.Min(m_margin.x, m_margin.z), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX));
  1095. float softnessY = Mathf.Min(Mathf.Min(m_margin.y, m_margin.w), m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessY));
  1096. softnessX = softnessX > 0 ? softnessX : 0;
  1097. softnessY = softnessY > 0 ? softnessY : 0;
  1098. float width = (m_rectTransform.rect.width - Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2 + softnessX;
  1099. float height = (m_rectTransform.rect.height - Mathf.Max(m_margin.y, 0) - Mathf.Max(m_margin.w, 0)) / 2 + softnessY;
  1100. Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (Mathf.Max(m_margin.x, 0) - Mathf.Max(m_margin.z, 0)) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-Mathf.Max(m_margin.y, 0) + Mathf.Max(m_margin.w, 0)) / 2);
  1101. //Vector2 center = m_rectTransform.localPosition + new Vector3((0.5f - m_rectTransform.pivot.x) * m_rectTransform.rect.width + (margin.x - margin.z) / 2, (0.5f - m_rectTransform.pivot.y) * m_rectTransform.rect.height + (-margin.y + margin.w) / 2);
  1102. Vector4 mask = new Vector4(center.x, center.y, width, height);
  1103. //Debug.Log(mask);
  1104. //Rect rect = new Rect(0, 0, m_rectTransform.rect.width + margin.x + margin.z, m_rectTransform.rect.height + margin.y + margin.w);
  1105. //int softness = (int)m_sharedMaterial.GetFloat(ShaderUtilities.ID_MaskSoftnessX) / 2;
  1106. m_sharedMaterial.SetVector(ShaderUtilities.ID_ClipRect, mask);
  1107. }
  1108. }
  1109. // Function called internally when a new material is assigned via the fontMaterial property.
  1110. protected override Material GetMaterial(Material mat)
  1111. {
  1112. // Get Shader PropertyIDs if they haven't been cached already.
  1113. ShaderUtilities.GetShaderPropertyIDs();
  1114. // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
  1115. // This can occur when the Duplicate Material Context menu is used on an inactive object.
  1116. //if (m_canvasRenderer == null)
  1117. // m_canvasRenderer = GetComponent<CanvasRenderer>();
  1118. // Create Instance Material only if the new material is not the same instance previously used.
  1119. if (m_fontMaterial == null || m_fontMaterial.GetInstanceID() != mat.GetInstanceID())
  1120. m_fontMaterial = CreateMaterialInstance(mat);
  1121. m_sharedMaterial = m_fontMaterial;
  1122. m_padding = GetPaddingForMaterial();
  1123. m_ShouldRecalculateStencil = true;
  1124. SetVerticesDirty();
  1125. SetMaterialDirty();
  1126. return m_sharedMaterial;
  1127. }
  1128. /// <summary>
  1129. /// Method returning instances of the materials used by the text object.
  1130. /// </summary>
  1131. /// <returns></returns>
  1132. protected override Material[] GetMaterials(Material[] mats)
  1133. {
  1134. int materialCount = m_textInfo.materialCount;
  1135. if (m_fontMaterials == null)
  1136. m_fontMaterials = new Material[materialCount];
  1137. else if (m_fontMaterials.Length != materialCount)
  1138. TMP_TextInfo.Resize(ref m_fontMaterials, materialCount, false);
  1139. // Get instances of the materials
  1140. for (int i = 0; i < materialCount; i++)
  1141. {
  1142. if (i == 0)
  1143. m_fontMaterials[i] = fontMaterial;
  1144. else
  1145. m_fontMaterials[i] = m_subTextObjects[i].material;
  1146. }
  1147. m_fontSharedMaterials = m_fontMaterials;
  1148. return m_fontMaterials;
  1149. }
  1150. // Function called internally when a new shared material is assigned via the fontSharedMaterial property.
  1151. protected override void SetSharedMaterial(Material mat)
  1152. {
  1153. // Check in case Object is disabled. If so, we don't have a valid reference to the Renderer.
  1154. // This can occur when the Duplicate Material Context menu is used on an inactive object.
  1155. //if (m_canvasRenderer == null)
  1156. // m_canvasRenderer = GetComponent<CanvasRenderer>();
  1157. m_sharedMaterial = mat;
  1158. m_padding = GetPaddingForMaterial();
  1159. SetMaterialDirty();
  1160. }
  1161. /// <summary>
  1162. /// Method returning an array containing the materials used by the text object.
  1163. /// </summary>
  1164. /// <returns></returns>
  1165. protected override Material[] GetSharedMaterials()
  1166. {
  1167. int materialCount = m_textInfo.materialCount;
  1168. if (m_fontSharedMaterials == null)
  1169. m_fontSharedMaterials = new Material[materialCount];
  1170. else if (m_fontSharedMaterials.Length != materialCount)
  1171. TMP_TextInfo.Resize(ref m_fontSharedMaterials, materialCount, false);
  1172. for (int i = 0; i < materialCount; i++)
  1173. {
  1174. if (i == 0)
  1175. m_fontSharedMaterials[i] = m_sharedMaterial;
  1176. else
  1177. m_fontSharedMaterials[i] = m_subTextObjects[i].sharedMaterial;
  1178. }
  1179. return m_fontSharedMaterials;
  1180. }
  1181. /// <summary>
  1182. /// Method used to assign new materials to the text and sub text objects.
  1183. /// </summary>
  1184. protected override void SetSharedMaterials(Material[] materials)
  1185. {
  1186. int materialCount = m_textInfo.materialCount;
  1187. // Check allocation of the fontSharedMaterials array.
  1188. if (m_fontSharedMaterials == null)
  1189. m_fontSharedMaterials = new Material[materialCount];
  1190. else if (m_fontSharedMaterials.Length != materialCount)
  1191. TMP_TextInfo.Resize(ref m_fontSharedMaterials, materialCount, false);
  1192. // Only assign as many materials as the text object contains.
  1193. for (int i = 0; i < materialCount; i++)
  1194. {
  1195. if (i == 0)
  1196. {
  1197. // Only assign new material if the font atlas textures match.
  1198. if (materials[i].GetTexture(ShaderUtilities.ID_MainTex) == null || materials[i].GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  1199. continue;
  1200. m_sharedMaterial = m_fontSharedMaterials[i] = materials[i];
  1201. m_padding = GetPaddingForMaterial(m_sharedMaterial);
  1202. }
  1203. else
  1204. {
  1205. // Only assign new material if the font atlas textures match.
  1206. if (materials[i].GetTexture(ShaderUtilities.ID_MainTex) == null || materials[i].GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID() != m_subTextObjects[i].sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex).GetInstanceID())
  1207. continue;
  1208. // Only assign a new material if none were specified in the text input.
  1209. if (m_subTextObjects[i].isDefaultMaterial)
  1210. m_subTextObjects[i].sharedMaterial = m_fontSharedMaterials[i] = materials[i];
  1211. }
  1212. }
  1213. }
  1214. // This function will create an instance of the Font Material.
  1215. protected override void SetOutlineThickness(float thickness)
  1216. {
  1217. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  1218. if (m_fontMaterial != null && m_sharedMaterial.GetInstanceID() != m_fontMaterial.GetInstanceID())
  1219. {
  1220. m_sharedMaterial = m_fontMaterial;
  1221. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  1222. }
  1223. else if(m_fontMaterial == null)
  1224. {
  1225. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  1226. m_sharedMaterial = m_fontMaterial;
  1227. m_canvasRenderer.SetMaterial(m_sharedMaterial, m_sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex));
  1228. }
  1229. thickness = Mathf.Clamp01(thickness);
  1230. m_sharedMaterial.SetFloat(ShaderUtilities.ID_OutlineWidth, thickness);
  1231. m_padding = GetPaddingForMaterial();
  1232. }
  1233. // This function will create an instance of the Font Material.
  1234. protected override void SetFaceColor(Color32 color)
  1235. {
  1236. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  1237. if (m_fontMaterial == null)
  1238. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  1239. m_sharedMaterial = m_fontMaterial;
  1240. m_padding = GetPaddingForMaterial();
  1241. m_sharedMaterial.SetColor(ShaderUtilities.ID_FaceColor, color);
  1242. }
  1243. // This function will create an instance of the Font Material.
  1244. protected override void SetOutlineColor(Color32 color)
  1245. {
  1246. // Use material instance if one exists. Otherwise, create a new instance of the shared material.
  1247. if (m_fontMaterial == null)
  1248. m_fontMaterial = CreateMaterialInstance(m_sharedMaterial);
  1249. m_sharedMaterial = m_fontMaterial;
  1250. m_padding = GetPaddingForMaterial();
  1251. m_sharedMaterial.SetColor(ShaderUtilities.ID_OutlineColor, color);
  1252. }
  1253. // Sets the Render Queue and Ztest mode
  1254. protected override void SetShaderDepth()
  1255. {
  1256. if (m_canvas == null || m_sharedMaterial == null)
  1257. return;
  1258. if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay || m_isOverlay)
  1259. {
  1260. // Should this use an instanced material?
  1261. //m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 0);
  1262. }
  1263. else
  1264. { // TODO: This section needs to be tested.
  1265. //m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_ZTestMode, 4);
  1266. }
  1267. }
  1268. // Sets the Culling mode of the material
  1269. protected override void SetCulling()
  1270. {
  1271. if (m_isCullingEnabled)
  1272. {
  1273. Material mat = materialForRendering;
  1274. if (mat != null)
  1275. mat.SetFloat("_CullMode", 2);
  1276. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  1277. {
  1278. mat = m_subTextObjects[i].materialForRendering;
  1279. if (mat != null)
  1280. {
  1281. mat.SetFloat(ShaderUtilities.ShaderTag_CullMode, 2);
  1282. }
  1283. }
  1284. }
  1285. else
  1286. {
  1287. Material mat = materialForRendering;
  1288. if (mat != null)
  1289. mat.SetFloat("_CullMode", 0);
  1290. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  1291. {
  1292. mat = m_subTextObjects[i].materialForRendering;
  1293. if (mat != null)
  1294. {
  1295. mat.SetFloat(ShaderUtilities.ShaderTag_CullMode, 0);
  1296. }
  1297. }
  1298. }
  1299. }
  1300. // Set Perspective Correction Mode based on whether Camera is Orthographic or Perspective
  1301. void SetPerspectiveCorrection()
  1302. {
  1303. if (m_isOrthographic)
  1304. m_sharedMaterial.SetFloat(ShaderUtilities.ID_PerspectiveFilter, 0.0f);
  1305. else
  1306. m_sharedMaterial.SetFloat(ShaderUtilities.ID_PerspectiveFilter, 0.875f);
  1307. }
  1308. // Function to allocate the necessary buffers to render the text. This function is called whenever the buffer size needs to be increased.
  1309. void SetMeshArrays(int size)
  1310. {
  1311. m_textInfo.meshInfo[0].ResizeMeshInfo(size);
  1312. m_canvasRenderer.SetMesh(m_textInfo.meshInfo[0].mesh);
  1313. }
  1314. // This function parses through the Char[] to determine how many characters will be visible. It then makes sure the arrays are large enough for all those characters.
  1315. internal override int SetArraySizes(TextProcessingElement[] textProcessingArray)
  1316. {
  1317. k_SetArraySizesMarker.Begin();
  1318. int spriteCount = 0;
  1319. m_totalCharacterCount = 0;
  1320. m_isUsingBold = false;
  1321. m_isTextLayoutPhase = false;
  1322. tag_NoParsing = false;
  1323. m_FontStyleInternal = m_fontStyle;
  1324. m_fontStyleStack.Clear();
  1325. m_FontWeightInternal = (m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold ? FontWeight.Bold : m_fontWeight;
  1326. m_FontWeightStack.SetDefault(m_FontWeightInternal);
  1327. m_currentFontAsset = m_fontAsset;
  1328. m_currentMaterial = m_sharedMaterial;
  1329. m_currentMaterialIndex = 0;
  1330. m_materialReferenceStack.SetDefault(new MaterialReference(m_currentMaterialIndex, m_currentFontAsset, null, m_currentMaterial, m_padding));
  1331. m_materialReferenceIndexLookup.Clear();
  1332. MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, ref m_materialReferences, m_materialReferenceIndexLookup);
  1333. // Set allocations for the text object's TextInfo
  1334. if (m_textInfo == null)
  1335. m_textInfo = new TMP_TextInfo(m_InternalTextProcessingArraySize);
  1336. else if (m_textInfo.characterInfo.Length < m_InternalTextProcessingArraySize)
  1337. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_InternalTextProcessingArraySize, false);
  1338. m_textElementType = TMP_TextElementType.Character;
  1339. // Handling for Underline special character
  1340. #region Setup Underline Special Character
  1341. /*
  1342. GetUnderlineSpecialCharacter(m_currentFontAsset);
  1343. if (m_Underline.character != null)
  1344. {
  1345. if (m_Underline.fontAsset.GetInstanceID() != m_currentFontAsset.GetInstanceID())
  1346. {
  1347. if (TMP_Settings.matchMaterialPreset && m_currentMaterial.GetInstanceID() != m_Underline.fontAsset.material.GetInstanceID())
  1348. m_Underline.material = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_Underline.fontAsset.material);
  1349. else
  1350. m_Underline.material = m_Underline.fontAsset.material;
  1351. m_Underline.materialIndex = MaterialReference.AddMaterialReference(m_Underline.material, m_Underline.fontAsset, m_materialReferences, m_materialReferenceIndexLookup);
  1352. m_materialReferences[m_Underline.materialIndex].referenceCount = 0;
  1353. }
  1354. }
  1355. */
  1356. #endregion
  1357. // Handling for Ellipsis special character
  1358. #region Setup Ellipsis Special Character
  1359. if (m_overflowMode == TextOverflowModes.Ellipsis)
  1360. {
  1361. GetEllipsisSpecialCharacter(m_currentFontAsset);
  1362. if (m_Ellipsis.character != null)
  1363. {
  1364. if (m_Ellipsis.fontAsset.GetInstanceID() != m_currentFontAsset.GetInstanceID())
  1365. {
  1366. if (TMP_Settings.matchMaterialPreset && m_currentMaterial.GetInstanceID() != m_Ellipsis.fontAsset.material.GetInstanceID())
  1367. m_Ellipsis.material = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_Ellipsis.fontAsset.material);
  1368. else
  1369. m_Ellipsis.material = m_Ellipsis.fontAsset.material;
  1370. m_Ellipsis.materialIndex = MaterialReference.AddMaterialReference(m_Ellipsis.material, m_Ellipsis.fontAsset, ref m_materialReferences, m_materialReferenceIndexLookup);
  1371. m_materialReferences[m_Ellipsis.materialIndex].referenceCount = 0;
  1372. }
  1373. }
  1374. else
  1375. {
  1376. m_overflowMode = TextOverflowModes.Truncate;
  1377. if (!TMP_Settings.warningsDisabled)
  1378. Debug.LogWarning("The character used for Ellipsis is not available in font asset [" + m_currentFontAsset.name + "] or any potential fallbacks. Switching Text Overflow mode to Truncate.", this);
  1379. }
  1380. }
  1381. #endregion
  1382. // Check if we should process Ligatures
  1383. bool ligature = m_ActiveFontFeatures.Contains(OTL_FeatureTag.liga);
  1384. // Clear Linked Text object content if we have any.
  1385. if (m_overflowMode == TextOverflowModes.Linked && m_linkedTextComponent != null && !m_isCalculatingPreferredValues)
  1386. {
  1387. TMP_Text linkedComponent = m_linkedTextComponent;
  1388. while (linkedComponent != null)
  1389. {
  1390. linkedComponent.text = String.Empty;
  1391. linkedComponent.ClearMesh();
  1392. linkedComponent.textInfo.Clear();
  1393. linkedComponent = linkedComponent.linkedTextComponent;
  1394. }
  1395. }
  1396. // Parsing XML tags in the text
  1397. for (int i = 0; i < textProcessingArray.Length && textProcessingArray[i].unicode != 0; i++)
  1398. {
  1399. //Make sure the characterInfo array can hold the next text element.
  1400. if (m_textInfo.characterInfo == null || m_totalCharacterCount >= m_textInfo.characterInfo.Length)
  1401. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, m_totalCharacterCount + 1, true);
  1402. uint unicode = textProcessingArray[i].unicode;
  1403. // PARSE XML TAGS
  1404. #region PARSE XML TAGS
  1405. if (m_isRichText && unicode == 60) // if Char '<'
  1406. {
  1407. int prev_MaterialIndex = m_currentMaterialIndex;
  1408. int endTagIndex;
  1409. // Check if Tag is Valid
  1410. if (ValidateHtmlTag(textProcessingArray, i + 1, out endTagIndex))
  1411. {
  1412. int tagStartIndex = textProcessingArray[i].stringIndex;
  1413. i = endTagIndex;
  1414. if ((m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold)
  1415. m_isUsingBold = true;
  1416. if (m_textElementType == TMP_TextElementType.Sprite)
  1417. {
  1418. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1419. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)(57344 + m_spriteIndex);
  1420. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  1421. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  1422. m_textInfo.characterInfo[m_totalCharacterCount].textElement = m_currentSpriteAsset.spriteCharacterTable[m_spriteIndex];
  1423. m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType;
  1424. m_textInfo.characterInfo[m_totalCharacterCount].index = tagStartIndex;
  1425. m_textInfo.characterInfo[m_totalCharacterCount].stringLength = textProcessingArray[i].stringIndex - tagStartIndex + 1;
  1426. // Restore element type and material index to previous values.
  1427. m_textElementType = TMP_TextElementType.Character;
  1428. m_currentMaterialIndex = prev_MaterialIndex;
  1429. spriteCount += 1;
  1430. m_totalCharacterCount += 1;
  1431. }
  1432. continue;
  1433. }
  1434. }
  1435. #endregion
  1436. bool isUsingAlternativeTypeface = false;
  1437. bool isUsingFallbackOrAlternativeTypeface = false;
  1438. TMP_FontAsset prev_fontAsset = m_currentFontAsset;
  1439. Material prev_material = m_currentMaterial;
  1440. int prev_materialIndex = m_currentMaterialIndex;
  1441. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  1442. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  1443. if (m_textElementType == TMP_TextElementType.Character)
  1444. {
  1445. if ((m_FontStyleInternal & FontStyles.UpperCase) == FontStyles.UpperCase)
  1446. {
  1447. // If this character is lowercase, switch to uppercase.
  1448. if (char.IsLower((char)unicode))
  1449. unicode = char.ToUpper((char)unicode);
  1450. }
  1451. else if ((m_FontStyleInternal & FontStyles.LowerCase) == FontStyles.LowerCase)
  1452. {
  1453. // If this character is uppercase, switch to lowercase.
  1454. if (char.IsUpper((char)unicode))
  1455. unicode = char.ToLower((char)unicode);
  1456. }
  1457. else if ((m_FontStyleInternal & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  1458. {
  1459. // Only convert lowercase characters to uppercase.
  1460. if (char.IsLower((char)unicode))
  1461. unicode = char.ToUpper((char)unicode);
  1462. }
  1463. }
  1464. #endregion
  1465. // Lookup the Glyph data for each character and cache it.
  1466. #region LOOKUP GLYPH
  1467. TMP_TextElement character = null;
  1468. uint nextCharacter = i + 1 < textProcessingArray.Length ? textProcessingArray[i + 1].unicode : 0;
  1469. // Check Emoji Fallback first in the event the requested unicode code point is an Emoji
  1470. if (emojiFallbackSupport && ((TMP_TextParsingUtilities.IsEmojiPresentationForm(unicode) && nextCharacter != 0xFE0E) || (TMP_TextParsingUtilities.IsEmoji(unicode) && nextCharacter == 0xFE0F)))
  1471. {
  1472. if (TMP_Settings.emojiFallbackTextAssets != null && TMP_Settings.emojiFallbackTextAssets.Count > 0)
  1473. {
  1474. character = TMP_FontAssetUtilities.GetTextElementFromTextAssets(unicode, m_currentFontAsset, TMP_Settings.emojiFallbackTextAssets, true, fontStyle, fontWeight, out isUsingAlternativeTypeface);
  1475. if (character != null)
  1476. {
  1477. // Add character to font asset lookup cache
  1478. //fontAsset.AddCharacterToLookupCache(unicode, character);
  1479. }
  1480. }
  1481. }
  1482. if (character == null)
  1483. character = GetTextElement(unicode, m_currentFontAsset, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  1484. // Check if Lowercase or Uppercase variant of the character is available.
  1485. /* Not sure this is necessary anyone as it is very unlikely with recursive search through fallback fonts.
  1486. if (glyph == null)
  1487. {
  1488. if (char.IsLower((char)c))
  1489. {
  1490. if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToUpper((char)c), out glyph))
  1491. c = chars[i] = char.ToUpper((char)c);
  1492. }
  1493. else if (char.IsUpper((char)c))
  1494. {
  1495. if (m_currentFontAsset.characterDictionary.TryGetValue(char.ToLower((char)c), out glyph))
  1496. c = chars[i] = char.ToLower((char)c);
  1497. }
  1498. }*/
  1499. #region MISSING CHARACTER HANDLING
  1500. // Replace missing glyph by the Square (9633) glyph or possibly the Space (32) glyph.
  1501. if (character == null)
  1502. {
  1503. DoMissingGlyphCallback((int)unicode, textProcessingArray[i].stringIndex, m_currentFontAsset);
  1504. // Save the original unicode character
  1505. uint srcGlyph = unicode;
  1506. // Try replacing the missing glyph character by TMP Settings Missing Glyph or Square (9633) character.
  1507. unicode = textProcessingArray[i].unicode = (uint)TMP_Settings.missingGlyphCharacter == 0 ? 9633 : (uint)TMP_Settings.missingGlyphCharacter;
  1508. // Check for the missing glyph character in the currently assigned font asset and its fallbacks
  1509. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset((uint)unicode, m_currentFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  1510. if (character == null)
  1511. {
  1512. // Search for the missing glyph character in the TMP Settings Fallback list.
  1513. if (TMP_Settings.fallbackFontAssets != null && TMP_Settings.fallbackFontAssets.Count > 0)
  1514. character = TMP_FontAssetUtilities.GetCharacterFromFontAssets(unicode, m_currentFontAsset, TMP_Settings.fallbackFontAssets, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  1515. }
  1516. if (character == null)
  1517. {
  1518. // Search for the missing glyph in the TMP Settings Default Font Asset.
  1519. if (TMP_Settings.defaultFontAsset != null)
  1520. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset(unicode, TMP_Settings.defaultFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  1521. }
  1522. if (character == null)
  1523. {
  1524. // Use Space (32) Glyph from the currently assigned font asset.
  1525. unicode = textProcessingArray[i].unicode = 32;
  1526. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset(unicode, m_currentFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  1527. }
  1528. if (character == null)
  1529. {
  1530. // Use End of Text (0x03) Glyph from the currently assigned font asset.
  1531. unicode = textProcessingArray[i].unicode = 0x03;
  1532. character = TMP_FontAssetUtilities.GetCharacterFromFontAsset(unicode, m_currentFontAsset, true, m_FontStyleInternal, m_FontWeightInternal, out isUsingAlternativeTypeface);
  1533. }
  1534. if (!TMP_Settings.warningsDisabled)
  1535. {
  1536. string formattedWarning = srcGlyph > 0xFFFF
  1537. ? string.Format("The character with Unicode value \\U{0:X8} was not found in the [{1}] font asset or any potential fallbacks. It was replaced by Unicode character \\u{2:X4} in text object [{3}].", srcGlyph, m_fontAsset.name, character.unicode, this.name)
  1538. : string.Format("The character with Unicode value \\u{0:X4} was not found in the [{1}] font asset or any potential fallbacks. It was replaced by Unicode character \\u{2:X4} in text object [{3}].", srcGlyph, m_fontAsset.name, character.unicode, this.name);
  1539. Debug.LogWarning(formattedWarning, this);
  1540. }
  1541. }
  1542. #endregion
  1543. m_textInfo.characterInfo[m_totalCharacterCount].alternativeGlyph = null;
  1544. if (character.elementType == TextElementType.Character)
  1545. {
  1546. if (character.textAsset.instanceID != m_currentFontAsset.instanceID)
  1547. {
  1548. isUsingFallbackOrAlternativeTypeface = true;
  1549. m_currentFontAsset = character.textAsset as TMP_FontAsset;
  1550. }
  1551. #region VARIATION SELECTOR
  1552. if (nextCharacter >= 0xFE00 && nextCharacter <= 0xFE0F || nextCharacter >= 0xE0100 && nextCharacter <= 0xE01EF)
  1553. {
  1554. // Get potential variant glyph index
  1555. uint variantGlyphIndex = m_currentFontAsset.GetGlyphVariantIndex((uint)unicode, nextCharacter);
  1556. if (variantGlyphIndex != 0)
  1557. {
  1558. if (m_currentFontAsset.TryAddGlyphInternal(variantGlyphIndex, out Glyph glyph))
  1559. {
  1560. m_textInfo.characterInfo[m_totalCharacterCount].alternativeGlyph = glyph;
  1561. }
  1562. }
  1563. textProcessingArray[i + 1].unicode = 0x1A;
  1564. i += 1;
  1565. }
  1566. #endregion
  1567. #region LIGATURES
  1568. if (ligature && m_currentFontAsset.fontFeatureTable.m_LigatureSubstitutionRecordLookup.TryGetValue(character.glyphIndex, out List<LigatureSubstitutionRecord> records))
  1569. {
  1570. if (records == null)
  1571. break;
  1572. for (int j = 0; j < records.Count; j++)
  1573. {
  1574. LigatureSubstitutionRecord record = records[j];
  1575. int componentCount = record.componentGlyphIDs.Length;
  1576. uint ligatureGlyphID = record.ligatureGlyphID;
  1577. //
  1578. for (int k = 1; k < componentCount; k++)
  1579. {
  1580. uint componentUnicode = (uint)textProcessingArray[i + k].unicode;
  1581. // Special Handling for Zero Width Joiner (ZWJ)
  1582. //if (componentUnicode == 0x200D)
  1583. // continue;
  1584. uint glyphIndex = m_currentFontAsset.GetGlyphIndex(componentUnicode);
  1585. if (glyphIndex == record.componentGlyphIDs[k])
  1586. continue;
  1587. ligatureGlyphID = 0;
  1588. break;
  1589. }
  1590. if (ligatureGlyphID != 0)
  1591. {
  1592. if (m_currentFontAsset.TryAddGlyphInternal(ligatureGlyphID, out Glyph glyph))
  1593. {
  1594. m_textInfo.characterInfo[m_totalCharacterCount].alternativeGlyph = glyph;
  1595. // Update text processing array
  1596. for (int c = 0; c < componentCount; c++)
  1597. {
  1598. if (c == 0)
  1599. {
  1600. textProcessingArray[i + c].length = componentCount;
  1601. continue;
  1602. }
  1603. textProcessingArray[i + c].unicode = 0x1A;
  1604. }
  1605. i += componentCount - 1;
  1606. break;
  1607. }
  1608. }
  1609. }
  1610. }
  1611. #endregion
  1612. }
  1613. #endregion
  1614. // Save text element data
  1615. m_textInfo.characterInfo[m_totalCharacterCount].elementType = TMP_TextElementType.Character;
  1616. m_textInfo.characterInfo[m_totalCharacterCount].textElement = character;
  1617. m_textInfo.characterInfo[m_totalCharacterCount].isUsingAlternateTypeface = isUsingAlternativeTypeface;
  1618. m_textInfo.characterInfo[m_totalCharacterCount].character = (char)unicode;
  1619. m_textInfo.characterInfo[m_totalCharacterCount].index = textProcessingArray[i].stringIndex;
  1620. m_textInfo.characterInfo[m_totalCharacterCount].stringLength = textProcessingArray[i].length;
  1621. m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset;
  1622. // Special handling if the character is a sprite.
  1623. if (character.elementType == TextElementType.Sprite)
  1624. {
  1625. TMP_SpriteAsset spriteAssetRef = character.textAsset as TMP_SpriteAsset;
  1626. m_currentMaterialIndex = MaterialReference.AddMaterialReference(spriteAssetRef.material, spriteAssetRef, ref m_materialReferences, m_materialReferenceIndexLookup);
  1627. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1628. m_textInfo.characterInfo[m_totalCharacterCount].elementType = TMP_TextElementType.Sprite;
  1629. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  1630. // Restore element type and material index to previous values.
  1631. m_textElementType = TMP_TextElementType.Character;
  1632. m_currentMaterialIndex = prev_materialIndex;
  1633. spriteCount += 1;
  1634. m_totalCharacterCount += 1;
  1635. continue;
  1636. }
  1637. if (isUsingFallbackOrAlternativeTypeface && m_currentFontAsset.instanceID != m_fontAsset.instanceID)
  1638. {
  1639. // Create Fallback material instance matching current material preset if necessary
  1640. if (TMP_Settings.matchMaterialPreset)
  1641. m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentMaterial, m_currentFontAsset.material);
  1642. else
  1643. m_currentMaterial = m_currentFontAsset.material;
  1644. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, ref m_materialReferences, m_materialReferenceIndexLookup);
  1645. }
  1646. // Handle Multi Atlas Texture support
  1647. if (character != null && character.glyph.atlasIndex > 0)
  1648. {
  1649. m_currentMaterial = TMP_MaterialManager.GetFallbackMaterial(m_currentFontAsset, m_currentMaterial, character.glyph.atlasIndex);
  1650. m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, m_currentFontAsset, ref m_materialReferences, m_materialReferenceIndexLookup);
  1651. isUsingFallbackOrAlternativeTypeface = true;
  1652. }
  1653. if (!char.IsWhiteSpace((char)unicode) && unicode != 0x200B)
  1654. {
  1655. // Limit the mesh of the main text object to 65535 vertices and use sub objects for the overflow.
  1656. if (m_materialReferences[m_currentMaterialIndex].referenceCount < 16383)
  1657. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1658. else
  1659. {
  1660. m_currentMaterialIndex = MaterialReference.AddMaterialReference(new Material(m_currentMaterial), m_currentFontAsset, ref m_materialReferences, m_materialReferenceIndexLookup);
  1661. m_materialReferences[m_currentMaterialIndex].referenceCount += 1;
  1662. }
  1663. }
  1664. m_textInfo.characterInfo[m_totalCharacterCount].material = m_currentMaterial;
  1665. m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex;
  1666. m_materialReferences[m_currentMaterialIndex].isFallbackMaterial = isUsingFallbackOrAlternativeTypeface;
  1667. // Restore previous font asset and material if fallback font was used.
  1668. if (isUsingFallbackOrAlternativeTypeface)
  1669. {
  1670. m_materialReferences[m_currentMaterialIndex].fallbackMaterial = prev_material;
  1671. m_currentFontAsset = prev_fontAsset;
  1672. m_currentMaterial = prev_material;
  1673. m_currentMaterialIndex = prev_materialIndex;
  1674. }
  1675. m_totalCharacterCount += 1;
  1676. }
  1677. // Early return if we are calculating the preferred values.
  1678. if (m_isCalculatingPreferredValues)
  1679. {
  1680. m_isCalculatingPreferredValues = false;
  1681. k_SetArraySizesMarker.End();
  1682. return m_totalCharacterCount;
  1683. }
  1684. // Save material and sprite count.
  1685. m_textInfo.spriteCount = spriteCount;
  1686. int materialCount = m_textInfo.materialCount = m_materialReferenceIndexLookup.Count;
  1687. // Check if we need to resize the MeshInfo array for handling different materials.
  1688. if (materialCount > m_textInfo.meshInfo.Length)
  1689. TMP_TextInfo.Resize(ref m_textInfo.meshInfo, materialCount, false);
  1690. // Resize SubTextObject array if necessary
  1691. if (materialCount > m_subTextObjects.Length)
  1692. TMP_TextInfo.Resize(ref m_subTextObjects, Mathf.NextPowerOfTwo(materialCount + 1));
  1693. // Resize CharacterInfo[] if allocations are excessive
  1694. if (m_VertexBufferAutoSizeReduction && m_textInfo.characterInfo.Length - m_totalCharacterCount > 256)
  1695. TMP_TextInfo.Resize(ref m_textInfo.characterInfo, Mathf.Max(m_totalCharacterCount + 1, 256), true);
  1696. // Iterate through the material references to set the mesh buffer allocations
  1697. for (int i = 0; i < materialCount; i++)
  1698. {
  1699. // Add new sub text object for each material reference
  1700. if (i > 0)
  1701. {
  1702. if (m_subTextObjects[i] == null)
  1703. {
  1704. m_subTextObjects[i] = TMP_SubMeshUI.AddSubTextObject(this, m_materialReferences[i]);
  1705. // Not sure this is necessary
  1706. m_textInfo.meshInfo[i].vertices = null;
  1707. }
  1708. //else if (m_subTextObjects[i].gameObject.activeInHierarchy == false)
  1709. // m_subTextObjects[i].gameObject.SetActive(true);
  1710. // Make sure the pivots are synchronized
  1711. if (m_rectTransform.pivot != m_subTextObjects[i].rectTransform.pivot)
  1712. m_subTextObjects[i].rectTransform.pivot = m_rectTransform.pivot;
  1713. // Check if the material has changed.
  1714. if (m_subTextObjects[i].sharedMaterial == null || m_subTextObjects[i].sharedMaterial.GetInstanceID() != m_materialReferences[i].material.GetInstanceID())
  1715. {
  1716. m_subTextObjects[i].sharedMaterial = m_materialReferences[i].material;
  1717. m_subTextObjects[i].fontAsset = m_materialReferences[i].fontAsset;
  1718. m_subTextObjects[i].spriteAsset = m_materialReferences[i].spriteAsset;
  1719. }
  1720. // Check if we need to use a Fallback Material
  1721. if (m_materialReferences[i].isFallbackMaterial)
  1722. {
  1723. m_subTextObjects[i].fallbackMaterial = m_materialReferences[i].material;
  1724. m_subTextObjects[i].fallbackSourceMaterial = m_materialReferences[i].fallbackMaterial;
  1725. }
  1726. }
  1727. int referenceCount = m_materialReferences[i].referenceCount;
  1728. // Check to make sure our buffers allocations can accommodate the required text elements.
  1729. if (m_textInfo.meshInfo[i].vertices == null || m_textInfo.meshInfo[i].vertices.Length < referenceCount * 4)
  1730. {
  1731. if (m_textInfo.meshInfo[i].vertices == null)
  1732. {
  1733. if (i == 0)
  1734. m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_mesh, referenceCount + 1);
  1735. else
  1736. m_textInfo.meshInfo[i] = new TMP_MeshInfo(m_subTextObjects[i].mesh, referenceCount + 1);
  1737. }
  1738. else
  1739. m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount + 1));
  1740. }
  1741. else if (m_VertexBufferAutoSizeReduction && referenceCount > 0 && m_textInfo.meshInfo[i].vertices.Length / 4 - referenceCount > 256)
  1742. {
  1743. // Resize vertex buffers if allocations are excessive.
  1744. //Debug.Log("Reducing the size of the vertex buffers.");
  1745. m_textInfo.meshInfo[i].ResizeMeshInfo(referenceCount > 1024 ? referenceCount + 256 : Mathf.NextPowerOfTwo(referenceCount + 1));
  1746. }
  1747. // Assign material reference
  1748. m_textInfo.meshInfo[i].material = m_materialReferences[i].material;
  1749. }
  1750. //TMP_MaterialManager.CleanupFallbackMaterials();
  1751. // Clean up unused SubMeshes
  1752. for (int i = materialCount; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  1753. {
  1754. if (i < m_textInfo.meshInfo.Length)
  1755. {
  1756. m_subTextObjects[i].canvasRenderer.SetMesh(null);
  1757. // TODO: Figure out a way to handle this without running into Unity's Rebuild loop issue.
  1758. //m_subTextObjects[i].gameObject.SetActive(false);
  1759. }
  1760. }
  1761. k_SetArraySizesMarker.End();
  1762. return m_totalCharacterCount;
  1763. }
  1764. // Added to sort handle the potential issue with OnWillRenderObject() not getting called when objects are not visible by camera.
  1765. //void OnBecameInvisible()
  1766. //{
  1767. // if (m_mesh != null)
  1768. // m_mesh.bounds = new Bounds(transform.position, new Vector3(1000, 1000, 0));
  1769. //}
  1770. /// <summary>
  1771. /// Update the margin width and height
  1772. /// </summary>
  1773. public override void ComputeMarginSize()
  1774. {
  1775. if (this.rectTransform != null)
  1776. {
  1777. //Debug.Log("*** ComputeMarginSize() *** Current RectTransform's Width is " + m_rectTransform.rect.width + " and Height is " + m_rectTransform.rect.height); // + " and size delta is " + m_rectTransform.sizeDelta);
  1778. Rect rect = m_rectTransform.rect;
  1779. m_marginWidth = rect.width - m_margin.x - m_margin.z;
  1780. m_marginHeight = rect.height - m_margin.y - m_margin.w;
  1781. // Cache current RectTransform width and pivot referenced in OnRectTransformDimensionsChange() to get around potential rounding error in the reported width of the RectTransform.
  1782. m_PreviousRectTransformSize = rect.size;
  1783. m_PreviousPivotPosition = m_rectTransform.pivot;
  1784. // Update the corners of the RectTransform
  1785. m_RectTransformCorners = GetTextContainerLocalCorners();
  1786. }
  1787. }
  1788. /// <summary>
  1789. ///
  1790. /// </summary>
  1791. protected override void OnDidApplyAnimationProperties()
  1792. {
  1793. m_havePropertiesChanged = true;
  1794. SetVerticesDirty();
  1795. SetLayoutDirty();
  1796. //Debug.Log("Animation Properties have changed.");
  1797. }
  1798. protected override void OnCanvasHierarchyChanged()
  1799. {
  1800. base.OnCanvasHierarchyChanged();
  1801. m_canvas = canvas;
  1802. if (!m_isAwake || !isActiveAndEnabled)
  1803. return;
  1804. // Special handling to stop InternalUpdate calls when parent Canvas is disabled.
  1805. if (m_canvas == null || m_canvas.enabled == false)
  1806. TMP_UpdateManager.UnRegisterTextObjectForUpdate(this);
  1807. else if (m_IsTextObjectScaleStatic == false)
  1808. TMP_UpdateManager.RegisterTextObjectForUpdate(this);
  1809. }
  1810. protected override void OnTransformParentChanged()
  1811. {
  1812. //Debug.Log("***** OnTransformParentChanged *****");
  1813. base.OnTransformParentChanged();
  1814. m_canvas = this.canvas;
  1815. ComputeMarginSize();
  1816. m_havePropertiesChanged = true;
  1817. }
  1818. protected override void OnRectTransformDimensionsChange()
  1819. {
  1820. //Debug.Log("*** OnRectTransformDimensionsChange() *** ActiveInHierarchy: " + this.gameObject.activeInHierarchy + " Frame: " + Time.frameCount);
  1821. // Make sure object is active in Hierarchy
  1822. if (!this.gameObject.activeInHierarchy)
  1823. return;
  1824. // Check if Canvas scale factor has changed as this requires an update of the SDF Scale.
  1825. bool hasCanvasScaleFactorChanged = false;
  1826. if (m_canvas != null && m_CanvasScaleFactor != m_canvas.scaleFactor)
  1827. {
  1828. m_CanvasScaleFactor = m_canvas.scaleFactor;
  1829. hasCanvasScaleFactorChanged = true;
  1830. }
  1831. // Ignore changes to RectTransform SizeDelta that are very small and typically the result of rounding errors when using RectTransform in Anchor Stretch mode.
  1832. if (hasCanvasScaleFactorChanged == false &&
  1833. rectTransform != null &&
  1834. Mathf.Abs(m_rectTransform.rect.width - m_PreviousRectTransformSize.x) < 0.0001f && Mathf.Abs(m_rectTransform.rect.height - m_PreviousRectTransformSize.y) < 0.0001f &&
  1835. Mathf.Abs(m_rectTransform.pivot.x - m_PreviousPivotPosition.x) < 0.0001f && Mathf.Abs(m_rectTransform.pivot.y - m_PreviousPivotPosition.y) < 0.0001f)
  1836. {
  1837. return;
  1838. }
  1839. ComputeMarginSize();
  1840. UpdateSubObjectPivot();
  1841. SetVerticesDirty();
  1842. SetLayoutDirty();
  1843. }
  1844. /// <summary>
  1845. /// Function used as a replacement for LateUpdate to check if the transform or scale of the text object has changed.
  1846. /// </summary>
  1847. internal override void InternalUpdate()
  1848. {
  1849. // We need to update the SDF scale or possibly regenerate the text object if lossy scale has changed.
  1850. if (m_havePropertiesChanged == false)
  1851. {
  1852. float lossyScaleY = m_rectTransform.lossyScale.y;
  1853. if (lossyScaleY != m_previousLossyScaleY && m_TextProcessingArray[0].unicode != 0)
  1854. {
  1855. float scaleDelta = lossyScaleY / m_previousLossyScaleY;
  1856. // Only update SDF Scale when lossy scale has changed by more than 20%
  1857. if (scaleDelta < 0.8f || scaleDelta > 1.25f)
  1858. {
  1859. UpdateSDFScale(scaleDelta);
  1860. m_previousLossyScaleY = lossyScaleY;
  1861. }
  1862. }
  1863. }
  1864. // Added to handle legacy animation mode.
  1865. if (m_isUsingLegacyAnimationComponent)
  1866. {
  1867. m_havePropertiesChanged = true;
  1868. OnPreRenderCanvas();
  1869. }
  1870. }
  1871. /// <summary>
  1872. /// Function called when the text needs to be updated.
  1873. /// </summary>
  1874. void OnPreRenderCanvas()
  1875. {
  1876. //Debug.Log("*** OnPreRenderCanvas() *** Frame: " + Time.frameCount);
  1877. // Make sure object is active and that we have a valid Canvas.
  1878. if (!m_isAwake || (this.IsActive() == false && m_ignoreActiveState == false))
  1879. return;
  1880. if (m_canvas == null) { m_canvas = this.canvas; if (m_canvas == null) return; }
  1881. if (m_havePropertiesChanged || m_isLayoutDirty)
  1882. {
  1883. //Debug.Log("Properties have changed!"); // Assigned Material is:" + m_sharedMaterial); // New Text is: " + m_text + ".");
  1884. // Check if we have a font asset assigned. Return if we don't because no one likes to see purple squares on screen.
  1885. if (m_fontAsset == null)
  1886. {
  1887. Debug.LogWarning("Please assign a Font Asset to this " + transform.name + " gameobject.", this);
  1888. return;
  1889. }
  1890. // Update mesh padding if necessary.
  1891. if (checkPaddingRequired)
  1892. UpdateMeshPadding();
  1893. // Reparse the text as input may have changed or been truncated.
  1894. ParseInputText();
  1895. TMP_FontAsset.UpdateFontAssetsInUpdateQueue();
  1896. // Reset Font min / max used with Auto-sizing
  1897. if (m_enableAutoSizing)
  1898. m_fontSize = Mathf.Clamp(m_fontSizeBase, m_fontSizeMin, m_fontSizeMax);
  1899. m_maxFontSize = m_fontSizeMax;
  1900. m_minFontSize = m_fontSizeMin;
  1901. m_lineSpacingDelta = 0;
  1902. m_charWidthAdjDelta = 0;
  1903. m_isTextTruncated = false;
  1904. m_havePropertiesChanged = false;
  1905. m_isLayoutDirty = false;
  1906. m_ignoreActiveState = false;
  1907. // Reset Text Auto Size iteration tracking.
  1908. m_IsAutoSizePointSizeSet = false;
  1909. m_AutoSizeIterationCount = 0;
  1910. // The GenerateTextMesh function is potentially called repeatedly when text auto size is enabled.
  1911. // This is a revised implementation to remove the use of recursion which could potentially result in stack overflow issues.
  1912. while (m_IsAutoSizePointSizeSet == false)
  1913. {
  1914. GenerateTextMesh();
  1915. m_AutoSizeIterationCount += 1;
  1916. }
  1917. }
  1918. }
  1919. /// <summary>
  1920. /// This is the main function that is responsible for creating / displaying the text.
  1921. /// </summary>
  1922. protected virtual void GenerateTextMesh()
  1923. {
  1924. k_GenerateTextMarker.Begin();
  1925. // Early exit if no font asset was assigned. This should not be needed since LiberationSans SDF will be assigned by default.
  1926. if (m_fontAsset == null || m_fontAsset.characterLookupTable == null)
  1927. {
  1928. Debug.LogWarning("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());
  1929. m_IsAutoSizePointSizeSet = true;
  1930. k_GenerateTextMarker.End();
  1931. return;
  1932. }
  1933. // Clear TextInfo
  1934. if (m_textInfo != null)
  1935. m_textInfo.Clear();
  1936. // Early exit if we don't have any Text to generate.
  1937. if (m_TextProcessingArray == null || m_TextProcessingArray.Length == 0 || m_TextProcessingArray[0].unicode == 0)
  1938. {
  1939. // Clear mesh and upload changes to the mesh.
  1940. ClearMesh();
  1941. m_preferredWidth = 0;
  1942. m_preferredHeight = 0;
  1943. // Event indicating the text has been regenerated.
  1944. TMPro_EventManager.ON_TEXT_CHANGED(this);
  1945. m_IsAutoSizePointSizeSet = true;
  1946. k_GenerateTextMarker.End();
  1947. return;
  1948. }
  1949. m_currentFontAsset = m_fontAsset;
  1950. m_currentMaterial = m_sharedMaterial;
  1951. m_currentMaterialIndex = 0;
  1952. m_materialReferenceStack.SetDefault(new MaterialReference(m_currentMaterialIndex, m_currentFontAsset, null, m_currentMaterial, m_padding));
  1953. m_currentSpriteAsset = m_spriteAsset;
  1954. // Stop all Sprite Animations
  1955. if (m_spriteAnimator != null)
  1956. m_spriteAnimator.StopAllAnimations();
  1957. // Total character count is computed when the text is parsed.
  1958. int totalCharacterCount = m_totalCharacterCount;
  1959. // Calculate the scale of the font based on selected font size and sampling point size.
  1960. // baseScale is calculated using the font asset assigned to the text object.
  1961. float baseScale = (m_fontSize / m_fontAsset.m_FaceInfo.pointSize * m_fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f));
  1962. float currentElementScale = baseScale;
  1963. float currentEmScale = m_fontSize * 0.01f * (m_isOrthographic ? 1 : 0.1f);
  1964. m_fontScaleMultiplier = 1;
  1965. m_currentFontSize = m_fontSize;
  1966. m_sizeStack.SetDefault(m_currentFontSize);
  1967. float fontSizeDelta = 0;
  1968. uint charCode = 0; // Holds the character code of the currently being processed character.
  1969. m_FontStyleInternal = m_fontStyle; // Set the default style.
  1970. m_FontWeightInternal = (m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold ? FontWeight.Bold : m_fontWeight;
  1971. m_FontWeightStack.SetDefault(m_FontWeightInternal);
  1972. m_fontStyleStack.Clear();
  1973. m_lineJustification = m_HorizontalAlignment; // m_textAlignment; // Sets the line justification mode to match editor alignment.
  1974. m_lineJustificationStack.SetDefault(m_lineJustification);
  1975. float padding = 0;
  1976. m_baselineOffset = 0; // Used by subscript characters.
  1977. m_baselineOffsetStack.Clear();
  1978. // Underline
  1979. bool beginUnderline = false;
  1980. Vector3 underline_start = Vector3.zero; // Used to track where underline starts & ends.
  1981. Vector3 underline_end = Vector3.zero;
  1982. // Strike-through
  1983. bool beginStrikethrough = false;
  1984. Vector3 strikethrough_start = Vector3.zero;
  1985. Vector3 strikethrough_end = Vector3.zero;
  1986. // Text Highlight
  1987. bool beginHighlight = false;
  1988. Vector3 highlight_start = Vector3.zero;
  1989. Vector3 highlight_end = Vector3.zero;
  1990. m_fontColor32 = m_fontColor;
  1991. m_htmlColor = m_fontColor32;
  1992. m_underlineColor = m_htmlColor;
  1993. m_strikethroughColor = m_htmlColor;
  1994. m_colorStack.SetDefault(m_htmlColor);
  1995. m_underlineColorStack.SetDefault(m_htmlColor);
  1996. m_strikethroughColorStack.SetDefault(m_htmlColor);
  1997. m_HighlightStateStack.SetDefault(new HighlightState(m_htmlColor, TMP_Offset.zero));
  1998. m_colorGradientPreset = null;
  1999. m_colorGradientStack.SetDefault(null);
  2000. m_ItalicAngle = m_currentFontAsset.italicStyle;
  2001. m_ItalicAngleStack.SetDefault(m_ItalicAngle);
  2002. // Clear the Style stack.
  2003. //m_styleStack.Clear();
  2004. // Clear the Action stack.
  2005. m_actionStack.Clear();
  2006. m_FXScale = Vector3.one;
  2007. m_FXRotation = Quaternion.identity;
  2008. m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
  2009. m_lineHeight = TMP_Math.FLOAT_UNSET;
  2010. float lineGap = m_currentFontAsset.m_FaceInfo.lineHeight - (m_currentFontAsset.m_FaceInfo.ascentLine - m_currentFontAsset.m_FaceInfo.descentLine);
  2011. m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
  2012. m_monoSpacing = 0;
  2013. m_xAdvance = 0; // Used to track the position of each character.
  2014. tag_LineIndent = 0; // Used for indentation of text.
  2015. tag_Indent = 0;
  2016. m_indentStack.SetDefault(0);
  2017. tag_NoParsing = false;
  2018. //m_isIgnoringAlignment = false;
  2019. m_characterCount = 0; // Total characters in the char[]
  2020. // Tracking of line information
  2021. m_firstCharacterOfLine = m_firstVisibleCharacter;
  2022. m_lastCharacterOfLine = 0;
  2023. m_firstVisibleCharacterOfLine = 0;
  2024. m_lastVisibleCharacterOfLine = 0;
  2025. m_maxLineAscender = k_LargeNegativeFloat;
  2026. m_maxLineDescender = k_LargePositiveFloat;
  2027. m_lineNumber = 0;
  2028. m_startOfLineAscender = 0;
  2029. m_startOfLineDescender = 0;
  2030. m_lineVisibleCharacterCount = 0;
  2031. m_lineVisibleSpaceCount = 0;
  2032. bool isStartOfNewLine = true;
  2033. m_IsDrivenLineSpacing = false;
  2034. m_firstOverflowCharacterIndex = -1;
  2035. m_LastBaseGlyphIndex = int.MinValue;
  2036. bool kerning = m_ActiveFontFeatures.Contains(OTL_FeatureTag.kern);
  2037. bool markToBase = m_ActiveFontFeatures.Contains(OTL_FeatureTag.mark);
  2038. bool markToMark = m_ActiveFontFeatures.Contains(OTL_FeatureTag.mkmk);
  2039. m_pageNumber = 0;
  2040. int pageToDisplay = Mathf.Clamp(m_pageToDisplay - 1, 0, m_textInfo.pageInfo.Length - 1);
  2041. m_textInfo.ClearPageInfo();
  2042. Vector4 margins = m_margin;
  2043. float marginWidth = m_marginWidth > 0 ? m_marginWidth : 0;
  2044. float marginHeight = m_marginHeight > 0 ? m_marginHeight : 0;
  2045. m_marginLeft = 0;
  2046. m_marginRight = 0;
  2047. m_width = -1;
  2048. float widthOfTextArea = marginWidth + 0.0001f - m_marginLeft - m_marginRight;
  2049. // Need to initialize these Extents structures
  2050. m_meshExtents.min = k_LargePositiveVector2;
  2051. m_meshExtents.max = k_LargeNegativeVector2;
  2052. // Initialize lineInfo
  2053. m_textInfo.ClearLineInfo();
  2054. // Tracking of the highest Ascender
  2055. m_maxCapHeight = 0;
  2056. m_maxTextAscender = 0;
  2057. m_ElementDescender = 0;
  2058. m_PageAscender = 0;
  2059. float maxVisibleDescender = 0;
  2060. bool isMaxVisibleDescenderSet = false;
  2061. m_isNewPage = false;
  2062. // Initialize struct to track states of word wrapping
  2063. bool isFirstWordOfLine = true;
  2064. m_isNonBreakingSpace = false;
  2065. bool ignoreNonBreakingSpace = false;
  2066. int lastSoftLineBreak = 0;
  2067. CharacterSubstitution characterToSubstitute = new CharacterSubstitution(-1, 0);
  2068. bool isSoftHyphenIgnored = false;
  2069. // Save character and line state before we begin layout.
  2070. SaveWordWrappingState(ref m_SavedWordWrapState, -1, -1);
  2071. SaveWordWrappingState(ref m_SavedLineState, -1, -1);
  2072. SaveWordWrappingState(ref m_SavedEllipsisState, -1, -1);
  2073. SaveWordWrappingState(ref m_SavedLastValidState, -1, -1);
  2074. SaveWordWrappingState(ref m_SavedSoftLineBreakState, -1, -1);
  2075. m_EllipsisInsertionCandidateStack.Clear();
  2076. // Safety Tracker
  2077. int restoreCount = 0;
  2078. k_GenerateTextPhaseIMarker.Begin();
  2079. // Parse through Character buffer to read HTML tags and begin creating mesh.
  2080. for (int i = 0; i < m_TextProcessingArray.Length && m_TextProcessingArray[i].unicode != 0; i++)
  2081. {
  2082. charCode = m_TextProcessingArray[i].unicode;
  2083. if (restoreCount > 5)
  2084. {
  2085. Debug.LogError("Line breaking recursion max threshold hit... Character [" + charCode + "] index: " + i);
  2086. characterToSubstitute.index = m_characterCount;
  2087. characterToSubstitute.unicode = 0x03;
  2088. }
  2089. // Skip characters that have been substituted.
  2090. if (charCode == 0x1A)
  2091. continue;
  2092. // Parse Rich Text Tag
  2093. #region Parse Rich Text Tag
  2094. if (m_isRichText && charCode == '<')
  2095. {
  2096. k_ParseMarkupTextMarker.Begin();
  2097. m_isTextLayoutPhase = true;
  2098. m_textElementType = TMP_TextElementType.Character;
  2099. int endTagIndex;
  2100. // Check if Tag is valid. If valid, skip to the end of the validated tag.
  2101. if (ValidateHtmlTag(m_TextProcessingArray, i + 1, out endTagIndex))
  2102. {
  2103. i = endTagIndex;
  2104. // Continue to next character or handle the sprite element
  2105. if (m_textElementType == TMP_TextElementType.Character)
  2106. {
  2107. k_ParseMarkupTextMarker.End();
  2108. continue;
  2109. }
  2110. }
  2111. k_ParseMarkupTextMarker.End();
  2112. }
  2113. else
  2114. {
  2115. m_textElementType = m_textInfo.characterInfo[m_characterCount].elementType;
  2116. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  2117. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  2118. }
  2119. #endregion End Parse Rich Text Tag
  2120. int previousMaterialIndex = m_currentMaterialIndex;
  2121. bool isUsingAltTypeface = m_textInfo.characterInfo[m_characterCount].isUsingAlternateTypeface;
  2122. m_isTextLayoutPhase = false;
  2123. // Handle potential character substitutions
  2124. #region Character Substitutions
  2125. bool isInjectedCharacter = false;
  2126. if (characterToSubstitute.index == m_characterCount)
  2127. {
  2128. charCode = characterToSubstitute.unicode;
  2129. m_textElementType = TMP_TextElementType.Character;
  2130. isInjectedCharacter = true;
  2131. switch (charCode)
  2132. {
  2133. case 0x03:
  2134. m_textInfo.characterInfo[m_characterCount].textElement = m_currentFontAsset.characterLookupTable[0x03];
  2135. m_isTextTruncated = true;
  2136. break;
  2137. case 0x2D:
  2138. //
  2139. break;
  2140. case 0x2026:
  2141. m_textInfo.characterInfo[m_characterCount].textElement = m_Ellipsis.character;
  2142. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Character;
  2143. m_textInfo.characterInfo[m_characterCount].fontAsset = m_Ellipsis.fontAsset;
  2144. m_textInfo.characterInfo[m_characterCount].material = m_Ellipsis.material;
  2145. m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_Ellipsis.materialIndex;
  2146. // Need to increase reference count in the event the primary mesh has no characters.
  2147. m_materialReferences[m_Underline.materialIndex].referenceCount += 1;
  2148. // Indicates the source parsing data has been modified.
  2149. m_isTextTruncated = true;
  2150. // End Of Text
  2151. characterToSubstitute.index = m_characterCount + 1;
  2152. characterToSubstitute.unicode = 0x03;
  2153. break;
  2154. }
  2155. }
  2156. #endregion
  2157. // When using Linked text, mark character as ignored and skip to next character.
  2158. #region Linked Text
  2159. if (m_characterCount < m_firstVisibleCharacter && charCode != 0x03)
  2160. {
  2161. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  2162. m_textInfo.characterInfo[m_characterCount].character = (char)0x200B;
  2163. m_textInfo.characterInfo[m_characterCount].lineNumber = 0;
  2164. m_characterCount += 1;
  2165. continue;
  2166. }
  2167. #endregion
  2168. // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
  2169. #region Handling of LowerCase, UpperCase and SmallCaps Font Styles
  2170. float smallCapsMultiplier = 1.0f;
  2171. if (m_textElementType == TMP_TextElementType.Character)
  2172. {
  2173. if ((m_FontStyleInternal & FontStyles.UpperCase) == FontStyles.UpperCase)
  2174. {
  2175. // If this character is lowercase, switch to uppercase.
  2176. if (char.IsLower((char)charCode))
  2177. charCode = char.ToUpper((char)charCode);
  2178. }
  2179. else if ((m_FontStyleInternal & FontStyles.LowerCase) == FontStyles.LowerCase)
  2180. {
  2181. // If this character is uppercase, switch to lowercase.
  2182. if (char.IsUpper((char)charCode))
  2183. charCode = char.ToLower((char)charCode);
  2184. }
  2185. else if ((m_FontStyleInternal & FontStyles.SmallCaps) == FontStyles.SmallCaps)
  2186. {
  2187. if (char.IsLower((char)charCode))
  2188. {
  2189. smallCapsMultiplier = 0.8f;
  2190. charCode = char.ToUpper((char)charCode);
  2191. }
  2192. }
  2193. }
  2194. #endregion
  2195. // Look up Character Data from Dictionary and cache it.
  2196. #region Look up Character Data
  2197. k_CharacterLookupMarker.Begin();
  2198. float baselineOffset = 0;
  2199. float elementAscentLine = 0;
  2200. float elementDescentLine = 0;
  2201. if (m_textElementType == TMP_TextElementType.Sprite)
  2202. {
  2203. // If a sprite is used as a fallback then get a reference to it and set the color to white.
  2204. TMP_SpriteCharacter sprite = (TMP_SpriteCharacter)textInfo.characterInfo[m_characterCount].textElement;
  2205. m_currentSpriteAsset = sprite.textAsset as TMP_SpriteAsset;
  2206. m_spriteIndex = (int)sprite.glyphIndex;
  2207. if (sprite == null)
  2208. {
  2209. k_CharacterLookupMarker.End();
  2210. continue;
  2211. }
  2212. // Sprites are assigned in the E000 Private Area + sprite Index
  2213. if (charCode == '<')
  2214. charCode = 57344 + (uint)m_spriteIndex;
  2215. else
  2216. m_spriteColor = s_colorWhite;
  2217. float fontScale = (m_currentFontSize / m_currentFontAsset.faceInfo.pointSize * m_currentFontAsset.faceInfo.scale * (m_isOrthographic ? 1 : 0.1f));
  2218. // The sprite scale calculations are based on the font asset assigned to the text object.
  2219. if (m_currentSpriteAsset.m_FaceInfo.pointSize > 0)
  2220. {
  2221. float spriteScale = m_currentFontSize / m_currentSpriteAsset.m_FaceInfo.pointSize * m_currentSpriteAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  2222. currentElementScale = sprite.m_Scale * sprite.m_Glyph.scale * spriteScale;
  2223. elementAscentLine = m_currentSpriteAsset.m_FaceInfo.ascentLine;
  2224. baselineOffset = m_currentSpriteAsset.m_FaceInfo.baseline * fontScale * m_fontScaleMultiplier * m_currentSpriteAsset.m_FaceInfo.scale;
  2225. elementDescentLine = m_currentSpriteAsset.m_FaceInfo.descentLine;
  2226. }
  2227. else
  2228. {
  2229. float spriteScale = m_currentFontSize / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  2230. currentElementScale = m_currentFontAsset.m_FaceInfo.ascentLine / sprite.m_Glyph.metrics.height * sprite.m_Scale * sprite.m_Glyph.scale * spriteScale;
  2231. float scaleDelta = spriteScale / currentElementScale;
  2232. elementAscentLine = m_currentFontAsset.m_FaceInfo.ascentLine * scaleDelta;
  2233. baselineOffset = m_currentFontAsset.m_FaceInfo.baseline * fontScale * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale;
  2234. elementDescentLine = m_currentFontAsset.m_FaceInfo.descentLine * scaleDelta;
  2235. }
  2236. m_cached_TextElement = sprite;
  2237. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite;
  2238. m_textInfo.characterInfo[m_characterCount].scale = currentElementScale;
  2239. m_textInfo.characterInfo[m_characterCount].fontAsset = m_currentFontAsset;
  2240. m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex;
  2241. m_currentMaterialIndex = previousMaterialIndex;
  2242. padding = 0;
  2243. }
  2244. else if (m_textElementType == TMP_TextElementType.Character)
  2245. {
  2246. m_cached_TextElement = m_textInfo.characterInfo[m_characterCount].textElement;
  2247. if (m_cached_TextElement == null)
  2248. {
  2249. k_CharacterLookupMarker.End();
  2250. continue;
  2251. }
  2252. m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;
  2253. m_currentMaterial = m_textInfo.characterInfo[m_characterCount].material;
  2254. m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
  2255. // Special handling if replaced character was a line feed where in this case we have to use the scale of the previous character.
  2256. float adjustedScale;
  2257. if (isInjectedCharacter && m_TextProcessingArray[i].unicode == 0x0A && m_characterCount != m_firstCharacterOfLine)
  2258. adjustedScale = m_textInfo.characterInfo[m_characterCount - 1].pointSize * smallCapsMultiplier / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  2259. else
  2260. adjustedScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  2261. // Special handling for injected Ellipsis
  2262. if (isInjectedCharacter && charCode == 0x2026)
  2263. {
  2264. elementAscentLine = 0;
  2265. elementDescentLine = 0;
  2266. }
  2267. else
  2268. {
  2269. elementAscentLine = m_currentFontAsset.m_FaceInfo.ascentLine;
  2270. elementDescentLine = m_currentFontAsset.m_FaceInfo.descentLine;
  2271. }
  2272. currentElementScale = adjustedScale * m_fontScaleMultiplier * m_cached_TextElement.m_Scale * m_cached_TextElement.m_Glyph.scale;
  2273. baselineOffset = m_currentFontAsset.m_FaceInfo.baseline * adjustedScale * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale;
  2274. m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Character;
  2275. m_textInfo.characterInfo[m_characterCount].scale = currentElementScale;
  2276. padding = m_currentMaterialIndex == 0 ? m_padding : m_subTextObjects[m_currentMaterialIndex].padding;
  2277. }
  2278. k_CharacterLookupMarker.End();
  2279. #endregion
  2280. // Handle Soft Hyphen
  2281. #region Handle Soft Hyphen
  2282. float currentElementUnmodifiedScale = currentElementScale;
  2283. if (charCode == 0xAD || charCode == 0x03)
  2284. currentElementScale = 0;
  2285. #endregion
  2286. // Store some of the text object's information
  2287. m_textInfo.characterInfo[m_characterCount].character = (char)charCode;
  2288. m_textInfo.characterInfo[m_characterCount].pointSize = m_currentFontSize;
  2289. m_textInfo.characterInfo[m_characterCount].color = m_htmlColor;
  2290. m_textInfo.characterInfo[m_characterCount].underlineColor = m_underlineColor;
  2291. m_textInfo.characterInfo[m_characterCount].strikethroughColor = m_strikethroughColor;
  2292. m_textInfo.characterInfo[m_characterCount].highlightState = m_HighlightState;
  2293. m_textInfo.characterInfo[m_characterCount].style = m_FontStyleInternal;
  2294. // Cache glyph metrics
  2295. Glyph altGlyph = m_textInfo.characterInfo[m_characterCount].alternativeGlyph;
  2296. GlyphMetrics currentGlyphMetrics = altGlyph == null ? m_cached_TextElement.m_Glyph.metrics : altGlyph.metrics;
  2297. // Optimization to avoid calling this more than once per character.
  2298. bool isWhiteSpace = charCode <= 0xFFFF && char.IsWhiteSpace((char)charCode);
  2299. // Handle Kerning if Enabled.
  2300. #region Handle Kerning
  2301. GlyphValueRecord glyphAdjustments = new GlyphValueRecord();
  2302. float characterSpacingAdjustment = m_characterSpacing;
  2303. if (kerning && m_textElementType == TMP_TextElementType.Character)
  2304. {
  2305. k_HandleGPOSFeaturesMarker.Begin();
  2306. GlyphPairAdjustmentRecord adjustmentPair;
  2307. uint baseGlyphIndex = m_cached_TextElement.m_GlyphIndex;
  2308. if (m_characterCount < totalCharacterCount - 1 && textInfo.characterInfo[m_characterCount + 1].elementType == TMP_TextElementType.Character)
  2309. {
  2310. uint nextGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.m_GlyphIndex;
  2311. uint key = nextGlyphIndex << 16 | baseGlyphIndex;
  2312. if (m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup.TryGetValue(key, out adjustmentPair))
  2313. {
  2314. glyphAdjustments = adjustmentPair.firstAdjustmentRecord.glyphValueRecord;
  2315. characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & UnityEngine.TextCore.LowLevel.FontFeatureLookupFlags.IgnoreSpacingAdjustments) == UnityEngine.TextCore.LowLevel.FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment;
  2316. }
  2317. }
  2318. if (m_characterCount >= 1)
  2319. {
  2320. uint previousGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.m_GlyphIndex;
  2321. uint key = baseGlyphIndex << 16 | previousGlyphIndex;
  2322. if (textInfo.characterInfo[m_characterCount - 1].elementType == TMP_TextElementType.Character && m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookup.TryGetValue(key, out adjustmentPair))
  2323. {
  2324. glyphAdjustments += adjustmentPair.secondAdjustmentRecord.glyphValueRecord;
  2325. characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & UnityEngine.TextCore.LowLevel.FontFeatureLookupFlags.IgnoreSpacingAdjustments) == UnityEngine.TextCore.LowLevel.FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment;
  2326. }
  2327. }
  2328. k_HandleGPOSFeaturesMarker.End();
  2329. }
  2330. m_textInfo.characterInfo[m_characterCount].adjustedHorizontalAdvance = glyphAdjustments.xAdvance;
  2331. #endregion
  2332. // Handle Diacritical Marks
  2333. #region Handle Diacritical Marks
  2334. bool isBaseGlyph = TMP_TextParsingUtilities.IsBaseGlyph(charCode);
  2335. if (isBaseGlyph)
  2336. m_LastBaseGlyphIndex = m_characterCount;
  2337. if (m_characterCount > 0 && !isBaseGlyph)
  2338. {
  2339. // Check for potential Mark-to-Base lookup if previous glyph was a base glyph
  2340. if (markToBase && m_LastBaseGlyphIndex != int.MinValue && m_LastBaseGlyphIndex == m_characterCount - 1)
  2341. {
  2342. Glyph baseGlyph = m_textInfo.characterInfo[m_LastBaseGlyphIndex].textElement.glyph;
  2343. uint baseGlyphIndex = baseGlyph.index;
  2344. uint markGlyphIndex = m_cached_TextElement.glyphIndex;
  2345. uint key = markGlyphIndex << 16 | baseGlyphIndex;
  2346. if (m_currentFontAsset.fontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.TryGetValue(key, out MarkToBaseAdjustmentRecord glyphAdjustmentRecord))
  2347. {
  2348. float advanceOffset = (m_textInfo.characterInfo[m_LastBaseGlyphIndex].origin - m_xAdvance) / currentElementScale;
  2349. glyphAdjustments.xPlacement = advanceOffset + glyphAdjustmentRecord.baseGlyphAnchorPoint.xCoordinate - glyphAdjustmentRecord.markPositionAdjustment.xPositionAdjustment;
  2350. glyphAdjustments.yPlacement = glyphAdjustmentRecord.baseGlyphAnchorPoint.yCoordinate - glyphAdjustmentRecord.markPositionAdjustment.yPositionAdjustment;
  2351. characterSpacingAdjustment = 0;
  2352. }
  2353. }
  2354. else
  2355. {
  2356. // Iterate from previous glyph to last base glyph checking for any potential Mark-to-Mark lookups to apply. Otherwise check for potential Mark-to-Base lookup between the current glyph and last base glyph
  2357. bool wasLookupApplied = false;
  2358. // Check for any potential Mark-to-Mark lookups
  2359. if (markToMark)
  2360. {
  2361. for (int characterLookupIndex = m_characterCount - 1; characterLookupIndex >= 0 && characterLookupIndex != m_LastBaseGlyphIndex; characterLookupIndex--)
  2362. {
  2363. // Handle any potential Mark-to-Mark lookup
  2364. Glyph baseMarkGlyph = m_textInfo.characterInfo[characterLookupIndex].textElement.glyph;
  2365. uint baseGlyphIndex = baseMarkGlyph.index;
  2366. uint combiningMarkGlyphIndex = m_cached_TextElement.glyphIndex;
  2367. uint key = combiningMarkGlyphIndex << 16 | baseGlyphIndex;
  2368. if (m_currentFontAsset.fontFeatureTable.m_MarkToMarkAdjustmentRecordLookup.TryGetValue(key, out MarkToMarkAdjustmentRecord glyphAdjustmentRecord))
  2369. {
  2370. float baseMarkOrigin = (m_textInfo.characterInfo[characterLookupIndex].origin - m_xAdvance) / currentElementScale;
  2371. float currentBaseline = baselineOffset - m_lineOffset + m_baselineOffset;
  2372. float baseMarkBaseline = (m_textInfo.characterInfo[characterLookupIndex].baseLine - currentBaseline) / currentElementScale;
  2373. glyphAdjustments.xPlacement = baseMarkOrigin + glyphAdjustmentRecord.baseMarkGlyphAnchorPoint.xCoordinate - glyphAdjustmentRecord.combiningMarkPositionAdjustment.xPositionAdjustment;
  2374. glyphAdjustments.yPlacement = baseMarkBaseline + glyphAdjustmentRecord.baseMarkGlyphAnchorPoint.yCoordinate - glyphAdjustmentRecord.combiningMarkPositionAdjustment.yPositionAdjustment;
  2375. characterSpacingAdjustment = 0;
  2376. wasLookupApplied = true;
  2377. break;
  2378. }
  2379. }
  2380. }
  2381. // If no Mark-to-Mark lookups were applied, check for potential Mark-to-Base lookup.
  2382. if (markToBase && m_LastBaseGlyphIndex != int.MinValue && !wasLookupApplied)
  2383. {
  2384. // Handle lookup for Mark-to-Base
  2385. Glyph baseGlyph = m_textInfo.characterInfo[m_LastBaseGlyphIndex].textElement.glyph;
  2386. uint baseGlyphIndex = baseGlyph.index;
  2387. uint markGlyphIndex = m_cached_TextElement.glyphIndex;
  2388. uint key = markGlyphIndex << 16 | baseGlyphIndex;
  2389. if (m_currentFontAsset.fontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.TryGetValue(key, out MarkToBaseAdjustmentRecord glyphAdjustmentRecord))
  2390. {
  2391. float advanceOffset = (m_textInfo.characterInfo[m_LastBaseGlyphIndex].origin - m_xAdvance) / currentElementScale;
  2392. glyphAdjustments.xPlacement = advanceOffset + glyphAdjustmentRecord.baseGlyphAnchorPoint.xCoordinate - glyphAdjustmentRecord.markPositionAdjustment.xPositionAdjustment;
  2393. glyphAdjustments.yPlacement = glyphAdjustmentRecord.baseGlyphAnchorPoint.yCoordinate - glyphAdjustmentRecord.markPositionAdjustment.yPositionAdjustment;
  2394. characterSpacingAdjustment = 0;
  2395. }
  2396. }
  2397. }
  2398. }
  2399. // Adjust relevant text metrics
  2400. elementAscentLine += glyphAdjustments.yPlacement;
  2401. elementDescentLine += glyphAdjustments.yPlacement;
  2402. #endregion
  2403. // Initial Implementation for RTL support.
  2404. #region Handle Right-to-Left
  2405. if (m_isRightToLeft)
  2406. {
  2407. m_xAdvance -= currentGlyphMetrics.horizontalAdvance * (1 - m_charWidthAdjDelta) * currentElementScale;
  2408. if (isWhiteSpace || charCode == 0x200B)
  2409. m_xAdvance -= m_wordSpacing * currentEmScale;
  2410. }
  2411. #endregion
  2412. // Handle Mono Spacing
  2413. #region Handle Mono Spacing
  2414. float monoAdvance = 0;
  2415. if (m_monoSpacing != 0)
  2416. {
  2417. if (m_duoSpace && (charCode == '.' || charCode == ':' || charCode == ','))
  2418. monoAdvance = (m_monoSpacing / 4 - (currentGlyphMetrics.width / 2 + currentGlyphMetrics.horizontalBearingX) * currentElementScale) * (1 - m_charWidthAdjDelta);
  2419. else
  2420. monoAdvance = (m_monoSpacing / 2 - (currentGlyphMetrics.width / 2 + currentGlyphMetrics.horizontalBearingX) * currentElementScale) * (1 - m_charWidthAdjDelta);
  2421. m_xAdvance += monoAdvance;
  2422. }
  2423. #endregion
  2424. // Set Padding based on selected font style
  2425. #region Handle Style Padding
  2426. float boldSpacingAdjustment;
  2427. float style_padding;
  2428. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_FontStyleInternal & FontStyles.Bold) == FontStyles.Bold)) // Checks for any combination of Bold Style.
  2429. {
  2430. if (m_currentMaterial != null && m_currentMaterial.HasProperty(ShaderUtilities.ID_GradientScale))
  2431. {
  2432. float gradientScale = m_currentMaterial.GetFloat(ShaderUtilities.ID_GradientScale);
  2433. style_padding = m_currentFontAsset.boldStyle / 4.0f * gradientScale * m_currentMaterial.GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  2434. // Clamp overall padding to Gradient Scale size.
  2435. if (style_padding + padding > gradientScale)
  2436. padding = gradientScale - style_padding;
  2437. }
  2438. else
  2439. style_padding = 0;
  2440. boldSpacingAdjustment = m_currentFontAsset.boldSpacing;
  2441. }
  2442. else
  2443. {
  2444. if (m_currentMaterial != null && m_currentMaterial.HasProperty(ShaderUtilities.ID_GradientScale) && m_currentMaterial.HasProperty(ShaderUtilities.ID_ScaleRatio_A))
  2445. {
  2446. float gradientScale = m_currentMaterial.GetFloat(ShaderUtilities.ID_GradientScale);
  2447. style_padding = m_currentFontAsset.normalStyle / 4.0f * gradientScale * m_currentMaterial.GetFloat(ShaderUtilities.ID_ScaleRatio_A);
  2448. // Clamp overall padding to Gradient Scale size.
  2449. if (style_padding + padding > gradientScale)
  2450. padding = gradientScale - style_padding;
  2451. }
  2452. else
  2453. style_padding = 0;
  2454. boldSpacingAdjustment = 0;
  2455. }
  2456. #endregion Handle Style Padding
  2457. // Determine the position of the vertices of the Character or Sprite.
  2458. #region Calculate Vertices Position
  2459. k_CalculateVerticesPositionMarker.Begin();
  2460. Vector3 top_left;
  2461. top_left.x = m_xAdvance + ((currentGlyphMetrics.horizontalBearingX * m_FXScale.x - padding - style_padding + glyphAdjustments.xPlacement) * currentElementScale * (1 - m_charWidthAdjDelta));
  2462. top_left.y = baselineOffset + (currentGlyphMetrics.horizontalBearingY + padding + glyphAdjustments.yPlacement) * currentElementScale - m_lineOffset + m_baselineOffset;
  2463. top_left.z = 0;
  2464. Vector3 bottom_left;
  2465. bottom_left.x = top_left.x;
  2466. bottom_left.y = top_left.y - ((currentGlyphMetrics.height + padding * 2) * currentElementScale);
  2467. bottom_left.z = 0;
  2468. Vector3 top_right;
  2469. top_right.x = bottom_left.x + ((currentGlyphMetrics.width * m_FXScale.x + padding * 2 + style_padding * 2) * currentElementScale * (1 - m_charWidthAdjDelta));
  2470. top_right.y = top_left.y;
  2471. top_right.z = 0;
  2472. Vector3 bottom_right;
  2473. bottom_right.x = top_right.x;
  2474. bottom_right.y = bottom_left.y;
  2475. bottom_right.z = 0;
  2476. k_CalculateVerticesPositionMarker.End();
  2477. #endregion
  2478. // Check if we need to Shear the rectangles for Italic styles
  2479. #region Handle Italic & Shearing
  2480. if (m_textElementType == TMP_TextElementType.Character && !isUsingAltTypeface && ((m_FontStyleInternal & FontStyles.Italic) == FontStyles.Italic))
  2481. {
  2482. // Shift Top vertices forward by half (Shear Value * height of character) and Bottom vertices back by same amount.
  2483. float shear_value = m_ItalicAngle * 0.01f;
  2484. float midPoint = ((m_currentFontAsset.m_FaceInfo.capLine - (m_currentFontAsset.m_FaceInfo.baseline + m_baselineOffset)) / 2) * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale;
  2485. Vector3 topShear = new Vector3(shear_value * ((currentGlyphMetrics.horizontalBearingY + padding + style_padding - midPoint) * currentElementScale), 0, 0);
  2486. Vector3 bottomShear = new Vector3(shear_value * (((currentGlyphMetrics.horizontalBearingY - currentGlyphMetrics.height - padding - style_padding - midPoint)) * currentElementScale), 0, 0);
  2487. top_left += topShear;
  2488. bottom_left += bottomShear;
  2489. top_right += topShear;
  2490. bottom_right += bottomShear;
  2491. }
  2492. #endregion Handle Italics & Shearing
  2493. // Handle Character FX Rotation
  2494. #region Handle Character FX Rotation
  2495. if (m_FXRotation != Quaternion.identity)
  2496. {
  2497. Matrix4x4 rotationMatrix = Matrix4x4.Rotate(m_FXRotation);
  2498. Vector3 positionOffset = (top_right + bottom_left) / 2;
  2499. top_left = rotationMatrix.MultiplyPoint3x4(top_left - positionOffset) + positionOffset;
  2500. bottom_left = rotationMatrix.MultiplyPoint3x4(bottom_left - positionOffset) + positionOffset;
  2501. top_right = rotationMatrix.MultiplyPoint3x4(top_right - positionOffset) + positionOffset;
  2502. bottom_right = rotationMatrix.MultiplyPoint3x4(bottom_right - positionOffset) + positionOffset;
  2503. }
  2504. #endregion
  2505. // Store vertex information for the character or sprite.
  2506. m_textInfo.characterInfo[m_characterCount].bottomLeft = bottom_left;
  2507. m_textInfo.characterInfo[m_characterCount].topLeft = top_left;
  2508. m_textInfo.characterInfo[m_characterCount].topRight = top_right;
  2509. m_textInfo.characterInfo[m_characterCount].bottomRight = bottom_right;
  2510. m_textInfo.characterInfo[m_characterCount].origin = m_xAdvance + glyphAdjustments.xPlacement * currentElementScale;
  2511. m_textInfo.characterInfo[m_characterCount].baseLine = (baselineOffset - m_lineOffset + m_baselineOffset) + glyphAdjustments.yPlacement * currentElementScale;
  2512. m_textInfo.characterInfo[m_characterCount].aspectRatio = (top_right.x - bottom_left.x) / (top_left.y - bottom_left.y);
  2513. // Compute text metrics
  2514. #region Compute Ascender & Descender values
  2515. k_ComputeTextMetricsMarker.Begin();
  2516. // Element Ascender in line space
  2517. float elementAscender = m_textElementType == TMP_TextElementType.Character
  2518. ? elementAscentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset
  2519. : elementAscentLine * currentElementScale + m_baselineOffset;
  2520. // Element Descender in line space
  2521. float elementDescender = m_textElementType == TMP_TextElementType.Character
  2522. ? elementDescentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset
  2523. : elementDescentLine * currentElementScale + m_baselineOffset;
  2524. float adjustedAscender = elementAscender;
  2525. float adjustedDescender = elementDescender;
  2526. // Max line ascender and descender in line space
  2527. bool isFirstCharacterOfLine = m_characterCount == m_firstCharacterOfLine;
  2528. if (isFirstCharacterOfLine || isWhiteSpace == false)
  2529. {
  2530. // Special handling for Superscript and Subscript where we use the unadjusted line ascender and descender
  2531. if (m_baselineOffset != 0)
  2532. {
  2533. adjustedAscender = Mathf.Max((elementAscender - m_baselineOffset) / m_fontScaleMultiplier, adjustedAscender);
  2534. adjustedDescender = Mathf.Min((elementDescender - m_baselineOffset) / m_fontScaleMultiplier, adjustedDescender);
  2535. }
  2536. m_maxLineAscender = Mathf.Max(adjustedAscender, m_maxLineAscender);
  2537. m_maxLineDescender = Mathf.Min(adjustedDescender, m_maxLineDescender);
  2538. }
  2539. // Element Ascender and Descender in object space
  2540. if (isFirstCharacterOfLine || isWhiteSpace == false)
  2541. {
  2542. m_textInfo.characterInfo[m_characterCount].adjustedAscender = adjustedAscender;
  2543. m_textInfo.characterInfo[m_characterCount].adjustedDescender = adjustedDescender;
  2544. m_ElementAscender = m_textInfo.characterInfo[m_characterCount].ascender = elementAscender - m_lineOffset;
  2545. m_ElementDescender = m_textInfo.characterInfo[m_characterCount].descender = elementDescender - m_lineOffset;
  2546. }
  2547. else
  2548. {
  2549. m_textInfo.characterInfo[m_characterCount].adjustedAscender = m_maxLineAscender;
  2550. m_textInfo.characterInfo[m_characterCount].adjustedDescender = m_maxLineDescender;
  2551. m_ElementAscender = m_textInfo.characterInfo[m_characterCount].ascender = m_maxLineAscender - m_lineOffset;
  2552. m_ElementDescender = m_textInfo.characterInfo[m_characterCount].descender = m_maxLineDescender - m_lineOffset;
  2553. }
  2554. // Max text object ascender and cap height
  2555. if (m_lineNumber == 0 || m_isNewPage)
  2556. {
  2557. if (isFirstCharacterOfLine || isWhiteSpace == false)
  2558. {
  2559. m_maxTextAscender = m_maxLineAscender;
  2560. m_maxCapHeight = Mathf.Max(m_maxCapHeight, m_currentFontAsset.m_FaceInfo.capLine * currentElementScale / smallCapsMultiplier);
  2561. }
  2562. }
  2563. // Page ascender
  2564. if (m_lineOffset == 0)
  2565. {
  2566. if (isFirstCharacterOfLine || isWhiteSpace == false)
  2567. m_PageAscender = m_PageAscender > elementAscender ? m_PageAscender : elementAscender;
  2568. }
  2569. k_ComputeTextMetricsMarker.End();
  2570. #endregion
  2571. // Set Characters to not visible by default.
  2572. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  2573. bool isJustifiedOrFlush = (m_lineJustification & HorizontalAlignmentOptions.Flush) == HorizontalAlignmentOptions.Flush || (m_lineJustification & HorizontalAlignmentOptions.Justified) == HorizontalAlignmentOptions.Justified;
  2574. // Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
  2575. #region Handle Visible Characters
  2576. if (charCode == 9 || ((m_TextWrappingMode == TextWrappingModes.PreserveWhitespace || m_TextWrappingMode == TextWrappingModes.PreserveWhitespaceNoWrap) && (isWhiteSpace || charCode == 0x200B)) || (isWhiteSpace == false && charCode != 0x200B && charCode != 0xAD && charCode != 0x03) || (charCode == 0xAD && isSoftHyphenIgnored == false) || m_textElementType == TMP_TextElementType.Sprite)
  2577. {
  2578. k_HandleVisibleCharacterMarker.Begin();
  2579. m_textInfo.characterInfo[m_characterCount].isVisible = true;
  2580. #region Experimental Margin Shaper
  2581. //Vector2 shapedMargins;
  2582. //if (marginShaper)
  2583. //{
  2584. // shapedMargins = m_marginShaper.GetShapedMargins(m_textInfo.characterInfo[m_characterCount].baseLine);
  2585. // if (shapedMargins.x < margins.x)
  2586. // {
  2587. // shapedMargins.x = m_marginLeft;
  2588. // }
  2589. // else
  2590. // {
  2591. // shapedMargins.x += m_marginLeft - margins.x;
  2592. // }
  2593. // if (shapedMargins.y < margins.z)
  2594. // {
  2595. // shapedMargins.y = m_marginRight;
  2596. // }
  2597. // else
  2598. // {
  2599. // shapedMargins.y += m_marginRight - margins.z;
  2600. // }
  2601. //}
  2602. //else
  2603. //{
  2604. // shapedMargins.x = m_marginLeft;
  2605. // shapedMargins.y = m_marginRight;
  2606. //}
  2607. //width = marginWidth + 0.0001f - shapedMargins.x - shapedMargins.y;
  2608. //if (m_width != -1 && m_width < width)
  2609. //{
  2610. // width = m_width;
  2611. //}
  2612. //m_textInfo.lineInfo[m_lineNumber].marginLeft = shapedMargins.x;
  2613. #endregion
  2614. float marginLeft = m_marginLeft;
  2615. float marginRight = m_marginRight;
  2616. // Injected characters do not override margins
  2617. if (isInjectedCharacter)
  2618. {
  2619. marginLeft = m_textInfo.lineInfo[m_lineNumber].marginLeft;
  2620. marginRight = m_textInfo.lineInfo[m_lineNumber].marginRight;
  2621. }
  2622. widthOfTextArea = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - marginLeft - marginRight, m_width) : marginWidth + 0.0001f - marginLeft - marginRight;
  2623. // Calculate the line breaking width of the text.
  2624. float textWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? currentGlyphMetrics.horizontalAdvance : 0) * (1 - m_charWidthAdjDelta) * (charCode == 0xAD ? currentElementUnmodifiedScale : currentElementScale);
  2625. float textHeight = m_maxTextAscender - (m_maxLineDescender - m_lineOffset) + (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0);
  2626. int testedCharacterCount = m_characterCount;
  2627. // Handling of current line Vertical Bounds
  2628. #region Current Line Vertical Bounds Check
  2629. if (textHeight > marginHeight + 0.0001f)
  2630. {
  2631. k_HandleVerticalLineBreakingMarker.Begin();
  2632. // Set isTextOverflowing and firstOverflowCharacterIndex
  2633. if (m_firstOverflowCharacterIndex == -1)
  2634. m_firstOverflowCharacterIndex = m_characterCount;
  2635. // Check if Auto-Size is enabled
  2636. if (m_enableAutoSizing)
  2637. {
  2638. // Handle Line spacing adjustments
  2639. #region Line Spacing Adjustments
  2640. if (m_lineSpacingDelta > m_lineSpacingMax && m_lineOffset > 0 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2641. {
  2642. float adjustmentDelta = (marginHeight - textHeight) / m_lineNumber;
  2643. m_lineSpacingDelta = Mathf.Max(m_lineSpacingDelta + adjustmentDelta / baseScale, m_lineSpacingMax);
  2644. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Line Spacing. Delta of [" + m_lineSpacingDelta.ToString("f3") + "].");
  2645. k_HandleVerticalLineBreakingMarker.End();
  2646. k_HandleVisibleCharacterMarker.End();
  2647. k_GenerateTextPhaseIMarker.End();
  2648. k_GenerateTextMarker.End();
  2649. return;
  2650. }
  2651. #endregion
  2652. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  2653. #region Text Auto-Sizing (Text greater than vertical bounds)
  2654. if (m_fontSize > m_fontSizeMin && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2655. {
  2656. m_maxFontSize = m_fontSize;
  2657. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2658. m_fontSize -= sizeDelta;
  2659. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  2660. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2661. k_HandleVerticalLineBreakingMarker.End();
  2662. k_HandleVisibleCharacterMarker.End();
  2663. k_GenerateTextPhaseIMarker.End();
  2664. k_GenerateTextMarker.End();
  2665. return;
  2666. }
  2667. #endregion Text Auto-Sizing
  2668. }
  2669. // Handle Vertical Overflow on current line
  2670. switch (m_overflowMode)
  2671. {
  2672. case TextOverflowModes.Overflow:
  2673. case TextOverflowModes.ScrollRect:
  2674. case TextOverflowModes.Masking:
  2675. // Nothing happens as vertical bounds are ignored in this mode.
  2676. break;
  2677. case TextOverflowModes.Truncate:
  2678. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  2679. characterToSubstitute.index = testedCharacterCount;
  2680. characterToSubstitute.unicode = 0x03;
  2681. k_HandleVerticalLineBreakingMarker.End();
  2682. k_HandleVisibleCharacterMarker.End();
  2683. continue;
  2684. case TextOverflowModes.Ellipsis:
  2685. if (m_EllipsisInsertionCandidateStack.Count == 0)
  2686. {
  2687. i = -1;
  2688. m_characterCount = 0;
  2689. characterToSubstitute.index = 0;
  2690. characterToSubstitute.unicode = 0x03;
  2691. m_firstCharacterOfLine = 0;
  2692. k_HandleVerticalLineBreakingMarker.End();
  2693. k_HandleVisibleCharacterMarker.End();
  2694. continue;
  2695. }
  2696. var ellipsisState = m_EllipsisInsertionCandidateStack.Pop();
  2697. i = RestoreWordWrappingState(ref ellipsisState);
  2698. i -= 1;
  2699. m_characterCount -= 1;
  2700. characterToSubstitute.index = m_characterCount;
  2701. characterToSubstitute.unicode = 0x2026;
  2702. restoreCount += 1;
  2703. k_HandleVerticalLineBreakingMarker.End();
  2704. k_HandleVisibleCharacterMarker.End();
  2705. continue;
  2706. case TextOverflowModes.Linked:
  2707. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  2708. if (m_linkedTextComponent != null)
  2709. {
  2710. m_linkedTextComponent.text = text;
  2711. m_linkedTextComponent.m_inputSource = m_inputSource;
  2712. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  2713. m_linkedTextComponent.ForceMeshUpdate();
  2714. m_isTextTruncated = true;
  2715. }
  2716. // Truncate remaining text
  2717. characterToSubstitute.index = testedCharacterCount;
  2718. characterToSubstitute.unicode = 0x03;
  2719. k_HandleVerticalLineBreakingMarker.End();
  2720. k_HandleVisibleCharacterMarker.End();
  2721. continue;
  2722. case TextOverflowModes.Page:
  2723. // End layout of text if first character / page doesn't fit.
  2724. if (i < 0 || testedCharacterCount == 0)
  2725. {
  2726. i = -1;
  2727. m_characterCount = 0;
  2728. characterToSubstitute.index = 0;
  2729. characterToSubstitute.unicode = 0x03;
  2730. k_HandleVerticalLineBreakingMarker.End();
  2731. k_HandleVisibleCharacterMarker.End();
  2732. continue;
  2733. }
  2734. else if (m_maxLineAscender - m_maxLineDescender > marginHeight + 0.0001f)
  2735. {
  2736. // Current line exceeds the height of the text container
  2737. // as such we stop on the previous line.
  2738. i = RestoreWordWrappingState(ref m_SavedLineState);
  2739. characterToSubstitute.index = testedCharacterCount;
  2740. characterToSubstitute.unicode = 0x03;
  2741. k_HandleVerticalLineBreakingMarker.End();
  2742. k_HandleVisibleCharacterMarker.End();
  2743. continue;
  2744. }
  2745. // Go back to previous line and re-layout
  2746. i = RestoreWordWrappingState(ref m_SavedLineState);
  2747. m_isNewPage = true;
  2748. m_firstCharacterOfLine = m_characterCount;
  2749. m_maxLineAscender = k_LargeNegativeFloat;
  2750. m_maxLineDescender = k_LargePositiveFloat;
  2751. m_startOfLineAscender = 0;
  2752. m_xAdvance = 0 + tag_Indent;
  2753. m_lineOffset = 0;
  2754. m_maxTextAscender = 0;
  2755. m_PageAscender = 0;
  2756. m_lineNumber += 1;
  2757. m_pageNumber += 1;
  2758. // Should consider saving page data here
  2759. k_HandleVerticalLineBreakingMarker.End();
  2760. k_HandleVisibleCharacterMarker.End();
  2761. continue;
  2762. }
  2763. k_HandleVerticalLineBreakingMarker.End();
  2764. }
  2765. #endregion
  2766. // Handling of Horizontal Bounds
  2767. #region Current Line Horizontal Bounds Check
  2768. if (isBaseGlyph && textWidth > widthOfTextArea * (isJustifiedOrFlush ? 1.05f : 1.0f))
  2769. {
  2770. k_HandleHorizontalLineBreakingMarker.Begin();
  2771. // Handle Line Breaking (if still possible)
  2772. if (m_TextWrappingMode != TextWrappingModes.NoWrap && m_TextWrappingMode != TextWrappingModes.PreserveWhitespaceNoWrap && m_characterCount != m_firstCharacterOfLine)
  2773. {
  2774. // Restore state to previous safe line breaking
  2775. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  2776. // Compute potential new line offset in the event a line break is needed.
  2777. float lineOffsetDelta = 0;
  2778. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  2779. {
  2780. float ascender = m_textInfo.characterInfo[m_characterCount].adjustedAscender;
  2781. lineOffsetDelta = (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0) - m_maxLineDescender + ascender + (lineGap + m_lineSpacingDelta) * baseScale + m_lineSpacing * currentEmScale;
  2782. }
  2783. else
  2784. {
  2785. lineOffsetDelta = m_lineHeight + m_lineSpacing * currentEmScale;
  2786. m_IsDrivenLineSpacing = true;
  2787. }
  2788. // Calculate new text height
  2789. float newTextHeight = m_maxTextAscender + lineOffsetDelta + m_lineOffset - m_textInfo.characterInfo[m_characterCount].adjustedDescender;
  2790. // Replace Soft Hyphen by Hyphen Minus 0x2D
  2791. #region Handle Soft Hyphenation
  2792. if (m_textInfo.characterInfo[m_characterCount - 1].character == 0xAD && isSoftHyphenIgnored == false)
  2793. {
  2794. // Only inject Hyphen Minus if new line is possible
  2795. if (m_overflowMode == TextOverflowModes.Overflow || newTextHeight < marginHeight + 0.0001f)
  2796. {
  2797. characterToSubstitute.index = m_characterCount - 1;
  2798. characterToSubstitute.unicode = 0x2D;
  2799. i -= 1;
  2800. m_characterCount -= 1;
  2801. k_HandleHorizontalLineBreakingMarker.End();
  2802. k_HandleVisibleCharacterMarker.End();
  2803. continue;
  2804. }
  2805. }
  2806. isSoftHyphenIgnored = false;
  2807. // Ignore Soft Hyphen to prevent it from wrapping
  2808. if (m_textInfo.characterInfo[m_characterCount].character == 0xAD)
  2809. {
  2810. isSoftHyphenIgnored = true;
  2811. k_HandleHorizontalLineBreakingMarker.End();
  2812. k_HandleVisibleCharacterMarker.End();
  2813. continue;
  2814. }
  2815. #endregion
  2816. // Adjust character spacing before breaking up word if auto size is enabled
  2817. if (m_enableAutoSizing && isFirstWordOfLine)
  2818. {
  2819. // Handle Character Width Adjustments
  2820. #region Character Width Adjustments
  2821. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2822. {
  2823. float adjustedTextWidth = textWidth;
  2824. // Determine full width of the text
  2825. if (m_charWidthAdjDelta > 0)
  2826. adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  2827. float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  2828. m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  2829. m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  2830. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  2831. k_HandleHorizontalLineBreakingMarker.End();
  2832. k_HandleVisibleCharacterMarker.End();
  2833. k_GenerateTextPhaseIMarker.End();
  2834. k_GenerateTextMarker.End();
  2835. return;
  2836. }
  2837. #endregion
  2838. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  2839. #region Text Auto-Sizing (Text greater than vertical bounds)
  2840. if (m_fontSize > m_fontSizeMin && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2841. {
  2842. m_maxFontSize = m_fontSize;
  2843. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2844. m_fontSize -= sizeDelta;
  2845. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  2846. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2847. k_HandleHorizontalLineBreakingMarker.End();
  2848. k_HandleVisibleCharacterMarker.End();
  2849. k_GenerateTextPhaseIMarker.End();
  2850. k_GenerateTextMarker.End();
  2851. return;
  2852. }
  2853. #endregion Text Auto-Sizing
  2854. }
  2855. // Special handling if first word of line and non breaking space
  2856. int savedSoftLineBreakingSpace = m_SavedSoftLineBreakState.previous_WordBreak;
  2857. if (isFirstWordOfLine && savedSoftLineBreakingSpace != -1)
  2858. {
  2859. if (savedSoftLineBreakingSpace != lastSoftLineBreak)
  2860. {
  2861. i = RestoreWordWrappingState(ref m_SavedSoftLineBreakState);
  2862. lastSoftLineBreak = savedSoftLineBreakingSpace;
  2863. // check if soft hyphen
  2864. if (m_textInfo.characterInfo[m_characterCount - 1].character == 0xAD)
  2865. {
  2866. characterToSubstitute.index = m_characterCount - 1;
  2867. characterToSubstitute.unicode = 0x2D;
  2868. i -= 1;
  2869. m_characterCount -= 1;
  2870. k_HandleHorizontalLineBreakingMarker.End();
  2871. k_HandleVisibleCharacterMarker.End();
  2872. continue;
  2873. }
  2874. }
  2875. }
  2876. // Determine if new line of text would exceed the vertical bounds of text container
  2877. if (newTextHeight > marginHeight + 0.0001f)
  2878. {
  2879. k_HandleVerticalLineBreakingMarker.Begin();
  2880. // Set isTextOverflowing and firstOverflowCharacterIndex
  2881. if (m_firstOverflowCharacterIndex == -1)
  2882. m_firstOverflowCharacterIndex = m_characterCount;
  2883. // Check if Auto-Size is enabled
  2884. if (m_enableAutoSizing)
  2885. {
  2886. // Handle Line spacing adjustments
  2887. #region Line Spacing Adjustments
  2888. if (m_lineSpacingDelta > m_lineSpacingMax && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2889. {
  2890. float adjustmentDelta = (marginHeight - newTextHeight) / (m_lineNumber + 1);
  2891. m_lineSpacingDelta = Mathf.Max(m_lineSpacingDelta + adjustmentDelta / baseScale, m_lineSpacingMax);
  2892. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Line Spacing. Delta of [" + m_lineSpacingDelta.ToString("f3") + "].");
  2893. k_HandleVerticalLineBreakingMarker.End();
  2894. k_HandleHorizontalLineBreakingMarker.End();
  2895. k_HandleVisibleCharacterMarker.End();
  2896. k_GenerateTextPhaseIMarker.End();
  2897. k_GenerateTextMarker.End();
  2898. return;
  2899. }
  2900. #endregion
  2901. // Handle Character Width Adjustments
  2902. #region Character Width Adjustments
  2903. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2904. {
  2905. float adjustedTextWidth = textWidth;
  2906. // Determine full width of the text
  2907. if (m_charWidthAdjDelta > 0)
  2908. adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  2909. float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  2910. m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  2911. m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  2912. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  2913. k_HandleVerticalLineBreakingMarker.End();
  2914. k_HandleHorizontalLineBreakingMarker.End();
  2915. k_HandleVisibleCharacterMarker.End();
  2916. k_GenerateTextPhaseIMarker.End();
  2917. k_GenerateTextMarker.End();
  2918. return;
  2919. }
  2920. #endregion
  2921. // Handle Text Auto-sizing resulting from text exceeding vertical bounds.
  2922. #region Text Auto-Sizing (Text greater than vertical bounds)
  2923. if (m_fontSize > m_fontSizeMin && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  2924. {
  2925. m_maxFontSize = m_fontSize;
  2926. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  2927. m_fontSize -= sizeDelta;
  2928. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  2929. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  2930. k_HandleVerticalLineBreakingMarker.End();
  2931. k_HandleHorizontalLineBreakingMarker.End();
  2932. k_HandleVisibleCharacterMarker.End();
  2933. k_GenerateTextPhaseIMarker.End();
  2934. k_GenerateTextMarker.End();
  2935. return;
  2936. }
  2937. #endregion Text Auto-Sizing
  2938. }
  2939. // Check Text Overflow Modes
  2940. switch (m_overflowMode)
  2941. {
  2942. case TextOverflowModes.Overflow:
  2943. case TextOverflowModes.ScrollRect:
  2944. case TextOverflowModes.Masking:
  2945. InsertNewLine(i, baseScale, currentElementScale, currentEmScale, boldSpacingAdjustment, characterSpacingAdjustment, widthOfTextArea, lineGap, ref isMaxVisibleDescenderSet, ref maxVisibleDescender);
  2946. isStartOfNewLine = true;
  2947. isFirstWordOfLine = true;
  2948. k_HandleVerticalLineBreakingMarker.End();
  2949. k_HandleHorizontalLineBreakingMarker.End();
  2950. k_HandleVisibleCharacterMarker.End();
  2951. continue;
  2952. case TextOverflowModes.Truncate:
  2953. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  2954. characterToSubstitute.index = testedCharacterCount;
  2955. characterToSubstitute.unicode = 0x03;
  2956. k_HandleVerticalLineBreakingMarker.End();
  2957. k_HandleHorizontalLineBreakingMarker.End();
  2958. k_HandleVisibleCharacterMarker.End();
  2959. continue;
  2960. case TextOverflowModes.Ellipsis:
  2961. if (m_EllipsisInsertionCandidateStack.Count == 0)
  2962. {
  2963. i = -1;
  2964. m_characterCount = 0;
  2965. characterToSubstitute.index = 0;
  2966. characterToSubstitute.unicode = 0x03;
  2967. m_firstCharacterOfLine = 0;
  2968. k_HandleVerticalLineBreakingMarker.End();
  2969. k_HandleHorizontalLineBreakingMarker.End();
  2970. k_HandleVisibleCharacterMarker.End();
  2971. continue;
  2972. }
  2973. var ellipsisState = m_EllipsisInsertionCandidateStack.Pop();
  2974. i = RestoreWordWrappingState(ref ellipsisState);
  2975. i -= 1;
  2976. m_characterCount -= 1;
  2977. characterToSubstitute.index = m_characterCount;
  2978. characterToSubstitute.unicode = 0x2026;
  2979. restoreCount += 1;
  2980. k_HandleVerticalLineBreakingMarker.End();
  2981. k_HandleHorizontalLineBreakingMarker.End();
  2982. k_HandleVisibleCharacterMarker.End();
  2983. continue;
  2984. case TextOverflowModes.Linked:
  2985. if (m_linkedTextComponent != null)
  2986. {
  2987. m_linkedTextComponent.text = text;
  2988. m_linkedTextComponent.m_inputSource = m_inputSource;
  2989. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  2990. m_linkedTextComponent.ForceMeshUpdate();
  2991. m_isTextTruncated = true;
  2992. }
  2993. // Truncate remaining text
  2994. characterToSubstitute.index = m_characterCount;
  2995. characterToSubstitute.unicode = 0x03;
  2996. k_HandleVerticalLineBreakingMarker.End();
  2997. k_HandleHorizontalLineBreakingMarker.End();
  2998. k_HandleVisibleCharacterMarker.End();
  2999. continue;
  3000. case TextOverflowModes.Page:
  3001. // Add new page
  3002. m_isNewPage = true;
  3003. InsertNewLine(i, baseScale, currentElementScale, currentEmScale, boldSpacingAdjustment, characterSpacingAdjustment, widthOfTextArea, lineGap, ref isMaxVisibleDescenderSet, ref maxVisibleDescender);
  3004. m_startOfLineAscender = 0;
  3005. m_lineOffset = 0;
  3006. m_maxTextAscender = 0;
  3007. m_PageAscender = 0;
  3008. m_pageNumber += 1;
  3009. isStartOfNewLine = true;
  3010. isFirstWordOfLine = true;
  3011. k_HandleVerticalLineBreakingMarker.End();
  3012. k_HandleHorizontalLineBreakingMarker.End();
  3013. k_HandleVisibleCharacterMarker.End();
  3014. continue;
  3015. }
  3016. }
  3017. else
  3018. {
  3019. //if (m_enableAutoSizing && isFirstWordOfLine)
  3020. //{
  3021. // // Handle Character Width Adjustments
  3022. // #region Character Width Adjustments
  3023. // if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100 && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  3024. // {
  3025. // //m_AutoSizeIterationCount = 0;
  3026. // float adjustedTextWidth = textWidth;
  3027. // // Determine full width of the text
  3028. // if (m_charWidthAdjDelta > 0)
  3029. // adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  3030. // float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  3031. // m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  3032. // m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  3033. // //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  3034. // GenerateTextMesh();
  3035. // return;
  3036. // }
  3037. // #endregion
  3038. //}
  3039. // New line of text does not exceed vertical bounds of text container
  3040. InsertNewLine(i, baseScale, currentElementScale, currentEmScale, boldSpacingAdjustment, characterSpacingAdjustment, widthOfTextArea, lineGap, ref isMaxVisibleDescenderSet, ref maxVisibleDescender);
  3041. isStartOfNewLine = true;
  3042. isFirstWordOfLine = true;
  3043. k_HandleHorizontalLineBreakingMarker.End();
  3044. k_HandleVisibleCharacterMarker.End();
  3045. continue;
  3046. }
  3047. }
  3048. else
  3049. {
  3050. if (m_enableAutoSizing && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  3051. {
  3052. // Handle Character Width Adjustments
  3053. #region Character Width Adjustments
  3054. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  3055. {
  3056. float adjustedTextWidth = textWidth;
  3057. // Determine full width of the text
  3058. if (m_charWidthAdjDelta > 0)
  3059. adjustedTextWidth /= 1f - m_charWidthAdjDelta;
  3060. float adjustmentDelta = textWidth - (widthOfTextArea - 0.0001f) * (isJustifiedOrFlush ? 1.05f : 1.0f);
  3061. m_charWidthAdjDelta += adjustmentDelta / adjustedTextWidth;
  3062. m_charWidthAdjDelta = Mathf.Min(m_charWidthAdjDelta, m_charWidthMaxAdj / 100);
  3063. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Character Width by " + (m_charWidthAdjDelta * 100) + "%");
  3064. k_HandleHorizontalLineBreakingMarker.End();
  3065. k_HandleVisibleCharacterMarker.End();
  3066. k_GenerateTextPhaseIMarker.End();
  3067. k_GenerateTextMarker.End();
  3068. return;
  3069. }
  3070. #endregion
  3071. // Handle Text Auto-sizing resulting from text exceeding horizontal bounds.
  3072. #region Text Exceeds Horizontal Bounds - Reducing Point Size
  3073. if (m_fontSize > m_fontSizeMin)
  3074. {
  3075. // Reset character width adjustment delta
  3076. //m_charWidthAdjDelta = 0;
  3077. // Adjust Point Size
  3078. m_maxFontSize = m_fontSize;
  3079. float sizeDelta = Mathf.Max((m_fontSize - m_minFontSize) / 2, 0.05f);
  3080. m_fontSize -= sizeDelta;
  3081. m_fontSize = Mathf.Max((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMin);
  3082. //Debug.Log("[" + m_AutoSizeIterationCount + "] Reducing Point Size from [" + m_maxFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  3083. k_HandleHorizontalLineBreakingMarker.End();
  3084. k_HandleVisibleCharacterMarker.End();
  3085. k_GenerateTextPhaseIMarker.End();
  3086. k_GenerateTextMarker.End();
  3087. return;
  3088. }
  3089. #endregion
  3090. }
  3091. // Check Text Overflow Modes
  3092. switch (m_overflowMode)
  3093. {
  3094. case TextOverflowModes.Overflow:
  3095. case TextOverflowModes.ScrollRect:
  3096. case TextOverflowModes.Masking:
  3097. // Nothing happens as horizontal bounds are ignored in this mode.
  3098. break;
  3099. case TextOverflowModes.Truncate:
  3100. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  3101. characterToSubstitute.index = testedCharacterCount;
  3102. characterToSubstitute.unicode = 0x03;
  3103. k_HandleHorizontalLineBreakingMarker.End();
  3104. k_HandleVisibleCharacterMarker.End();
  3105. continue;
  3106. case TextOverflowModes.Ellipsis:
  3107. if (m_EllipsisInsertionCandidateStack.Count == 0)
  3108. {
  3109. i = -1;
  3110. m_characterCount = 0;
  3111. characterToSubstitute.index = 0;
  3112. characterToSubstitute.unicode = 0x03;
  3113. m_firstCharacterOfLine = 0;
  3114. k_HandleHorizontalLineBreakingMarker.End();
  3115. k_HandleVisibleCharacterMarker.End();
  3116. continue;
  3117. }
  3118. var ellipsisState = m_EllipsisInsertionCandidateStack.Pop();
  3119. i = RestoreWordWrappingState(ref ellipsisState);
  3120. i -= 1;
  3121. m_characterCount -= 1;
  3122. characterToSubstitute.index = m_characterCount;
  3123. characterToSubstitute.unicode = 0x2026;
  3124. restoreCount += 1;
  3125. k_HandleHorizontalLineBreakingMarker.End();
  3126. k_HandleVisibleCharacterMarker.End();
  3127. continue;
  3128. case TextOverflowModes.Linked:
  3129. i = RestoreWordWrappingState(ref m_SavedWordWrapState);
  3130. if (m_linkedTextComponent != null)
  3131. {
  3132. m_linkedTextComponent.text = text;
  3133. m_linkedTextComponent.m_inputSource = m_inputSource;
  3134. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  3135. m_linkedTextComponent.ForceMeshUpdate();
  3136. m_isTextTruncated = true;
  3137. }
  3138. // Truncate text the overflows the vertical bounds
  3139. characterToSubstitute.index = m_characterCount;
  3140. characterToSubstitute.unicode = 0x03;
  3141. k_HandleHorizontalLineBreakingMarker.End();
  3142. k_HandleVisibleCharacterMarker.End();
  3143. continue;
  3144. }
  3145. }
  3146. k_HandleHorizontalLineBreakingMarker.End();
  3147. }
  3148. #endregion
  3149. // Special handling of characters that are not ignored at the end of a line.
  3150. if (isWhiteSpace)
  3151. {
  3152. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  3153. m_lastVisibleCharacterOfLine = m_characterCount;
  3154. m_lineVisibleSpaceCount = m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
  3155. m_textInfo.lineInfo[m_lineNumber].marginLeft = marginLeft;
  3156. m_textInfo.lineInfo[m_lineNumber].marginRight = marginRight;
  3157. m_textInfo.spaceCount += 1;
  3158. if (charCode == 0xA0)
  3159. m_textInfo.lineInfo[m_lineNumber].controlCharacterCount += 1;
  3160. }
  3161. else if (charCode == 0xAD)
  3162. {
  3163. m_textInfo.characterInfo[m_characterCount].isVisible = false;
  3164. }
  3165. else
  3166. {
  3167. // Determine Vertex Color
  3168. Color32 vertexColor;
  3169. if (m_overrideHtmlColors)
  3170. vertexColor = m_fontColor32;
  3171. else
  3172. vertexColor = m_htmlColor;
  3173. k_SaveGlyphVertexDataMarker.Begin();
  3174. // Store Character & Sprite Vertex Information
  3175. if (m_textElementType == TMP_TextElementType.Character)
  3176. {
  3177. // Save Character Vertex Data
  3178. SaveGlyphVertexInfo(padding, style_padding, vertexColor);
  3179. }
  3180. else if (m_textElementType == TMP_TextElementType.Sprite)
  3181. {
  3182. SaveSpriteVertexInfo(vertexColor);
  3183. }
  3184. k_SaveGlyphVertexDataMarker.End();
  3185. if (isStartOfNewLine)
  3186. {
  3187. isStartOfNewLine = false;
  3188. m_firstVisibleCharacterOfLine = m_characterCount;
  3189. }
  3190. m_lineVisibleCharacterCount += 1;
  3191. m_lastVisibleCharacterOfLine = m_characterCount;
  3192. m_textInfo.lineInfo[m_lineNumber].marginLeft = marginLeft;
  3193. m_textInfo.lineInfo[m_lineNumber].marginRight = marginRight;
  3194. }
  3195. k_HandleVisibleCharacterMarker.End();
  3196. }
  3197. else
  3198. {
  3199. k_HandleWhiteSpacesMarker.Begin();
  3200. // Special handling for text overflow linked mode
  3201. #region Check Vertical Bounds
  3202. if (m_overflowMode == TextOverflowModes.Linked && (charCode == 10 || charCode == 11))
  3203. {
  3204. float textHeight = m_maxTextAscender - (m_maxLineDescender - m_lineOffset) + (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0);
  3205. int testedCharacterCount = m_characterCount;
  3206. if (textHeight > marginHeight + 0.0001f)
  3207. {
  3208. // Set isTextOverflowing and firstOverflowCharacterIndex
  3209. if (m_firstOverflowCharacterIndex == -1)
  3210. m_firstOverflowCharacterIndex = m_characterCount;
  3211. i = RestoreWordWrappingState(ref m_SavedLastValidState);
  3212. if (m_linkedTextComponent != null)
  3213. {
  3214. m_linkedTextComponent.text = text;
  3215. m_linkedTextComponent.m_inputSource = m_inputSource;
  3216. m_linkedTextComponent.firstVisibleCharacter = m_characterCount;
  3217. m_linkedTextComponent.ForceMeshUpdate();
  3218. m_isTextTruncated = true;
  3219. }
  3220. // Truncate remaining text
  3221. characterToSubstitute.index = testedCharacterCount;
  3222. characterToSubstitute.unicode = 0x03;
  3223. k_HandleWhiteSpacesMarker.End();
  3224. continue;
  3225. }
  3226. }
  3227. #endregion
  3228. // Track # of spaces per line which is used for line justification.
  3229. if ((charCode == 10 || charCode == 11 || charCode == 0xA0 || charCode == 0x2007 || charCode == 0x2028 || charCode == 0x2029 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060)
  3230. {
  3231. m_textInfo.lineInfo[m_lineNumber].spaceCount += 1;
  3232. m_textInfo.spaceCount += 1;
  3233. }
  3234. // Special handling for control characters like <NBSP>
  3235. if (charCode == 0xA0)
  3236. m_textInfo.lineInfo[m_lineNumber].controlCharacterCount += 1;
  3237. k_HandleWhiteSpacesMarker.End();
  3238. }
  3239. #endregion Handle Visible Characters
  3240. // Tracking of potential insertion positions for Ellipsis character
  3241. #region Track Potential Insertion Location for Ellipsis
  3242. if (m_overflowMode == TextOverflowModes.Ellipsis && (isInjectedCharacter == false || charCode == 0x2D))
  3243. {
  3244. float fontScale = m_currentFontSize / m_Ellipsis.fontAsset.m_FaceInfo.pointSize * m_Ellipsis.fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  3245. float scale = fontScale * m_fontScaleMultiplier * m_Ellipsis.character.m_Scale * m_Ellipsis.character.m_Glyph.scale;
  3246. float marginLeft = m_marginLeft;
  3247. float marginRight = m_marginRight;
  3248. // Use the scale and margins of the previous character if Line Feed (LF) is not the first character of a line.
  3249. if (charCode == 0x0A && m_characterCount != m_firstCharacterOfLine)
  3250. {
  3251. fontScale = m_textInfo.characterInfo[m_characterCount - 1].pointSize / m_Ellipsis.fontAsset.m_FaceInfo.pointSize * m_Ellipsis.fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f);
  3252. scale = fontScale * m_fontScaleMultiplier * m_Ellipsis.character.m_Scale * m_Ellipsis.character.m_Glyph.scale;
  3253. marginLeft = m_textInfo.lineInfo[m_lineNumber].marginLeft;
  3254. marginRight = m_textInfo.lineInfo[m_lineNumber].marginRight;
  3255. }
  3256. float textHeight = m_maxTextAscender - (m_maxLineDescender - m_lineOffset) + (m_lineOffset > 0 && m_IsDrivenLineSpacing == false ? m_maxLineAscender - m_startOfLineAscender : 0);
  3257. float textWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? m_Ellipsis.character.m_Glyph.metrics.horizontalAdvance : 0) * (1 - m_charWidthAdjDelta) * scale;
  3258. float widthOfTextAreaForEllipsis = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - marginLeft - marginRight, m_width) : marginWidth + 0.0001f - marginLeft - marginRight;
  3259. if (textWidth < widthOfTextAreaForEllipsis * (isJustifiedOrFlush ? 1.05f : 1.0f) && textHeight < marginHeight + 0.0001f)
  3260. {
  3261. SaveWordWrappingState(ref m_SavedEllipsisState, i, m_characterCount);
  3262. m_EllipsisInsertionCandidateStack.Push(m_SavedEllipsisState);
  3263. }
  3264. }
  3265. #endregion
  3266. // Store Rectangle positions for each Character.
  3267. #region Store Character Data
  3268. m_textInfo.characterInfo[m_characterCount].lineNumber = m_lineNumber;
  3269. m_textInfo.characterInfo[m_characterCount].pageNumber = m_pageNumber;
  3270. if (charCode != 10 && charCode != 11 && charCode != 13 && isInjectedCharacter == false /* && charCode != 8230 */ || m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
  3271. m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  3272. #endregion Store Character Data
  3273. // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
  3274. #region XAdvance, Tabulation & Stops
  3275. k_ComputeCharacterAdvanceMarker.Begin();
  3276. if (charCode == 9)
  3277. {
  3278. float tabSize = m_currentFontAsset.m_FaceInfo.tabWidth * m_currentFontAsset.tabSize * currentElementScale;
  3279. float tabs = Mathf.Ceil(m_xAdvance / tabSize) * tabSize;
  3280. m_xAdvance = tabs > m_xAdvance ? tabs : m_xAdvance + tabSize;
  3281. }
  3282. else if (m_monoSpacing != 0)
  3283. {
  3284. float monoAdjustment;
  3285. if (m_duoSpace && (charCode == '.' || charCode == ':' || charCode == ','))
  3286. monoAdjustment = m_monoSpacing / 2 - monoAdvance;
  3287. else
  3288. monoAdjustment = m_monoSpacing - monoAdvance;
  3289. m_xAdvance += (monoAdjustment + ((m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment) * currentEmScale) + m_cSpacing) * (1 - m_charWidthAdjDelta);
  3290. if (isWhiteSpace || charCode == 0x200B)
  3291. m_xAdvance += m_wordSpacing * currentEmScale;
  3292. }
  3293. else if (m_isRightToLeft)
  3294. {
  3295. m_xAdvance -= ((glyphAdjustments.xAdvance * currentElementScale + (m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment + boldSpacingAdjustment) * currentEmScale + m_cSpacing) * (1 - m_charWidthAdjDelta));
  3296. if (isWhiteSpace || charCode == 0x200B)
  3297. m_xAdvance -= m_wordSpacing * currentEmScale;
  3298. }
  3299. else
  3300. {
  3301. m_xAdvance += ((currentGlyphMetrics.horizontalAdvance * m_FXScale.x + glyphAdjustments.xAdvance) * currentElementScale + (m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment + boldSpacingAdjustment) * currentEmScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  3302. if (isWhiteSpace || charCode == 0x200B)
  3303. m_xAdvance += m_wordSpacing * currentEmScale;
  3304. }
  3305. // Store xAdvance information
  3306. m_textInfo.characterInfo[m_characterCount].xAdvance = m_xAdvance;
  3307. k_ComputeCharacterAdvanceMarker.End();
  3308. #endregion Tabulation & Stops
  3309. // Handle Carriage Return
  3310. #region Carriage Return
  3311. if (charCode == 13)
  3312. {
  3313. k_HandleCarriageReturnMarker.Begin();
  3314. m_xAdvance = 0 + tag_Indent;
  3315. k_HandleCarriageReturnMarker.End();
  3316. }
  3317. #endregion Carriage Return
  3318. // Tracking of text overflow page mode
  3319. #region Save PageInfo
  3320. k_SavePageInfoMarker.Begin();
  3321. if (m_overflowMode == TextOverflowModes.Page && charCode != 10 && charCode != 11 && charCode != 13 && charCode != 0x2028 && charCode != 0x2029)
  3322. {
  3323. // Check if we need to increase allocations for the pageInfo array.
  3324. if (m_pageNumber + 1 > m_textInfo.pageInfo.Length)
  3325. TMP_TextInfo.Resize(ref m_textInfo.pageInfo, m_pageNumber + 1, true);
  3326. m_textInfo.pageInfo[m_pageNumber].ascender = m_PageAscender;
  3327. m_textInfo.pageInfo[m_pageNumber].descender = m_ElementDescender < m_textInfo.pageInfo[m_pageNumber].descender
  3328. ? m_ElementDescender
  3329. : m_textInfo.pageInfo[m_pageNumber].descender;
  3330. if (m_isNewPage)
  3331. {
  3332. m_isNewPage = false;
  3333. m_textInfo.pageInfo[m_pageNumber].firstCharacterIndex = m_characterCount;
  3334. }
  3335. // Last index
  3336. m_textInfo.pageInfo[m_pageNumber].lastCharacterIndex = m_characterCount;
  3337. }
  3338. k_SavePageInfoMarker.End();
  3339. #endregion Save PageInfo
  3340. // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
  3341. #region Check for Line Feed and Last Character
  3342. if (charCode == 10 || charCode == 11 || charCode == 0x03 || charCode == 0x2028 || charCode == 0x2029 || (charCode == 0x2D && isInjectedCharacter) || m_characterCount == totalCharacterCount - 1)
  3343. {
  3344. k_HandleLineTerminationMarker.Begin();
  3345. // Adjust current line spacing (if necessary) before inserting new line
  3346. float baselineAdjustmentDelta = m_maxLineAscender - m_startOfLineAscender;
  3347. if (m_lineOffset > 0 && Math.Abs(baselineAdjustmentDelta) > 0.01f && m_IsDrivenLineSpacing == false && !m_isNewPage)
  3348. {
  3349. //Debug.Log("Line Feed - Adjusting Line Spacing on line #" + m_lineNumber);
  3350. AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, baselineAdjustmentDelta);
  3351. m_ElementDescender -= baselineAdjustmentDelta;
  3352. m_lineOffset += baselineAdjustmentDelta;
  3353. // Adjust saved ellipsis state only if we are adjusting the same line number
  3354. if (m_SavedEllipsisState.lineNumber == m_lineNumber)
  3355. {
  3356. m_SavedEllipsisState = m_EllipsisInsertionCandidateStack.Pop();
  3357. m_SavedEllipsisState.startOfLineAscender += baselineAdjustmentDelta;
  3358. m_SavedEllipsisState.lineOffset += baselineAdjustmentDelta;
  3359. m_EllipsisInsertionCandidateStack.Push(m_SavedEllipsisState);
  3360. }
  3361. }
  3362. m_isNewPage = false;
  3363. // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
  3364. float lineAscender = m_maxLineAscender - m_lineOffset;
  3365. float lineDescender = m_maxLineDescender - m_lineOffset;
  3366. // Update maxDescender and maxVisibleDescender
  3367. m_ElementDescender = m_ElementDescender < lineDescender ? m_ElementDescender : lineDescender;
  3368. if (!isMaxVisibleDescenderSet)
  3369. maxVisibleDescender = m_ElementDescender;
  3370. if (m_useMaxVisibleDescender && (m_characterCount >= m_maxVisibleCharacters || m_lineNumber >= m_maxVisibleLines))
  3371. isMaxVisibleDescenderSet = true;
  3372. // Save Line Information
  3373. m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex = m_firstCharacterOfLine;
  3374. m_textInfo.lineInfo[m_lineNumber].firstVisibleCharacterIndex = m_firstVisibleCharacterOfLine = m_firstCharacterOfLine > m_firstVisibleCharacterOfLine ? m_firstCharacterOfLine : m_firstVisibleCharacterOfLine;
  3375. m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex = m_lastCharacterOfLine = m_characterCount;
  3376. m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex = m_lastVisibleCharacterOfLine = m_lastVisibleCharacterOfLine < m_firstVisibleCharacterOfLine ? m_firstVisibleCharacterOfLine : m_lastVisibleCharacterOfLine;
  3377. m_textInfo.lineInfo[m_lineNumber].characterCount = m_textInfo.lineInfo[m_lineNumber].lastCharacterIndex - m_textInfo.lineInfo[m_lineNumber].firstCharacterIndex + 1;
  3378. m_textInfo.lineInfo[m_lineNumber].visibleCharacterCount = m_lineVisibleCharacterCount;
  3379. m_textInfo.lineInfo[m_lineNumber].visibleSpaceCount = (m_textInfo.lineInfo[m_lineNumber].lastVisibleCharacterIndex + 1) - m_lineVisibleCharacterCount;
  3380. m_textInfo.lineInfo[m_lineNumber].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_firstVisibleCharacterOfLine].bottomLeft.x, lineDescender);
  3381. m_textInfo.lineInfo[m_lineNumber].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].topRight.x, lineAscender);
  3382. m_textInfo.lineInfo[m_lineNumber].length = m_textInfo.lineInfo[m_lineNumber].lineExtents.max.x - (padding * currentElementScale);
  3383. m_textInfo.lineInfo[m_lineNumber].width = widthOfTextArea;
  3384. if (m_textInfo.lineInfo[m_lineNumber].characterCount == 1)
  3385. m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification;
  3386. float maxAdvanceOffset = ((m_currentFontAsset.normalSpacingOffset + characterSpacingAdjustment + boldSpacingAdjustment) * currentEmScale + m_cSpacing) * (1 - m_charWidthAdjDelta);
  3387. if (m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].isVisible)
  3388. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance + (m_isRightToLeft ? maxAdvanceOffset : - maxAdvanceOffset);
  3389. else
  3390. m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance + (m_isRightToLeft ? maxAdvanceOffset : - maxAdvanceOffset);
  3391. m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset;
  3392. m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender;
  3393. m_textInfo.lineInfo[m_lineNumber].descender = lineDescender;
  3394. m_textInfo.lineInfo[m_lineNumber].lineHeight = lineAscender - lineDescender + lineGap * baseScale;
  3395. // Add new line if not last line or character.
  3396. if (charCode == 10 || charCode == 11 || (charCode == 0x2D && isInjectedCharacter) || charCode == 0x2028 || charCode == 0x2029)
  3397. {
  3398. // Store the state of the line before starting on the new line.
  3399. SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount);
  3400. m_lineNumber += 1;
  3401. isStartOfNewLine = true;
  3402. ignoreNonBreakingSpace = false;
  3403. isFirstWordOfLine = true;
  3404. m_firstCharacterOfLine = m_characterCount + 1;
  3405. m_lineVisibleCharacterCount = 0;
  3406. m_lineVisibleSpaceCount = 0;
  3407. // Check to make sure Array is large enough to hold a new line.
  3408. if (m_lineNumber >= m_textInfo.lineInfo.Length)
  3409. ResizeLineExtents(m_lineNumber);
  3410. float lastVisibleAscender = m_textInfo.characterInfo[m_characterCount].adjustedAscender;
  3411. // Apply Line Spacing with special handling for VT char(11)
  3412. if (m_lineHeight == TMP_Math.FLOAT_UNSET)
  3413. {
  3414. float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale;
  3415. m_lineOffset += lineOffsetDelta;
  3416. m_IsDrivenLineSpacing = false;
  3417. }
  3418. else
  3419. {
  3420. m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale;
  3421. m_IsDrivenLineSpacing = true;
  3422. }
  3423. m_maxLineAscender = k_LargeNegativeFloat;
  3424. m_maxLineDescender = k_LargePositiveFloat;
  3425. m_startOfLineAscender = lastVisibleAscender;
  3426. m_xAdvance = 0 + tag_LineIndent + tag_Indent;
  3427. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  3428. SaveWordWrappingState(ref m_SavedLastValidState, i, m_characterCount);
  3429. m_characterCount += 1;
  3430. k_HandleLineTerminationMarker.End();
  3431. continue;
  3432. }
  3433. // If End of Text
  3434. if (charCode == 0x03)
  3435. i = m_TextProcessingArray.Length;
  3436. k_HandleLineTerminationMarker.End();
  3437. }
  3438. #endregion Check for Linefeed or Last Character
  3439. // Track extents of the text
  3440. #region Track Text Extents
  3441. k_SaveTextExtentMarker.Begin();
  3442. // Determine the bounds of the Mesh.
  3443. if (m_textInfo.characterInfo[m_characterCount].isVisible)
  3444. {
  3445. m_meshExtents.min.x = Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x);
  3446. m_meshExtents.min.y = Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y);
  3447. m_meshExtents.max.x = Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x);
  3448. m_meshExtents.max.y = Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topRight.y);
  3449. //m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[m_characterCount].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[m_characterCount].bottomLeft.y));
  3450. //m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[m_characterCount].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[m_characterCount].topRight.y));
  3451. }
  3452. k_SaveTextExtentMarker.End();
  3453. #endregion Track Text Extents
  3454. // Save State of Mesh Creation for handling of Word Wrapping
  3455. #region Save Word Wrapping State
  3456. if ((m_TextWrappingMode != TextWrappingModes.NoWrap && m_TextWrappingMode != TextWrappingModes.PreserveWhitespaceNoWrap) || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis || m_overflowMode == TextOverflowModes.Linked)
  3457. {
  3458. k_SaveProcessingStatesMarker.Begin();
  3459. bool shouldSaveHardLineBreak = false;
  3460. bool shouldSaveSoftLineBreak = false;
  3461. if ((isWhiteSpace || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && (!m_isNonBreakingSpace || ignoreNonBreakingSpace) && charCode != 0xA0 && charCode != 0x2007 && charCode != 0x2011 && charCode != 0x202F && charCode != 0x2060)
  3462. {
  3463. // Ignore Hyphen (0x2D) when preceded by a whitespace
  3464. if ((charCode == 0x2D && m_characterCount > 0 && char.IsWhiteSpace(m_textInfo.characterInfo[m_characterCount - 1].character)) == false)
  3465. {
  3466. isFirstWordOfLine = false;
  3467. shouldSaveHardLineBreak = true;
  3468. // Reset soft line breaking point since we now have a valid hard break point.
  3469. m_SavedSoftLineBreakState.previous_WordBreak = -1;
  3470. }
  3471. }
  3472. // Handling for East Asian scripts
  3473. else if (m_isNonBreakingSpace == false && (TMP_TextParsingUtilities.IsHangul(charCode) && TMP_Settings.useModernHangulLineBreakingRules == false || TMP_TextParsingUtilities.IsCJK(charCode)))
  3474. {
  3475. bool isCurrentLeadingCharacter = TMP_Settings.linebreakingRules.leadingCharacters.Contains(charCode);
  3476. bool isNextFollowingCharacter = m_characterCount < totalCharacterCount - 1 && TMP_Settings.linebreakingRules.followingCharacters.Contains(m_textInfo.characterInfo[m_characterCount + 1].character);
  3477. if (isCurrentLeadingCharacter == false)
  3478. {
  3479. if (isNextFollowingCharacter == false)
  3480. {
  3481. isFirstWordOfLine = false;
  3482. shouldSaveHardLineBreak = true;
  3483. }
  3484. if (isFirstWordOfLine)
  3485. {
  3486. // Special handling for non-breaking space and soft line breaks
  3487. if (isWhiteSpace)
  3488. shouldSaveSoftLineBreak = true;
  3489. shouldSaveHardLineBreak = true;
  3490. }
  3491. }
  3492. else
  3493. {
  3494. if (isFirstWordOfLine && isFirstCharacterOfLine)
  3495. {
  3496. // Special handling for non-breaking space and soft line breaks
  3497. if (isWhiteSpace)
  3498. shouldSaveSoftLineBreak = true;
  3499. shouldSaveHardLineBreak = true;
  3500. }
  3501. }
  3502. }
  3503. // Special handling for Latin characters followed by a CJK character.
  3504. else if (m_isNonBreakingSpace == false && m_characterCount + 1 < totalCharacterCount && TMP_TextParsingUtilities.IsCJK(m_textInfo.characterInfo[m_characterCount + 1].character))
  3505. {
  3506. shouldSaveHardLineBreak = true;
  3507. }
  3508. else if (isFirstWordOfLine)
  3509. {
  3510. // Special handling for non-breaking space and soft line breaks
  3511. if (isWhiteSpace && charCode != 0xA0 || (charCode == 0xAD && isSoftHyphenIgnored == false))
  3512. shouldSaveSoftLineBreak = true;
  3513. shouldSaveHardLineBreak = true;
  3514. }
  3515. // Save potential Hard lines break
  3516. if (shouldSaveHardLineBreak)
  3517. SaveWordWrappingState(ref m_SavedWordWrapState, i, m_characterCount);
  3518. // Save potential Soft line break
  3519. if (shouldSaveSoftLineBreak)
  3520. SaveWordWrappingState(ref m_SavedSoftLineBreakState, i, m_characterCount);
  3521. k_SaveProcessingStatesMarker.End();
  3522. }
  3523. #endregion Save Word Wrapping State
  3524. // Consider only saving state on base glyphs
  3525. SaveWordWrappingState(ref m_SavedLastValidState, i, m_characterCount);
  3526. m_characterCount += 1;
  3527. }
  3528. // Check Auto Sizing and increase font size to fill text container.
  3529. #region Check Auto-Sizing (Upper Font Size Bounds)
  3530. fontSizeDelta = m_maxFontSize - m_minFontSize;
  3531. if (/* !m_isCharacterWrappingEnabled && */ m_enableAutoSizing && fontSizeDelta > 0.051f && m_fontSize < m_fontSizeMax && m_AutoSizeIterationCount < m_AutoSizeMaxIterationCount)
  3532. {
  3533. // Reset character width adjustment delta
  3534. if (m_charWidthAdjDelta < m_charWidthMaxAdj / 100)
  3535. m_charWidthAdjDelta = 0;
  3536. m_minFontSize = m_fontSize;
  3537. float sizeDelta = Mathf.Max((m_maxFontSize - m_fontSize) / 2, 0.05f);
  3538. m_fontSize += sizeDelta;
  3539. m_fontSize = Mathf.Min((int)(m_fontSize * 20 + 0.5f) / 20f, m_fontSizeMax);
  3540. //Debug.Log("[" + m_AutoSizeIterationCount + "] Increasing Point Size from [" + m_minFontSize.ToString("f3") + "] to [" + m_fontSize.ToString("f3") + "] with delta of [" + sizeDelta.ToString("f3") + "].");
  3541. k_GenerateTextPhaseIMarker.End();
  3542. k_GenerateTextMarker.End();
  3543. return;
  3544. }
  3545. #endregion End Auto-sizing Check
  3546. m_IsAutoSizePointSizeSet = true;
  3547. if (m_AutoSizeIterationCount >= m_AutoSizeMaxIterationCount)
  3548. Debug.Log("Auto Size Iteration Count: " + m_AutoSizeIterationCount + ". Final Point Size: " + m_fontSize);
  3549. // If there are no visible characters or only character is End of Text (0x03)... no need to continue
  3550. if (m_characterCount == 0 || (m_characterCount == 1 && charCode == 0x03))
  3551. {
  3552. ClearMesh();
  3553. // Event indicating the text has been regenerated.
  3554. TMPro_EventManager.ON_TEXT_CHANGED(this);
  3555. k_GenerateTextPhaseIMarker.End();
  3556. k_GenerateTextMarker.End();
  3557. return;
  3558. }
  3559. // End Sampling of Phase I
  3560. k_GenerateTextPhaseIMarker.End();
  3561. // *** PHASE II of Text Generation ***
  3562. k_GenerateTextPhaseIIMarker.Begin();
  3563. int last_vert_index = m_materialReferences[m_Underline.materialIndex].referenceCount * 4;
  3564. // Partial clear of the vertices array to mark unused vertices as degenerate.
  3565. m_textInfo.meshInfo[0].Clear(false);
  3566. // Handle Text Alignment
  3567. #region Text Vertical Alignment
  3568. Vector3 anchorOffset = Vector3.zero;
  3569. Vector3[] corners = m_RectTransformCorners; // GetTextContainerLocalCorners();
  3570. // Handle Vertical Text Alignment
  3571. switch (m_VerticalAlignment)
  3572. {
  3573. // Top Vertically
  3574. case VerticalAlignmentOptions.Top:
  3575. if (m_overflowMode != TextOverflowModes.Page)
  3576. anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_maxTextAscender - margins.y, 0);
  3577. else
  3578. anchorOffset = corners[1] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].ascender - margins.y, 0);
  3579. break;
  3580. // Middle Vertically
  3581. case VerticalAlignmentOptions.Middle:
  3582. if (m_overflowMode != TextOverflowModes.Page)
  3583. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxTextAscender + margins.y + maxVisibleDescender - margins.w) / 2, 0);
  3584. else
  3585. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_textInfo.pageInfo[pageToDisplay].ascender + margins.y + m_textInfo.pageInfo[pageToDisplay].descender - margins.w) / 2, 0);
  3586. break;
  3587. // Bottom Vertically
  3588. case VerticalAlignmentOptions.Bottom:
  3589. if (m_overflowMode != TextOverflowModes.Page)
  3590. anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - maxVisibleDescender + margins.w, 0);
  3591. else
  3592. anchorOffset = corners[0] + new Vector3(0 + margins.x, 0 - m_textInfo.pageInfo[pageToDisplay].descender + margins.w, 0);
  3593. break;
  3594. // Baseline Vertically
  3595. case VerticalAlignmentOptions.Baseline:
  3596. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0, 0);
  3597. break;
  3598. // Midline Vertically
  3599. case VerticalAlignmentOptions.Geometry:
  3600. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_meshExtents.max.y + margins.y + m_meshExtents.min.y - margins.w) / 2, 0);
  3601. break;
  3602. // Capline Vertically
  3603. case VerticalAlignmentOptions.Capline:
  3604. anchorOffset = (corners[0] + corners[1]) / 2 + new Vector3(0 + margins.x, 0 - (m_maxCapHeight - margins.y - margins.w) / 2, 0);
  3605. break;
  3606. }
  3607. #endregion
  3608. // Initialization for Second Pass
  3609. Vector3 justificationOffset = Vector3.zero;
  3610. Vector3 offset = Vector3.zero;
  3611. // int vert_index_X4 = 0;
  3612. // int sprite_index_X4 = 0;
  3613. int wordCount = 0;
  3614. int lineCount = 0;
  3615. int lastLine = 0;
  3616. bool isFirstSeperator = false;
  3617. bool isStartOfWord = false;
  3618. int wordFirstChar = 0;
  3619. int wordLastChar = 0;
  3620. // Second Pass : Line Justification, UV Mapping, Character & Line Visibility & more.
  3621. // Variables used to handle Canvas Render Modes and SDF Scaling
  3622. bool isCameraAssigned = m_canvas.worldCamera == null ? false : true;
  3623. float lossyScale = m_previousLossyScaleY = this.transform.lossyScale.y;
  3624. RenderMode canvasRenderMode = m_canvas.renderMode;
  3625. float canvasScaleFactor = m_canvas.scaleFactor;
  3626. Color32 underlineColor = Color.white;
  3627. Color32 strikethroughColor = Color.white;
  3628. HighlightState highlightState = new HighlightState(new Color32(255, 255, 0, 64), TMP_Offset.zero);
  3629. float xScale = 0;
  3630. float xScaleMax = 0;
  3631. float underlineStartScale = 0;
  3632. float underlineEndScale = 0;
  3633. float underlineMaxScale = 0;
  3634. float underlineBaseLine = k_LargePositiveFloat;
  3635. int lastPage = 0;
  3636. float strikethroughPointSize = 0;
  3637. float strikethroughScale = 0;
  3638. float strikethroughBaseline = 0;
  3639. TMP_CharacterInfo[] characterInfos = m_textInfo.characterInfo;
  3640. #region Handle Line Justification & UV Mapping & Character Visibility & More
  3641. for (int i = 0; i < m_characterCount; i++)
  3642. {
  3643. TMP_FontAsset currentFontAsset = characterInfos[i].fontAsset;
  3644. char unicode = characterInfos[i].character;
  3645. bool isWhiteSpace = char.IsWhiteSpace(unicode);
  3646. int currentLine = characterInfos[i].lineNumber;
  3647. TMP_LineInfo lineInfo = m_textInfo.lineInfo[currentLine];
  3648. lineCount = currentLine + 1;
  3649. HorizontalAlignmentOptions lineAlignment = lineInfo.alignment;
  3650. // Process Line Justification
  3651. #region Handle Line Justification
  3652. switch (lineAlignment)
  3653. {
  3654. case HorizontalAlignmentOptions.Left:
  3655. if (!m_isRightToLeft)
  3656. justificationOffset = new Vector3(0 + lineInfo.marginLeft, 0, 0);
  3657. else
  3658. justificationOffset = new Vector3(0 - lineInfo.maxAdvance, 0, 0);
  3659. break;
  3660. case HorizontalAlignmentOptions.Center:
  3661. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - lineInfo.maxAdvance / 2, 0, 0);
  3662. break;
  3663. case HorizontalAlignmentOptions.Geometry:
  3664. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width / 2 - (lineInfo.lineExtents.min.x + lineInfo.lineExtents.max.x) / 2, 0, 0);
  3665. break;
  3666. case HorizontalAlignmentOptions.Right:
  3667. if (!m_isRightToLeft)
  3668. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width - lineInfo.maxAdvance, 0, 0);
  3669. else
  3670. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0);
  3671. break;
  3672. case HorizontalAlignmentOptions.Justified:
  3673. case HorizontalAlignmentOptions.Flush:
  3674. // Skip Zero Width Characters and spaces outside of the margins.
  3675. if (i > lineInfo.lastVisibleCharacterIndex || unicode == 0x0A || unicode == 0xAD || unicode == 0x200B || unicode == 0x2060 || unicode == 0x03) break;
  3676. char lastCharOfCurrentLine = characterInfos[lineInfo.lastCharacterIndex].character;
  3677. bool isFlush = (lineAlignment & HorizontalAlignmentOptions.Flush) == HorizontalAlignmentOptions.Flush;
  3678. // In Justified mode, all lines are justified except the last one.
  3679. // In Flush mode, all lines are justified.
  3680. if (char.IsControl(lastCharOfCurrentLine) == false && currentLine < m_lineNumber || isFlush || lineInfo.maxAdvance > lineInfo.width)
  3681. {
  3682. // First character of each line.
  3683. if (currentLine != lastLine || i == 0 || i == m_firstVisibleCharacter)
  3684. {
  3685. if (!m_isRightToLeft)
  3686. justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0);
  3687. else
  3688. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0);
  3689. if (char.IsSeparator(unicode))
  3690. isFirstSeperator = true;
  3691. else
  3692. isFirstSeperator = false;
  3693. }
  3694. else
  3695. {
  3696. float gap = !m_isRightToLeft ? lineInfo.width - lineInfo.maxAdvance : lineInfo.width + lineInfo.maxAdvance;
  3697. int visibleCount = lineInfo.visibleCharacterCount - 1 + lineInfo.controlCharacterCount;
  3698. int spaces = lineInfo.spaceCount - lineInfo.controlCharacterCount;
  3699. if (isFirstSeperator) { spaces -= 1; visibleCount += 1; }
  3700. float ratio = spaces > 0 ? m_wordWrappingRatios : 1;
  3701. if (spaces < 1) spaces = 1;
  3702. if (unicode != 0xA0 && (unicode == 9 || char.IsSeparator(unicode)))
  3703. {
  3704. if (!m_isRightToLeft)
  3705. justificationOffset += new Vector3(gap * (1 - ratio) / spaces, 0, 0);
  3706. else
  3707. justificationOffset -= new Vector3(gap * (1 - ratio) / spaces, 0, 0);
  3708. }
  3709. else
  3710. {
  3711. if (!m_isRightToLeft)
  3712. justificationOffset += new Vector3(gap * ratio / visibleCount, 0, 0);
  3713. else
  3714. justificationOffset -= new Vector3(gap * ratio / visibleCount, 0, 0);
  3715. }
  3716. }
  3717. }
  3718. else
  3719. {
  3720. if (!m_isRightToLeft)
  3721. justificationOffset = new Vector3(lineInfo.marginLeft, 0, 0); // Keep last line left justified.
  3722. else
  3723. justificationOffset = new Vector3(lineInfo.marginLeft + lineInfo.width, 0, 0); // Keep last line right justified.
  3724. }
  3725. //Debug.Log("Char [" + (char)charCode + "] Code:" + charCode + " Line # " + currentLine + " Offset:" + justificationOffset + " # Spaces:" + lineInfo.spaceCount + " # Characters:" + lineInfo.characterCount);
  3726. break;
  3727. }
  3728. #endregion End Text Justification
  3729. offset = anchorOffset + justificationOffset;
  3730. // Handle UV2 mapping options and packing of scale information into UV2.
  3731. #region Handling of UV2 mapping & Scale packing
  3732. bool isCharacterVisible = characterInfos[i].isVisible;
  3733. if (isCharacterVisible)
  3734. {
  3735. TMP_TextElementType elementType = characterInfos[i].elementType;
  3736. switch (elementType)
  3737. {
  3738. // CHARACTERS
  3739. case TMP_TextElementType.Character:
  3740. Extents lineExtents = lineInfo.lineExtents;
  3741. float uvOffset = (m_uvLineOffset * currentLine) % 1; // + m_uvOffset.x;
  3742. // Setup UV2 based on Character Mapping Options Selected
  3743. #region Handle UV Mapping Options
  3744. switch (m_horizontalMapping)
  3745. {
  3746. case TextureMappingOptions.Character:
  3747. characterInfos[i].vertex_BL.uv2.x = 0; //+ m_uvOffset.x;
  3748. characterInfos[i].vertex_TL.uv2.x = 0; //+ m_uvOffset.x;
  3749. characterInfos[i].vertex_TR.uv2.x = 1; //+ m_uvOffset.x;
  3750. characterInfos[i].vertex_BR.uv2.x = 1; //+ m_uvOffset.x;
  3751. break;
  3752. case TextureMappingOptions.Line:
  3753. if (m_textAlignment != TextAlignmentOptions.Justified)
  3754. {
  3755. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  3756. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  3757. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  3758. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x - lineExtents.min.x) / (lineExtents.max.x - lineExtents.min.x) + uvOffset;
  3759. break;
  3760. }
  3761. else // Special Case if Justified is used in Line Mode.
  3762. {
  3763. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3764. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3765. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3766. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3767. break;
  3768. }
  3769. case TextureMappingOptions.Paragraph:
  3770. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3771. characterInfos[i].vertex_TL.uv2.x = (characterInfos[i].vertex_TL.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3772. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3773. characterInfos[i].vertex_BR.uv2.x = (characterInfos[i].vertex_BR.position.x + justificationOffset.x - m_meshExtents.min.x) / (m_meshExtents.max.x - m_meshExtents.min.x) + uvOffset;
  3774. break;
  3775. case TextureMappingOptions.MatchAspect:
  3776. switch (m_verticalMapping)
  3777. {
  3778. case TextureMappingOptions.Character:
  3779. characterInfos[i].vertex_BL.uv2.y = 0; // + m_uvOffset.y;
  3780. characterInfos[i].vertex_TL.uv2.y = 1; // + m_uvOffset.y;
  3781. characterInfos[i].vertex_TR.uv2.y = 0; // + m_uvOffset.y;
  3782. characterInfos[i].vertex_BR.uv2.y = 1; // + m_uvOffset.y;
  3783. break;
  3784. case TextureMappingOptions.Line:
  3785. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
  3786. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineExtents.min.y) / (lineExtents.max.y - lineExtents.min.y) + uvOffset;
  3787. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3788. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3789. break;
  3790. case TextureMappingOptions.Paragraph:
  3791. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
  3792. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y) + uvOffset;
  3793. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3794. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3795. break;
  3796. case TextureMappingOptions.MatchAspect:
  3797. Debug.Log("ERROR: Cannot Match both Vertical & Horizontal.");
  3798. break;
  3799. }
  3800. //float xDelta = 1 - (_uv2s[vert_index + 0].y * textMeshCharacterInfo[i].AspectRatio); // Left aligned
  3801. float xDelta = (1 - ((characterInfos[i].vertex_BL.uv2.y + characterInfos[i].vertex_TL.uv2.y) * characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
  3802. characterInfos[i].vertex_BL.uv2.x = (characterInfos[i].vertex_BL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
  3803. characterInfos[i].vertex_TL.uv2.x = characterInfos[i].vertex_BL.uv2.x;
  3804. characterInfos[i].vertex_TR.uv2.x = (characterInfos[i].vertex_TL.uv2.y * characterInfos[i].aspectRatio) + xDelta + uvOffset;
  3805. characterInfos[i].vertex_BR.uv2.x = characterInfos[i].vertex_TR.uv2.x;
  3806. break;
  3807. }
  3808. switch (m_verticalMapping)
  3809. {
  3810. case TextureMappingOptions.Character:
  3811. characterInfos[i].vertex_BL.uv2.y = 0; // + m_uvOffset.y;
  3812. characterInfos[i].vertex_TL.uv2.y = 1; // + m_uvOffset.y;
  3813. characterInfos[i].vertex_TR.uv2.y = 1; // + m_uvOffset.y;
  3814. characterInfos[i].vertex_BR.uv2.y = 0; // + m_uvOffset.y;
  3815. break;
  3816. case TextureMappingOptions.Line:
  3817. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - lineInfo.descender) / (lineInfo.ascender - lineInfo.descender); // + m_uvOffset.y;
  3818. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - lineInfo.descender) / (lineInfo.ascender - lineInfo.descender); // + m_uvOffset.y;
  3819. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3820. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3821. break;
  3822. case TextureMappingOptions.Paragraph:
  3823. characterInfos[i].vertex_BL.uv2.y = (characterInfos[i].vertex_BL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y); // + m_uvOffset.y;
  3824. characterInfos[i].vertex_TL.uv2.y = (characterInfos[i].vertex_TL.position.y - m_meshExtents.min.y) / (m_meshExtents.max.y - m_meshExtents.min.y); // + m_uvOffset.y;
  3825. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3826. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3827. break;
  3828. case TextureMappingOptions.MatchAspect:
  3829. float yDelta = (1 - ((characterInfos[i].vertex_BL.uv2.x + characterInfos[i].vertex_TR.uv2.x) / characterInfos[i].aspectRatio)) / 2; // Center of Rectangle
  3830. characterInfos[i].vertex_BL.uv2.y = yDelta + (characterInfos[i].vertex_BL.uv2.x / characterInfos[i].aspectRatio); // + m_uvOffset.y;
  3831. characterInfos[i].vertex_TL.uv2.y = yDelta + (characterInfos[i].vertex_TR.uv2.x / characterInfos[i].aspectRatio); // + m_uvOffset.y;
  3832. characterInfos[i].vertex_BR.uv2.y = characterInfos[i].vertex_BL.uv2.y;
  3833. characterInfos[i].vertex_TR.uv2.y = characterInfos[i].vertex_TL.uv2.y;
  3834. break;
  3835. }
  3836. #endregion
  3837. // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio.
  3838. #region Pack Scale into UV2
  3839. xScale = characterInfos[i].scale * (1 - m_charWidthAdjDelta);
  3840. if (!characterInfos[i].isUsingAlternateTypeface && (characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold) xScale *= -1;
  3841. switch (canvasRenderMode)
  3842. {
  3843. case RenderMode.ScreenSpaceOverlay:
  3844. xScale *= Mathf.Abs(lossyScale) / canvasScaleFactor;
  3845. break;
  3846. case RenderMode.ScreenSpaceCamera:
  3847. xScale *= isCameraAssigned ? Mathf.Abs(lossyScale) : 1;
  3848. break;
  3849. case RenderMode.WorldSpace:
  3850. xScale *= Mathf.Abs(lossyScale);
  3851. break;
  3852. }
  3853. // Set SDF Scale
  3854. characterInfos[i].vertex_BL.uv.w = xScale;
  3855. characterInfos[i].vertex_TL.uv.w = xScale;
  3856. characterInfos[i].vertex_TR.uv.w = xScale;
  3857. characterInfos[i].vertex_BR.uv.w = xScale;
  3858. #endregion
  3859. break;
  3860. // SPRITES
  3861. case TMP_TextElementType.Sprite:
  3862. // Nothing right now
  3863. break;
  3864. }
  3865. // Handle maxVisibleCharacters, maxVisibleLines and Overflow Page Mode.
  3866. #region Handle maxVisibleCharacters / maxVisibleLines / Page Mode
  3867. if (i < m_maxVisibleCharacters && wordCount < m_maxVisibleWords && currentLine < m_maxVisibleLines && m_overflowMode != TextOverflowModes.Page)
  3868. {
  3869. characterInfos[i].vertex_BL.position += offset;
  3870. characterInfos[i].vertex_TL.position += offset;
  3871. characterInfos[i].vertex_TR.position += offset;
  3872. characterInfos[i].vertex_BR.position += offset;
  3873. }
  3874. else if (i < m_maxVisibleCharacters && wordCount < m_maxVisibleWords && currentLine < m_maxVisibleLines && m_overflowMode == TextOverflowModes.Page && characterInfos[i].pageNumber == pageToDisplay)
  3875. {
  3876. characterInfos[i].vertex_BL.position += offset;
  3877. characterInfos[i].vertex_TL.position += offset;
  3878. characterInfos[i].vertex_TR.position += offset;
  3879. characterInfos[i].vertex_BR.position += offset;
  3880. }
  3881. else
  3882. {
  3883. characterInfos[i].vertex_BL.position = Vector3.zero;
  3884. characterInfos[i].vertex_TL.position = Vector3.zero;
  3885. characterInfos[i].vertex_TR.position = Vector3.zero;
  3886. characterInfos[i].vertex_BR.position = Vector3.zero;
  3887. characterInfos[i].isVisible = false;
  3888. }
  3889. #endregion
  3890. // Fill Vertex Buffers for the various types of element
  3891. if (elementType == TMP_TextElementType.Character)
  3892. {
  3893. FillCharacterVertexBuffers(i);
  3894. }
  3895. else if (elementType == TMP_TextElementType.Sprite)
  3896. {
  3897. FillSpriteVertexBuffers(i);
  3898. }
  3899. }
  3900. #endregion
  3901. // Apply Alignment and Justification Offset
  3902. m_textInfo.characterInfo[i].bottomLeft += offset;
  3903. m_textInfo.characterInfo[i].topLeft += offset;
  3904. m_textInfo.characterInfo[i].topRight += offset;
  3905. m_textInfo.characterInfo[i].bottomRight += offset;
  3906. m_textInfo.characterInfo[i].origin += offset.x;
  3907. m_textInfo.characterInfo[i].xAdvance += offset.x;
  3908. m_textInfo.characterInfo[i].ascender += offset.y;
  3909. m_textInfo.characterInfo[i].descender += offset.y;
  3910. m_textInfo.characterInfo[i].baseLine += offset.y;
  3911. // Update MeshExtents
  3912. if (isCharacterVisible)
  3913. {
  3914. //m_meshExtents.min = new Vector2(Mathf.Min(m_meshExtents.min.x, m_textInfo.characterInfo[i].bottomLeft.x), Mathf.Min(m_meshExtents.min.y, m_textInfo.characterInfo[i].bottomLeft.y));
  3915. //m_meshExtents.max = new Vector2(Mathf.Max(m_meshExtents.max.x, m_textInfo.characterInfo[i].topRight.x), Mathf.Max(m_meshExtents.max.y, m_textInfo.characterInfo[i].topLeft.y));
  3916. }
  3917. // Need to recompute lineExtent to account for the offset from justification.
  3918. #region Adjust lineExtents resulting from alignment offset
  3919. if (currentLine != lastLine || i == m_characterCount - 1)
  3920. {
  3921. // Update the previous line's extents
  3922. if (currentLine != lastLine)
  3923. {
  3924. m_textInfo.lineInfo[lastLine].baseline += offset.y;
  3925. m_textInfo.lineInfo[lastLine].ascender += offset.y;
  3926. m_textInfo.lineInfo[lastLine].descender += offset.y;
  3927. m_textInfo.lineInfo[lastLine].maxAdvance += offset.x;
  3928. m_textInfo.lineInfo[lastLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[lastLine].descender);
  3929. m_textInfo.lineInfo[lastLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[lastLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[lastLine].ascender);
  3930. }
  3931. // Update the current line's extents
  3932. if (i == m_characterCount - 1)
  3933. {
  3934. m_textInfo.lineInfo[currentLine].baseline += offset.y;
  3935. m_textInfo.lineInfo[currentLine].ascender += offset.y;
  3936. m_textInfo.lineInfo[currentLine].descender += offset.y;
  3937. m_textInfo.lineInfo[currentLine].maxAdvance += offset.x;
  3938. m_textInfo.lineInfo[currentLine].lineExtents.min = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].firstCharacterIndex].bottomLeft.x, m_textInfo.lineInfo[currentLine].descender);
  3939. m_textInfo.lineInfo[currentLine].lineExtents.max = new Vector2(m_textInfo.characterInfo[m_textInfo.lineInfo[currentLine].lastVisibleCharacterIndex].topRight.x, m_textInfo.lineInfo[currentLine].ascender);
  3940. }
  3941. }
  3942. #endregion
  3943. // Track Word Count per line and for the object
  3944. #region Track Word Count
  3945. if (char.IsLetterOrDigit(unicode) || unicode == 0x2D || unicode == 0xAD || unicode == 0x2010 || unicode == 0x2011)
  3946. {
  3947. if (isStartOfWord == false)
  3948. {
  3949. isStartOfWord = true;
  3950. wordFirstChar = i;
  3951. }
  3952. // If last character is a word
  3953. if (isStartOfWord && i == m_characterCount - 1)
  3954. {
  3955. int size = m_textInfo.wordInfo.Length;
  3956. int index = m_textInfo.wordCount;
  3957. if (m_textInfo.wordCount + 1 > size)
  3958. TMP_TextInfo.Resize(ref m_textInfo.wordInfo, size + 1);
  3959. wordLastChar = i;
  3960. m_textInfo.wordInfo[index].firstCharacterIndex = wordFirstChar;
  3961. m_textInfo.wordInfo[index].lastCharacterIndex = wordLastChar;
  3962. m_textInfo.wordInfo[index].characterCount = wordLastChar - wordFirstChar + 1;
  3963. m_textInfo.wordInfo[index].textComponent = this;
  3964. wordCount += 1;
  3965. m_textInfo.wordCount += 1;
  3966. m_textInfo.lineInfo[currentLine].wordCount += 1;
  3967. }
  3968. }
  3969. else if (isStartOfWord || i == 0 && (!char.IsPunctuation(unicode) || isWhiteSpace || unicode == 0x200B || i == m_characterCount - 1))
  3970. {
  3971. if (i > 0 && i < characterInfos.Length - 1 && i < m_characterCount && (unicode == 39 || unicode == 8217) && char.IsLetterOrDigit(characterInfos[i - 1].character) && char.IsLetterOrDigit(characterInfos[i + 1].character))
  3972. {
  3973. }
  3974. else
  3975. {
  3976. wordLastChar = i == m_characterCount - 1 && char.IsLetterOrDigit(unicode) ? i : i - 1;
  3977. isStartOfWord = false;
  3978. int size = m_textInfo.wordInfo.Length;
  3979. int index = m_textInfo.wordCount;
  3980. if (m_textInfo.wordCount + 1 > size)
  3981. TMP_TextInfo.Resize(ref m_textInfo.wordInfo, size + 1);
  3982. m_textInfo.wordInfo[index].firstCharacterIndex = wordFirstChar;
  3983. m_textInfo.wordInfo[index].lastCharacterIndex = wordLastChar;
  3984. m_textInfo.wordInfo[index].characterCount = wordLastChar - wordFirstChar + 1;
  3985. m_textInfo.wordInfo[index].textComponent = this;
  3986. wordCount += 1;
  3987. m_textInfo.wordCount += 1;
  3988. m_textInfo.lineInfo[currentLine].wordCount += 1;
  3989. }
  3990. }
  3991. #endregion
  3992. // Setup & Handle Underline
  3993. #region Underline
  3994. // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
  3995. bool isUnderline = (m_textInfo.characterInfo[i].style & FontStyles.Underline) == FontStyles.Underline;
  3996. if (isUnderline)
  3997. {
  3998. bool isUnderlineVisible = true;
  3999. int currentPage = m_textInfo.characterInfo[i].pageNumber;
  4000. m_textInfo.characterInfo[i].underlineVertexIndex = last_vert_index;
  4001. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
  4002. isUnderlineVisible = false;
  4003. // We only use the scale of visible characters.
  4004. if (!isWhiteSpace && unicode != 0x200B)
  4005. {
  4006. underlineMaxScale = Mathf.Max(underlineMaxScale, m_textInfo.characterInfo[i].scale);
  4007. xScaleMax = Mathf.Max(xScaleMax, Mathf.Abs(xScale));
  4008. underlineBaseLine = Mathf.Min(currentPage == lastPage ? underlineBaseLine : k_LargePositiveFloat, m_textInfo.characterInfo[i].baseLine + font.m_FaceInfo.underlineOffset * underlineMaxScale);
  4009. lastPage = currentPage; // Need to track pages to ensure we reset baseline for the new pages.
  4010. }
  4011. if (beginUnderline == false && isUnderlineVisible == true && i <= lineInfo.lastVisibleCharacterIndex && unicode != 10 && unicode != 11 && unicode != 13)
  4012. {
  4013. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(unicode))
  4014. { }
  4015. else
  4016. {
  4017. beginUnderline = true;
  4018. underlineStartScale = m_textInfo.characterInfo[i].scale;
  4019. if (underlineMaxScale == 0)
  4020. {
  4021. underlineMaxScale = underlineStartScale;
  4022. xScaleMax = xScale;
  4023. }
  4024. underline_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, underlineBaseLine, 0);
  4025. underlineColor = m_textInfo.characterInfo[i].underlineColor;
  4026. }
  4027. }
  4028. // End Underline if text only contains one character.
  4029. if (beginUnderline && m_characterCount == 1)
  4030. {
  4031. beginUnderline = false;
  4032. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  4033. underlineEndScale = m_textInfo.characterInfo[i].scale;
  4034. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  4035. underlineMaxScale = 0;
  4036. xScaleMax = 0;
  4037. underlineBaseLine = k_LargePositiveFloat;
  4038. }
  4039. else if (beginUnderline && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
  4040. {
  4041. // Terminate underline at previous visible character if space or carriage return.
  4042. if (isWhiteSpace || unicode == 0x200B)
  4043. {
  4044. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  4045. underline_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, underlineBaseLine, 0);
  4046. underlineEndScale = m_textInfo.characterInfo[lastVisibleCharacterIndex].scale;
  4047. }
  4048. else
  4049. { // End underline if last character of the line.
  4050. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  4051. underlineEndScale = m_textInfo.characterInfo[i].scale;
  4052. }
  4053. beginUnderline = false;
  4054. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  4055. underlineMaxScale = 0;
  4056. xScaleMax = 0;
  4057. underlineBaseLine = k_LargePositiveFloat;
  4058. }
  4059. else if (beginUnderline && !isUnderlineVisible)
  4060. {
  4061. beginUnderline = false;
  4062. underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
  4063. underlineEndScale = m_textInfo.characterInfo[i - 1].scale;
  4064. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  4065. underlineMaxScale = 0;
  4066. xScaleMax = 0;
  4067. underlineBaseLine = k_LargePositiveFloat;
  4068. }
  4069. else if (beginUnderline && i < m_characterCount - 1 && !underlineColor.Compare(m_textInfo.characterInfo[i + 1].underlineColor))
  4070. {
  4071. // End underline if underline color has changed.
  4072. beginUnderline = false;
  4073. underline_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, underlineBaseLine, 0);
  4074. underlineEndScale = m_textInfo.characterInfo[i].scale;
  4075. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  4076. underlineMaxScale = 0;
  4077. xScaleMax = 0;
  4078. underlineBaseLine = k_LargePositiveFloat;
  4079. }
  4080. }
  4081. else
  4082. {
  4083. // End Underline
  4084. if (beginUnderline == true)
  4085. {
  4086. beginUnderline = false;
  4087. underline_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, underlineBaseLine, 0);
  4088. underlineEndScale = m_textInfo.characterInfo[i - 1].scale;
  4089. DrawUnderlineMesh(underline_start, underline_end, ref last_vert_index, underlineStartScale, underlineEndScale, underlineMaxScale, xScaleMax, underlineColor);
  4090. underlineMaxScale = 0;
  4091. xScaleMax = 0;
  4092. underlineBaseLine = k_LargePositiveFloat;
  4093. }
  4094. }
  4095. #endregion
  4096. // Setup & Handle Strikethrough
  4097. #region Strikethrough
  4098. // NOTE: Need to figure out how underline will be handled with multiple fonts and which font will be used for the underline.
  4099. bool isStrikethrough = (m_textInfo.characterInfo[i].style & FontStyles.Strikethrough) == FontStyles.Strikethrough;
  4100. float strikethroughOffset = currentFontAsset.m_FaceInfo.strikethroughOffset;
  4101. if (isStrikethrough)
  4102. {
  4103. bool isStrikeThroughVisible = true;
  4104. m_textInfo.characterInfo[i].strikethroughVertexIndex = last_vert_index;
  4105. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && m_textInfo.characterInfo[i].pageNumber + 1 != m_pageToDisplay))
  4106. isStrikeThroughVisible = false;
  4107. if (beginStrikethrough == false && isStrikeThroughVisible && i <= lineInfo.lastVisibleCharacterIndex && unicode != 10 && unicode != 11 && unicode != 13)
  4108. {
  4109. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(unicode))
  4110. { }
  4111. else
  4112. {
  4113. beginStrikethrough = true;
  4114. strikethroughPointSize = m_textInfo.characterInfo[i].pointSize;
  4115. strikethroughScale = m_textInfo.characterInfo[i].scale;
  4116. strikethrough_start = new Vector3(m_textInfo.characterInfo[i].bottomLeft.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  4117. strikethroughColor = m_textInfo.characterInfo[i].strikethroughColor;
  4118. strikethroughBaseline = m_textInfo.characterInfo[i].baseLine;
  4119. //Debug.Log("Char [" + currentCharacter + "] Start Strikethrough POS: " + strikethrough_start);
  4120. }
  4121. }
  4122. // End Strikethrough if text only contains one character.
  4123. if (beginStrikethrough && m_characterCount == 1)
  4124. {
  4125. beginStrikethrough = false;
  4126. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  4127. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  4128. }
  4129. else if (beginStrikethrough && i == lineInfo.lastCharacterIndex)
  4130. {
  4131. // Terminate Strikethrough at previous visible character if space or carriage return.
  4132. if (isWhiteSpace || unicode == 0x200B)
  4133. {
  4134. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  4135. strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + strikethroughOffset * strikethroughScale, 0);
  4136. }
  4137. else
  4138. {
  4139. // Terminate Strikethrough at last character of line.
  4140. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  4141. }
  4142. beginStrikethrough = false;
  4143. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  4144. }
  4145. else if (beginStrikethrough && i < m_characterCount && (m_textInfo.characterInfo[i + 1].pointSize != strikethroughPointSize || !TMP_Math.Approximately(m_textInfo.characterInfo[i + 1].baseLine + offset.y, strikethroughBaseline)))
  4146. {
  4147. // Terminate Strikethrough if scale changes.
  4148. beginStrikethrough = false;
  4149. int lastVisibleCharacterIndex = lineInfo.lastVisibleCharacterIndex;
  4150. if (i > lastVisibleCharacterIndex)
  4151. strikethrough_end = new Vector3(m_textInfo.characterInfo[lastVisibleCharacterIndex].topRight.x, m_textInfo.characterInfo[lastVisibleCharacterIndex].baseLine + strikethroughOffset * strikethroughScale, 0);
  4152. else
  4153. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  4154. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  4155. //Debug.Log("Char [" + currentCharacter + "] at Index: " + i + " End Strikethrough POS: " + strikethrough_end + " Baseline: " + m_textInfo.characterInfo[i].baseLine.ToString("f3"));
  4156. }
  4157. else if (beginStrikethrough && i < m_characterCount && currentFontAsset.GetInstanceID() != characterInfos[i + 1].fontAsset.GetInstanceID())
  4158. {
  4159. // Terminate Strikethrough if font asset changes.
  4160. beginStrikethrough = false;
  4161. strikethrough_end = new Vector3(m_textInfo.characterInfo[i].topRight.x, m_textInfo.characterInfo[i].baseLine + strikethroughOffset * strikethroughScale, 0);
  4162. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  4163. }
  4164. else if (beginStrikethrough && !isStrikeThroughVisible)
  4165. {
  4166. // Terminate Strikethrough if character is not visible.
  4167. beginStrikethrough = false;
  4168. strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + strikethroughOffset * strikethroughScale, 0);
  4169. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  4170. }
  4171. }
  4172. else
  4173. {
  4174. // End Strikethrough
  4175. if (beginStrikethrough == true)
  4176. {
  4177. beginStrikethrough = false;
  4178. strikethrough_end = new Vector3(m_textInfo.characterInfo[i - 1].topRight.x, m_textInfo.characterInfo[i - 1].baseLine + strikethroughOffset * strikethroughScale, 0);
  4179. DrawUnderlineMesh(strikethrough_start, strikethrough_end, ref last_vert_index, strikethroughScale, strikethroughScale, strikethroughScale, xScale, strikethroughColor);
  4180. }
  4181. }
  4182. #endregion
  4183. // HANDLE TEXT HIGHLIGHTING
  4184. #region Text Highlighting
  4185. bool isHighlight = (m_textInfo.characterInfo[i].style & FontStyles.Highlight) == FontStyles.Highlight;
  4186. if (isHighlight)
  4187. {
  4188. bool isHighlightVisible = true;
  4189. int currentPage = m_textInfo.characterInfo[i].pageNumber;
  4190. if (i > m_maxVisibleCharacters || currentLine > m_maxVisibleLines || (m_overflowMode == TextOverflowModes.Page && currentPage + 1 != m_pageToDisplay))
  4191. isHighlightVisible = false;
  4192. if (beginHighlight == false && isHighlightVisible == true && i <= lineInfo.lastVisibleCharacterIndex && unicode != 10 && unicode != 11 && unicode != 13)
  4193. {
  4194. if (i == lineInfo.lastVisibleCharacterIndex && char.IsSeparator(unicode))
  4195. { }
  4196. else
  4197. {
  4198. beginHighlight = true;
  4199. highlight_start = k_LargePositiveVector2;
  4200. highlight_end = k_LargeNegativeVector2;
  4201. highlightState = m_textInfo.characterInfo[i].highlightState;
  4202. }
  4203. }
  4204. if (beginHighlight)
  4205. {
  4206. TMP_CharacterInfo currentCharacter = m_textInfo.characterInfo[i];
  4207. HighlightState currentState = currentCharacter.highlightState;
  4208. bool isColorTransition = false;
  4209. // Handle Highlight color changes
  4210. if (highlightState != currentState)
  4211. {
  4212. // Adjust previous highlight section to prevent a gaps between sections.
  4213. if (isWhiteSpace)
  4214. highlight_end.x = (highlight_end.x - highlightState.padding.right + currentCharacter.origin) / 2;
  4215. else
  4216. highlight_end.x = (highlight_end.x - highlightState.padding.right + currentCharacter.bottomLeft.x) / 2;
  4217. highlight_start.y = Mathf.Min(highlight_start.y, currentCharacter.descender);
  4218. highlight_end.y = Mathf.Max(highlight_end.y, currentCharacter.ascender);
  4219. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  4220. beginHighlight = true;
  4221. highlight_start = new Vector2(highlight_end.x, currentCharacter.descender - currentState.padding.bottom);
  4222. if (isWhiteSpace)
  4223. highlight_end = new Vector2(currentCharacter.xAdvance + currentState.padding.right, currentCharacter.ascender + currentState.padding.top);
  4224. else
  4225. highlight_end = new Vector2(currentCharacter.topRight.x + currentState.padding.right, currentCharacter.ascender + currentState.padding.top);
  4226. highlightState = currentState;
  4227. isColorTransition = true;
  4228. }
  4229. if (!isColorTransition)
  4230. {
  4231. if (isWhiteSpace)
  4232. {
  4233. // Use the Min / Max of glyph metrics if white space.
  4234. highlight_start.x = Mathf.Min(highlight_start.x, currentCharacter.origin - highlightState.padding.left);
  4235. highlight_end.x = Mathf.Max(highlight_end.x, currentCharacter.xAdvance + highlightState.padding.right);
  4236. }
  4237. else
  4238. {
  4239. // Use the Min / Max of character bounds
  4240. highlight_start.x = Mathf.Min(highlight_start.x, currentCharacter.bottomLeft.x - highlightState.padding.left);
  4241. highlight_end.x = Mathf.Max(highlight_end.x, currentCharacter.topRight.x + highlightState.padding.right);
  4242. }
  4243. highlight_start.y = Mathf.Min(highlight_start.y, currentCharacter.descender - highlightState.padding.bottom);
  4244. highlight_end.y = Mathf.Max(highlight_end.y, currentCharacter.ascender + highlightState.padding.top);
  4245. }
  4246. }
  4247. // End Highlight if text only contains one character.
  4248. if (beginHighlight && m_characterCount == 1)
  4249. {
  4250. beginHighlight = false;
  4251. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  4252. }
  4253. else if (beginHighlight && (i == lineInfo.lastCharacterIndex || i >= lineInfo.lastVisibleCharacterIndex))
  4254. {
  4255. beginHighlight = false;
  4256. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  4257. }
  4258. else if (beginHighlight && !isHighlightVisible)
  4259. {
  4260. beginHighlight = false;
  4261. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  4262. }
  4263. }
  4264. else
  4265. {
  4266. // End Highlight
  4267. if (beginHighlight == true)
  4268. {
  4269. beginHighlight = false;
  4270. DrawTextHighlight(highlight_start, highlight_end, ref last_vert_index, highlightState.color);
  4271. }
  4272. }
  4273. #endregion
  4274. lastLine = currentLine;
  4275. }
  4276. #endregion
  4277. // Set vertex count for Underline geometry
  4278. m_textInfo.meshInfo[m_Underline.materialIndex].vertexCount = last_vert_index;
  4279. // METRICS ABOUT THE TEXT OBJECT
  4280. m_textInfo.characterCount = m_characterCount;
  4281. m_textInfo.spriteCount = m_spriteCount;
  4282. m_textInfo.lineCount = lineCount;
  4283. m_textInfo.wordCount = wordCount != 0 && m_characterCount > 0 ? wordCount : 1;
  4284. m_textInfo.pageCount = m_pageNumber + 1;
  4285. // End Sampling of Phase II
  4286. k_GenerateTextPhaseIIMarker.End();
  4287. // Phase III - Update Mesh Vertex Data
  4288. k_GenerateTextPhaseIIIMarker.Begin();
  4289. if (m_renderMode == TextRenderFlags.Render && IsActive())
  4290. {
  4291. // Event to allow users to modify the content of the text info before the text is rendered.
  4292. OnPreRenderText?.Invoke(m_textInfo);
  4293. // Must ensure the Canvas support the additional vertex attributes used by TMP.
  4294. // This could be optimized based on canvas render mode settings but gets complicated to handle with multiple text objects using different material presets.
  4295. if (m_canvas.additionalShaderChannels != (AdditionalCanvasShaderChannels)25)
  4296. m_canvas.additionalShaderChannels |= (AdditionalCanvasShaderChannels)25;
  4297. // Sort the geometry of the text object if needed.
  4298. if (m_geometrySortingOrder != VertexSortingOrder.Normal)
  4299. m_textInfo.meshInfo[0].SortGeometry(VertexSortingOrder.Reverse);
  4300. // Upload Mesh Data
  4301. m_mesh.MarkDynamic();
  4302. m_mesh.vertices = m_textInfo.meshInfo[0].vertices;
  4303. m_mesh.SetUVs(0, m_textInfo.meshInfo[0].uvs0);
  4304. m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  4305. //m_mesh.uv4 = m_textInfo.meshInfo[0].uvs4;
  4306. m_mesh.colors32 = m_textInfo.meshInfo[0].colors32;
  4307. // Compute Bounds for the mesh. Manual computation is more efficient then using Mesh.RecalcualteBounds.
  4308. m_mesh.RecalculateBounds();
  4309. //m_mesh.bounds = new Bounds(new Vector3((m_meshExtents.max.x + m_meshExtents.min.x) / 2, (m_meshExtents.max.y + m_meshExtents.min.y) / 2, 0) + offset, new Vector3(m_meshExtents.max.x - m_meshExtents.min.x, m_meshExtents.max.y - m_meshExtents.min.y, 0));
  4310. m_canvasRenderer.SetMesh(m_mesh);
  4311. // Cache CanvasRenderer color of the parent text object.
  4312. Color parentBaseColor = m_canvasRenderer.GetColor();
  4313. bool isCullTransparentMeshEnabled = m_canvasRenderer.cullTransparentMesh;
  4314. for (int i = 1; i < m_textInfo.materialCount; i++)
  4315. {
  4316. // Clear unused vertices
  4317. m_textInfo.meshInfo[i].ClearUnusedVertices();
  4318. if (m_subTextObjects[i] == null) continue;
  4319. // Sort the geometry of the sub-text objects if needed.
  4320. if (m_geometrySortingOrder != VertexSortingOrder.Normal)
  4321. m_textInfo.meshInfo[i].SortGeometry(VertexSortingOrder.Reverse);
  4322. //m_subTextObjects[i].mesh.MarkDynamic();
  4323. m_subTextObjects[i].mesh.vertices = m_textInfo.meshInfo[i].vertices;
  4324. m_subTextObjects[i].mesh.SetUVs(0, m_textInfo.meshInfo[i].uvs0);
  4325. m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  4326. //m_subTextObjects[i].mesh.uv4 = m_textInfo.meshInfo[i].uvs4;
  4327. m_subTextObjects[i].mesh.colors32 = m_textInfo.meshInfo[i].colors32;
  4328. m_subTextObjects[i].mesh.RecalculateBounds();
  4329. m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  4330. // Set CanvasRenderer color to match the parent text object.
  4331. m_subTextObjects[i].canvasRenderer.SetColor(parentBaseColor);
  4332. // Make sure Cull Transparent Mesh of the sub objects matches the parent
  4333. m_subTextObjects[i].canvasRenderer.cullTransparentMesh = isCullTransparentMeshEnabled;
  4334. // Sync RaycastTarget property with parent text object
  4335. m_subTextObjects[i].raycastTarget = this.raycastTarget;
  4336. }
  4337. }
  4338. // Update culling if it has to be delayed due to text layout being dirty.
  4339. if (m_ShouldUpdateCulling)
  4340. UpdateCulling();
  4341. // Event indicating the text has been regenerated.
  4342. TMPro_EventManager.ON_TEXT_CHANGED(this);
  4343. //Debug.Log("***** Done rendering text object ID " + GetInstanceID() + ". *****");
  4344. // End Sampling
  4345. k_GenerateTextPhaseIIIMarker.End();
  4346. k_GenerateTextMarker.End();
  4347. }
  4348. /// <summary>
  4349. /// Method to return the local corners of the Text Container or RectTransform.
  4350. /// </summary>
  4351. /// <returns></returns>
  4352. protected override Vector3[] GetTextContainerLocalCorners()
  4353. {
  4354. if (m_rectTransform == null) m_rectTransform = this.rectTransform;
  4355. m_rectTransform.GetLocalCorners(m_RectTransformCorners);
  4356. return m_RectTransformCorners;
  4357. }
  4358. /// <summary>
  4359. /// Method to Enable or Disable child SubMesh objects.
  4360. /// </summary>
  4361. /// <param name="state"></param>
  4362. protected override void SetActiveSubMeshes(bool state)
  4363. {
  4364. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  4365. {
  4366. if (m_subTextObjects[i].enabled != state)
  4367. m_subTextObjects[i].enabled = state;
  4368. }
  4369. }
  4370. /// <summary>
  4371. /// Destroy Sub Mesh Objects
  4372. /// </summary>
  4373. protected override void DestroySubMeshObjects()
  4374. {
  4375. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  4376. DestroyImmediate(m_subTextObjects[i]);
  4377. }
  4378. /// <summary>
  4379. /// Method returning the compound bounds of the text object and child sub objects.
  4380. /// </summary>
  4381. /// <returns></returns>
  4382. protected override Bounds GetCompoundBounds()
  4383. {
  4384. Bounds mainBounds = m_mesh.bounds;
  4385. Vector3 min = mainBounds.min;
  4386. Vector3 max = mainBounds.max;
  4387. for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++)
  4388. {
  4389. Bounds subBounds = m_subTextObjects[i].mesh.bounds;
  4390. min.x = min.x < subBounds.min.x ? min.x : subBounds.min.x;
  4391. min.y = min.y < subBounds.min.y ? min.y : subBounds.min.y;
  4392. max.x = max.x > subBounds.max.x ? max.x : subBounds.max.x;
  4393. max.y = max.y > subBounds.max.y ? max.y : subBounds.max.y;
  4394. }
  4395. Vector3 center = (min + max) / 2;
  4396. Vector2 size = max - min;
  4397. return new Bounds(center, size);
  4398. }
  4399. internal override Rect GetCanvasSpaceClippingRect()
  4400. {
  4401. if (m_canvas == null || m_canvas.rootCanvas == null || m_mesh == null)
  4402. return Rect.zero;
  4403. Transform rootCanvasTransform = m_canvas.rootCanvas.transform;
  4404. Bounds compoundBounds = GetCompoundBounds();
  4405. Vector2 position = rootCanvasTransform.InverseTransformPoint(m_rectTransform.position);
  4406. Vector2 canvasLossyScale = rootCanvasTransform.lossyScale;
  4407. Vector2 lossyScale = m_rectTransform.lossyScale / canvasLossyScale;
  4408. return new Rect(position + compoundBounds.min * lossyScale, compoundBounds.size * lossyScale);
  4409. }
  4410. /// <summary>
  4411. /// Method to Update Scale in UV2
  4412. /// </summary>
  4413. //void UpdateSDFScale(float lossyScale)
  4414. //{
  4415. // // TODO: Resolve - Underline / Strikethrough segments not getting their SDF Scale adjusted.
  4416. // //Debug.Log("Updating SDF Scale.");
  4417. // // Return if we don't have a valid reference to a Canvas.
  4418. // if (m_canvas == null)
  4419. // {
  4420. // m_canvas = GetCanvas();
  4421. // if (m_canvas == null) return;
  4422. // }
  4423. // lossyScale = lossyScale == 0 ? 1 : lossyScale;
  4424. // float xScale = 0;
  4425. // float canvasScaleFactor = m_canvas.scaleFactor;
  4426. // if (m_canvas.renderMode == RenderMode.ScreenSpaceOverlay)
  4427. // xScale = lossyScale / canvasScaleFactor;
  4428. // else if (m_canvas.renderMode == RenderMode.ScreenSpaceCamera)
  4429. // xScale = m_canvas.worldCamera != null ? lossyScale : 1;
  4430. // else
  4431. // xScale = lossyScale;
  4432. // // Iterate through each of the characters.
  4433. // for (int i = 0; i < m_textInfo.characterCount; i++)
  4434. // {
  4435. // // Only update scale for visible characters.
  4436. // if (m_textInfo.characterInfo[i].isVisible && m_textInfo.characterInfo[i].elementType == TMP_TextElementType.Character)
  4437. // {
  4438. // float scale = xScale * m_textInfo.characterInfo[i].scale * (1 - m_charWidthAdjDelta);
  4439. // if (!m_textInfo.characterInfo[i].isUsingAlternateTypeface && (m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold) scale *= -1;
  4440. // int index = m_textInfo.characterInfo[i].materialReferenceIndex;
  4441. // int vertexIndex = m_textInfo.characterInfo[i].vertexIndex;
  4442. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 0].y = scale;
  4443. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 1].y = scale;
  4444. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 2].y = scale;
  4445. // m_textInfo.meshInfo[index].uvs2[vertexIndex + 3].y = scale;
  4446. // }
  4447. // }
  4448. // // Push the updated uv2 scale information to the meshes.
  4449. // for (int i = 0; i < m_textInfo.materialCount; i++)
  4450. // {
  4451. // if (i == 0)
  4452. // {
  4453. // m_mesh.uv2 = m_textInfo.meshInfo[0].uvs2;
  4454. // m_canvasRenderer.SetMesh(m_mesh);
  4455. // }
  4456. // else
  4457. // {
  4458. // m_subTextObjects[i].mesh.uv2 = m_textInfo.meshInfo[i].uvs2;
  4459. // m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  4460. // }
  4461. // }
  4462. //}
  4463. /// <summary>
  4464. /// Method to update the SDF Scale in UV2.
  4465. /// </summary>
  4466. /// <param name="scaleDelta"></param>
  4467. void UpdateSDFScale(float scaleDelta)
  4468. {
  4469. if (scaleDelta == 0 || scaleDelta == float.PositiveInfinity || scaleDelta == float.NegativeInfinity)
  4470. {
  4471. m_havePropertiesChanged = true;
  4472. OnPreRenderCanvas();
  4473. return;
  4474. }
  4475. for (int materialIndex = 0; materialIndex < m_textInfo.materialCount; materialIndex ++)
  4476. {
  4477. TMP_MeshInfo meshInfo = m_textInfo.meshInfo[materialIndex];
  4478. for (int i = 0; i < meshInfo.uvs0.Length; i++)
  4479. {
  4480. meshInfo.uvs0[i].w *= Mathf.Abs(scaleDelta);
  4481. }
  4482. }
  4483. // Push the updated uv0 scale information to the meshes.
  4484. for (int i = 0; i < m_textInfo.materialCount; i++)
  4485. {
  4486. if (i == 0)
  4487. {
  4488. m_mesh.SetUVs(0, m_textInfo.meshInfo[0].uvs0);
  4489. m_canvasRenderer.SetMesh(m_mesh);
  4490. }
  4491. else
  4492. {
  4493. m_subTextObjects[i].mesh.SetUVs(0, m_textInfo.meshInfo[i].uvs0);
  4494. m_subTextObjects[i].canvasRenderer.SetMesh(m_subTextObjects[i].mesh);
  4495. }
  4496. }
  4497. }
  4498. #endregion
  4499. }
  4500. }