linerules.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. package uniseg
  2. import "unicode/utf8"
  3. // The states of the line break parser.
  4. const (
  5. lbAny = iota
  6. lbBK
  7. lbCR
  8. lbLF
  9. lbNL
  10. lbSP
  11. lbZW
  12. lbWJ
  13. lbGL
  14. lbBA
  15. lbHY
  16. lbCL
  17. lbCP
  18. lbEX
  19. lbIS
  20. lbSY
  21. lbOP
  22. lbQU
  23. lbQUSP
  24. lbNS
  25. lbCLCPSP
  26. lbB2
  27. lbB2SP
  28. lbCB
  29. lbBB
  30. lbLB21a
  31. lbHL
  32. lbAL
  33. lbNU
  34. lbPR
  35. lbEB
  36. lbIDEM
  37. lbNUNU
  38. lbNUSY
  39. lbNUIS
  40. lbNUCL
  41. lbNUCP
  42. lbPO
  43. lbJL
  44. lbJV
  45. lbJT
  46. lbH2
  47. lbH3
  48. lbOddRI
  49. lbEvenRI
  50. lbExtPicCn
  51. lbZWJBit = 64
  52. lbCPeaFWHBit = 128
  53. )
  54. // These constants define whether a given text may be broken into the next line.
  55. // If the break is optional (LineCanBreak), you may choose to break or not based
  56. // on your own criteria, for example, if the text has reached the available
  57. // width.
  58. const (
  59. LineDontBreak = iota // You may not break the line here.
  60. LineCanBreak // You may or may not break the line here.
  61. LineMustBreak // You must break the line here.
  62. )
  63. // lbTransitions implements the line break parser's state transitions. It's
  64. // anologous to [grTransitions], see comments there for details.
  65. //
  66. // Unicode version 15.0.0.
  67. func lbTransitions(state, prop int) (newState, lineBreak, rule int) {
  68. switch uint64(state) | uint64(prop)<<32 {
  69. // LB4.
  70. case lbBK | prAny<<32:
  71. return lbAny, LineMustBreak, 40
  72. // LB5.
  73. case lbCR | prLF<<32:
  74. return lbLF, LineDontBreak, 50
  75. case lbCR | prAny<<32:
  76. return lbAny, LineMustBreak, 50
  77. case lbLF | prAny<<32:
  78. return lbAny, LineMustBreak, 50
  79. case lbNL | prAny<<32:
  80. return lbAny, LineMustBreak, 50
  81. // LB6.
  82. case lbAny | prBK<<32:
  83. return lbBK, LineDontBreak, 60
  84. case lbAny | prCR<<32:
  85. return lbCR, LineDontBreak, 60
  86. case lbAny | prLF<<32:
  87. return lbLF, LineDontBreak, 60
  88. case lbAny | prNL<<32:
  89. return lbNL, LineDontBreak, 60
  90. // LB7.
  91. case lbAny | prSP<<32:
  92. return lbSP, LineDontBreak, 70
  93. case lbAny | prZW<<32:
  94. return lbZW, LineDontBreak, 70
  95. // LB8.
  96. case lbZW | prSP<<32:
  97. return lbZW, LineDontBreak, 70
  98. case lbZW | prAny<<32:
  99. return lbAny, LineCanBreak, 80
  100. // LB11.
  101. case lbAny | prWJ<<32:
  102. return lbWJ, LineDontBreak, 110
  103. case lbWJ | prAny<<32:
  104. return lbAny, LineDontBreak, 110
  105. // LB12.
  106. case lbAny | prGL<<32:
  107. return lbGL, LineCanBreak, 310
  108. case lbGL | prAny<<32:
  109. return lbAny, LineDontBreak, 120
  110. // LB13 (simple transitions).
  111. case lbAny | prCL<<32:
  112. return lbCL, LineCanBreak, 310
  113. case lbAny | prCP<<32:
  114. return lbCP, LineCanBreak, 310
  115. case lbAny | prEX<<32:
  116. return lbEX, LineDontBreak, 130
  117. case lbAny | prIS<<32:
  118. return lbIS, LineCanBreak, 310
  119. case lbAny | prSY<<32:
  120. return lbSY, LineCanBreak, 310
  121. // LB14.
  122. case lbAny | prOP<<32:
  123. return lbOP, LineCanBreak, 310
  124. case lbOP | prSP<<32:
  125. return lbOP, LineDontBreak, 70
  126. case lbOP | prAny<<32:
  127. return lbAny, LineDontBreak, 140
  128. // LB15.
  129. case lbQU | prSP<<32:
  130. return lbQUSP, LineDontBreak, 70
  131. case lbQU | prOP<<32:
  132. return lbOP, LineDontBreak, 150
  133. case lbQUSP | prOP<<32:
  134. return lbOP, LineDontBreak, 150
  135. // LB16.
  136. case lbCL | prSP<<32:
  137. return lbCLCPSP, LineDontBreak, 70
  138. case lbNUCL | prSP<<32:
  139. return lbCLCPSP, LineDontBreak, 70
  140. case lbCP | prSP<<32:
  141. return lbCLCPSP, LineDontBreak, 70
  142. case lbNUCP | prSP<<32:
  143. return lbCLCPSP, LineDontBreak, 70
  144. case lbCL | prNS<<32:
  145. return lbNS, LineDontBreak, 160
  146. case lbNUCL | prNS<<32:
  147. return lbNS, LineDontBreak, 160
  148. case lbCP | prNS<<32:
  149. return lbNS, LineDontBreak, 160
  150. case lbNUCP | prNS<<32:
  151. return lbNS, LineDontBreak, 160
  152. case lbCLCPSP | prNS<<32:
  153. return lbNS, LineDontBreak, 160
  154. // LB17.
  155. case lbAny | prB2<<32:
  156. return lbB2, LineCanBreak, 310
  157. case lbB2 | prSP<<32:
  158. return lbB2SP, LineDontBreak, 70
  159. case lbB2 | prB2<<32:
  160. return lbB2, LineDontBreak, 170
  161. case lbB2SP | prB2<<32:
  162. return lbB2, LineDontBreak, 170
  163. // LB18.
  164. case lbSP | prAny<<32:
  165. return lbAny, LineCanBreak, 180
  166. case lbQUSP | prAny<<32:
  167. return lbAny, LineCanBreak, 180
  168. case lbCLCPSP | prAny<<32:
  169. return lbAny, LineCanBreak, 180
  170. case lbB2SP | prAny<<32:
  171. return lbAny, LineCanBreak, 180
  172. // LB19.
  173. case lbAny | prQU<<32:
  174. return lbQU, LineDontBreak, 190
  175. case lbQU | prAny<<32:
  176. return lbAny, LineDontBreak, 190
  177. // LB20.
  178. case lbAny | prCB<<32:
  179. return lbCB, LineCanBreak, 200
  180. case lbCB | prAny<<32:
  181. return lbAny, LineCanBreak, 200
  182. // LB21.
  183. case lbAny | prBA<<32:
  184. return lbBA, LineDontBreak, 210
  185. case lbAny | prHY<<32:
  186. return lbHY, LineDontBreak, 210
  187. case lbAny | prNS<<32:
  188. return lbNS, LineDontBreak, 210
  189. case lbAny | prBB<<32:
  190. return lbBB, LineCanBreak, 310
  191. case lbBB | prAny<<32:
  192. return lbAny, LineDontBreak, 210
  193. // LB21a.
  194. case lbAny | prHL<<32:
  195. return lbHL, LineCanBreak, 310
  196. case lbHL | prHY<<32:
  197. return lbLB21a, LineDontBreak, 210
  198. case lbHL | prBA<<32:
  199. return lbLB21a, LineDontBreak, 210
  200. case lbLB21a | prAny<<32:
  201. return lbAny, LineDontBreak, 211
  202. // LB21b.
  203. case lbSY | prHL<<32:
  204. return lbHL, LineDontBreak, 212
  205. case lbNUSY | prHL<<32:
  206. return lbHL, LineDontBreak, 212
  207. // LB22.
  208. case lbAny | prIN<<32:
  209. return lbAny, LineDontBreak, 220
  210. // LB23.
  211. case lbAny | prAL<<32:
  212. return lbAL, LineCanBreak, 310
  213. case lbAny | prNU<<32:
  214. return lbNU, LineCanBreak, 310
  215. case lbAL | prNU<<32:
  216. return lbNU, LineDontBreak, 230
  217. case lbHL | prNU<<32:
  218. return lbNU, LineDontBreak, 230
  219. case lbNU | prAL<<32:
  220. return lbAL, LineDontBreak, 230
  221. case lbNU | prHL<<32:
  222. return lbHL, LineDontBreak, 230
  223. case lbNUNU | prAL<<32:
  224. return lbAL, LineDontBreak, 230
  225. case lbNUNU | prHL<<32:
  226. return lbHL, LineDontBreak, 230
  227. // LB23a.
  228. case lbAny | prPR<<32:
  229. return lbPR, LineCanBreak, 310
  230. case lbAny | prID<<32:
  231. return lbIDEM, LineCanBreak, 310
  232. case lbAny | prEB<<32:
  233. return lbEB, LineCanBreak, 310
  234. case lbAny | prEM<<32:
  235. return lbIDEM, LineCanBreak, 310
  236. case lbPR | prID<<32:
  237. return lbIDEM, LineDontBreak, 231
  238. case lbPR | prEB<<32:
  239. return lbEB, LineDontBreak, 231
  240. case lbPR | prEM<<32:
  241. return lbIDEM, LineDontBreak, 231
  242. case lbIDEM | prPO<<32:
  243. return lbPO, LineDontBreak, 231
  244. case lbEB | prPO<<32:
  245. return lbPO, LineDontBreak, 231
  246. // LB24.
  247. case lbAny | prPO<<32:
  248. return lbPO, LineCanBreak, 310
  249. case lbPR | prAL<<32:
  250. return lbAL, LineDontBreak, 240
  251. case lbPR | prHL<<32:
  252. return lbHL, LineDontBreak, 240
  253. case lbPO | prAL<<32:
  254. return lbAL, LineDontBreak, 240
  255. case lbPO | prHL<<32:
  256. return lbHL, LineDontBreak, 240
  257. case lbAL | prPR<<32:
  258. return lbPR, LineDontBreak, 240
  259. case lbAL | prPO<<32:
  260. return lbPO, LineDontBreak, 240
  261. case lbHL | prPR<<32:
  262. return lbPR, LineDontBreak, 240
  263. case lbHL | prPO<<32:
  264. return lbPO, LineDontBreak, 240
  265. // LB25 (simple transitions).
  266. case lbPR | prNU<<32:
  267. return lbNU, LineDontBreak, 250
  268. case lbPO | prNU<<32:
  269. return lbNU, LineDontBreak, 250
  270. case lbOP | prNU<<32:
  271. return lbNU, LineDontBreak, 250
  272. case lbHY | prNU<<32:
  273. return lbNU, LineDontBreak, 250
  274. case lbNU | prNU<<32:
  275. return lbNUNU, LineDontBreak, 250
  276. case lbNU | prSY<<32:
  277. return lbNUSY, LineDontBreak, 250
  278. case lbNU | prIS<<32:
  279. return lbNUIS, LineDontBreak, 250
  280. case lbNUNU | prNU<<32:
  281. return lbNUNU, LineDontBreak, 250
  282. case lbNUNU | prSY<<32:
  283. return lbNUSY, LineDontBreak, 250
  284. case lbNUNU | prIS<<32:
  285. return lbNUIS, LineDontBreak, 250
  286. case lbNUSY | prNU<<32:
  287. return lbNUNU, LineDontBreak, 250
  288. case lbNUSY | prSY<<32:
  289. return lbNUSY, LineDontBreak, 250
  290. case lbNUSY | prIS<<32:
  291. return lbNUIS, LineDontBreak, 250
  292. case lbNUIS | prNU<<32:
  293. return lbNUNU, LineDontBreak, 250
  294. case lbNUIS | prSY<<32:
  295. return lbNUSY, LineDontBreak, 250
  296. case lbNUIS | prIS<<32:
  297. return lbNUIS, LineDontBreak, 250
  298. case lbNU | prCL<<32:
  299. return lbNUCL, LineDontBreak, 250
  300. case lbNU | prCP<<32:
  301. return lbNUCP, LineDontBreak, 250
  302. case lbNUNU | prCL<<32:
  303. return lbNUCL, LineDontBreak, 250
  304. case lbNUNU | prCP<<32:
  305. return lbNUCP, LineDontBreak, 250
  306. case lbNUSY | prCL<<32:
  307. return lbNUCL, LineDontBreak, 250
  308. case lbNUSY | prCP<<32:
  309. return lbNUCP, LineDontBreak, 250
  310. case lbNUIS | prCL<<32:
  311. return lbNUCL, LineDontBreak, 250
  312. case lbNUIS | prCP<<32:
  313. return lbNUCP, LineDontBreak, 250
  314. case lbNU | prPO<<32:
  315. return lbPO, LineDontBreak, 250
  316. case lbNUNU | prPO<<32:
  317. return lbPO, LineDontBreak, 250
  318. case lbNUSY | prPO<<32:
  319. return lbPO, LineDontBreak, 250
  320. case lbNUIS | prPO<<32:
  321. return lbPO, LineDontBreak, 250
  322. case lbNUCL | prPO<<32:
  323. return lbPO, LineDontBreak, 250
  324. case lbNUCP | prPO<<32:
  325. return lbPO, LineDontBreak, 250
  326. case lbNU | prPR<<32:
  327. return lbPR, LineDontBreak, 250
  328. case lbNUNU | prPR<<32:
  329. return lbPR, LineDontBreak, 250
  330. case lbNUSY | prPR<<32:
  331. return lbPR, LineDontBreak, 250
  332. case lbNUIS | prPR<<32:
  333. return lbPR, LineDontBreak, 250
  334. case lbNUCL | prPR<<32:
  335. return lbPR, LineDontBreak, 250
  336. case lbNUCP | prPR<<32:
  337. return lbPR, LineDontBreak, 250
  338. // LB26.
  339. case lbAny | prJL<<32:
  340. return lbJL, LineCanBreak, 310
  341. case lbAny | prJV<<32:
  342. return lbJV, LineCanBreak, 310
  343. case lbAny | prJT<<32:
  344. return lbJT, LineCanBreak, 310
  345. case lbAny | prH2<<32:
  346. return lbH2, LineCanBreak, 310
  347. case lbAny | prH3<<32:
  348. return lbH3, LineCanBreak, 310
  349. case lbJL | prJL<<32:
  350. return lbJL, LineDontBreak, 260
  351. case lbJL | prJV<<32:
  352. return lbJV, LineDontBreak, 260
  353. case lbJL | prH2<<32:
  354. return lbH2, LineDontBreak, 260
  355. case lbJL | prH3<<32:
  356. return lbH3, LineDontBreak, 260
  357. case lbJV | prJV<<32:
  358. return lbJV, LineDontBreak, 260
  359. case lbJV | prJT<<32:
  360. return lbJT, LineDontBreak, 260
  361. case lbH2 | prJV<<32:
  362. return lbJV, LineDontBreak, 260
  363. case lbH2 | prJT<<32:
  364. return lbJT, LineDontBreak, 260
  365. case lbJT | prJT<<32:
  366. return lbJT, LineDontBreak, 260
  367. case lbH3 | prJT<<32:
  368. return lbJT, LineDontBreak, 260
  369. // LB27.
  370. case lbJL | prPO<<32:
  371. return lbPO, LineDontBreak, 270
  372. case lbJV | prPO<<32:
  373. return lbPO, LineDontBreak, 270
  374. case lbJT | prPO<<32:
  375. return lbPO, LineDontBreak, 270
  376. case lbH2 | prPO<<32:
  377. return lbPO, LineDontBreak, 270
  378. case lbH3 | prPO<<32:
  379. return lbPO, LineDontBreak, 270
  380. case lbPR | prJL<<32:
  381. return lbJL, LineDontBreak, 270
  382. case lbPR | prJV<<32:
  383. return lbJV, LineDontBreak, 270
  384. case lbPR | prJT<<32:
  385. return lbJT, LineDontBreak, 270
  386. case lbPR | prH2<<32:
  387. return lbH2, LineDontBreak, 270
  388. case lbPR | prH3<<32:
  389. return lbH3, LineDontBreak, 270
  390. // LB28.
  391. case lbAL | prAL<<32:
  392. return lbAL, LineDontBreak, 280
  393. case lbAL | prHL<<32:
  394. return lbHL, LineDontBreak, 280
  395. case lbHL | prAL<<32:
  396. return lbAL, LineDontBreak, 280
  397. case lbHL | prHL<<32:
  398. return lbHL, LineDontBreak, 280
  399. // LB29.
  400. case lbIS | prAL<<32:
  401. return lbAL, LineDontBreak, 290
  402. case lbIS | prHL<<32:
  403. return lbHL, LineDontBreak, 290
  404. case lbNUIS | prAL<<32:
  405. return lbAL, LineDontBreak, 290
  406. case lbNUIS | prHL<<32:
  407. return lbHL, LineDontBreak, 290
  408. default:
  409. return -1, -1, -1
  410. }
  411. }
  412. // transitionLineBreakState determines the new state of the line break parser
  413. // given the current state and the next code point. It also returns the type of
  414. // line break: LineDontBreak, LineCanBreak, or LineMustBreak. If more than one
  415. // code point is needed to determine the new state, the byte slice or the string
  416. // starting after rune "r" can be used (whichever is not nil or empty) for
  417. // further lookups.
  418. func transitionLineBreakState(state int, r rune, b []byte, str string) (newState int, lineBreak int) {
  419. // Determine the property of the next character.
  420. nextProperty, generalCategory := propertyLineBreak(r)
  421. // Prepare.
  422. var forceNoBreak, isCPeaFWH bool
  423. if state >= 0 && state&lbCPeaFWHBit != 0 {
  424. isCPeaFWH = true // LB30: CP but ea is not F, W, or H.
  425. state = state &^ lbCPeaFWHBit
  426. }
  427. if state >= 0 && state&lbZWJBit != 0 {
  428. state = state &^ lbZWJBit // Extract zero-width joiner bit.
  429. forceNoBreak = true // LB8a.
  430. }
  431. defer func() {
  432. // Transition into LB30.
  433. if newState == lbCP || newState == lbNUCP {
  434. ea := propertyEastAsianWidth(r)
  435. if ea != prF && ea != prW && ea != prH {
  436. newState |= lbCPeaFWHBit
  437. }
  438. }
  439. // Override break.
  440. if forceNoBreak {
  441. lineBreak = LineDontBreak
  442. }
  443. }()
  444. // LB1.
  445. if nextProperty == prAI || nextProperty == prSG || nextProperty == prXX {
  446. nextProperty = prAL
  447. } else if nextProperty == prSA {
  448. if generalCategory == gcMn || generalCategory == gcMc {
  449. nextProperty = prCM
  450. } else {
  451. nextProperty = prAL
  452. }
  453. } else if nextProperty == prCJ {
  454. nextProperty = prNS
  455. }
  456. // Combining marks.
  457. if nextProperty == prZWJ || nextProperty == prCM {
  458. var bit int
  459. if nextProperty == prZWJ {
  460. bit = lbZWJBit
  461. }
  462. mustBreakState := state < 0 || state == lbBK || state == lbCR || state == lbLF || state == lbNL
  463. if !mustBreakState && state != lbSP && state != lbZW && state != lbQUSP && state != lbCLCPSP && state != lbB2SP {
  464. // LB9.
  465. return state | bit, LineDontBreak
  466. } else {
  467. // LB10.
  468. if mustBreakState {
  469. return lbAL | bit, LineMustBreak
  470. }
  471. return lbAL | bit, LineCanBreak
  472. }
  473. }
  474. // Find the applicable transition in the table.
  475. var rule int
  476. newState, lineBreak, rule = lbTransitions(state, nextProperty)
  477. if newState < 0 {
  478. // No specific transition found. Try the less specific ones.
  479. anyPropProp, anyPropLineBreak, anyPropRule := lbTransitions(state, prAny)
  480. anyStateProp, anyStateLineBreak, anyStateRule := lbTransitions(lbAny, nextProperty)
  481. if anyPropProp >= 0 && anyStateProp >= 0 {
  482. // Both apply. We'll use a mix (see comments for grTransitions).
  483. newState, lineBreak, rule = anyStateProp, anyStateLineBreak, anyStateRule
  484. if anyPropRule < anyStateRule {
  485. lineBreak, rule = anyPropLineBreak, anyPropRule
  486. }
  487. } else if anyPropProp >= 0 {
  488. // We only have a specific state.
  489. newState, lineBreak, rule = anyPropProp, anyPropLineBreak, anyPropRule
  490. // This branch will probably never be reached because okAnyState will
  491. // always be true given the current transition map. But we keep it here
  492. // for future modifications to the transition map where this may not be
  493. // true anymore.
  494. } else if anyStateProp >= 0 {
  495. // We only have a specific property.
  496. newState, lineBreak, rule = anyStateProp, anyStateLineBreak, anyStateRule
  497. } else {
  498. // No known transition. LB31: ALL ÷ ALL.
  499. newState, lineBreak, rule = lbAny, LineCanBreak, 310
  500. }
  501. }
  502. // LB12a.
  503. if rule > 121 &&
  504. nextProperty == prGL &&
  505. (state != lbSP && state != lbBA && state != lbHY && state != lbLB21a && state != lbQUSP && state != lbCLCPSP && state != lbB2SP) {
  506. return lbGL, LineDontBreak
  507. }
  508. // LB13.
  509. if rule > 130 && state != lbNU && state != lbNUNU {
  510. switch nextProperty {
  511. case prCL:
  512. return lbCL, LineDontBreak
  513. case prCP:
  514. return lbCP, LineDontBreak
  515. case prIS:
  516. return lbIS, LineDontBreak
  517. case prSY:
  518. return lbSY, LineDontBreak
  519. }
  520. }
  521. // LB25 (look ahead).
  522. if rule > 250 &&
  523. (state == lbPR || state == lbPO) &&
  524. nextProperty == prOP || nextProperty == prHY {
  525. var r rune
  526. if b != nil { // Byte slice version.
  527. r, _ = utf8.DecodeRune(b)
  528. } else { // String version.
  529. r, _ = utf8.DecodeRuneInString(str)
  530. }
  531. if r != utf8.RuneError {
  532. pr, _ := propertyLineBreak(r)
  533. if pr == prNU {
  534. return lbNU, LineDontBreak
  535. }
  536. }
  537. }
  538. // LB30 (part one).
  539. if rule > 300 {
  540. if (state == lbAL || state == lbHL || state == lbNU || state == lbNUNU) && nextProperty == prOP {
  541. ea := propertyEastAsianWidth(r)
  542. if ea != prF && ea != prW && ea != prH {
  543. return lbOP, LineDontBreak
  544. }
  545. } else if isCPeaFWH {
  546. switch nextProperty {
  547. case prAL:
  548. return lbAL, LineDontBreak
  549. case prHL:
  550. return lbHL, LineDontBreak
  551. case prNU:
  552. return lbNU, LineDontBreak
  553. }
  554. }
  555. }
  556. // LB30a.
  557. if newState == lbAny && nextProperty == prRI {
  558. if state != lbOddRI && state != lbEvenRI { // Includes state == -1.
  559. // Transition into the first RI.
  560. return lbOddRI, lineBreak
  561. }
  562. if state == lbOddRI {
  563. // Don't break pairs of Regional Indicators.
  564. return lbEvenRI, LineDontBreak
  565. }
  566. return lbOddRI, lineBreak
  567. }
  568. // LB30b.
  569. if rule > 302 {
  570. if nextProperty == prEM {
  571. if state == lbEB || state == lbExtPicCn {
  572. return prAny, LineDontBreak
  573. }
  574. }
  575. graphemeProperty := propertyGraphemes(r)
  576. if graphemeProperty == prExtendedPictographic && generalCategory == gcCn {
  577. return lbExtPicCn, LineCanBreak
  578. }
  579. }
  580. return
  581. }