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.

742 lines
24 KiB

5 years ago
  1. /* --COPYRIGHT--,BSD
  2. * Copyright (c) 2013, Texas Instruments Incorporated
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * * Neither the name of Texas Instruments Incorporated nor the names of
  17. * its contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  27. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  28. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  29. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  30. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. * --/COPYRIGHT--*/
  32. #include "grlib.h"
  33. //*****************************************************************************
  34. //
  35. //! \addtogroup string_api
  36. //! @{
  37. //
  38. //*****************************************************************************
  39. //*****************************************************************************
  40. //
  41. // The character printed by GrStringDraw in place of any character in the
  42. // string which does not appear in the font. When using a font which does not
  43. // include this character, a space is left instead.
  44. //
  45. //*****************************************************************************
  46. #define ABSENT_CHAR_REPLACEMENT '.'
  47. //*****************************************************************************
  48. //
  49. // Counts the number of zeros at the start of a word. This macro uses
  50. // compiler-specific constructs to perform an inline insertion of the "clz"
  51. // instruction, which counts the leading zeros directly.
  52. //
  53. //*****************************************************************************
  54. int NumLeadingZeros(long x)
  55. {
  56. long y = 0x80, count =0;
  57. long i;
  58. for (i=0; i< 32; i++)
  59. {
  60. if (0x00 != (x & y ))
  61. break;
  62. count++;
  63. y = y >> 1;
  64. }
  65. return count;
  66. }
  67. //*****************************************************************************
  68. //
  69. //! Determines the width of a string.
  70. //!
  71. //! \param pContext is a pointer to the drawing context to use.
  72. //! \param pcString is the string in question.
  73. //! \param lLength is the length of the string.
  74. //!
  75. //! This function determines the width of a string (or portion of the string)
  76. //! when drawn with a particular font. The \e lLength parameter allows a
  77. //! portion of the string to be examined without having to insert a NULL
  78. //! character at the stopping point (would not be possible if the string was
  79. //! located in flash); specifying a length of -1 will cause the width of the
  80. //! entire string to be computed.
  81. //!
  82. //! \return Returns the width of the string in pixels.
  83. //
  84. //*****************************************************************************
  85. long
  86. GrStringWidthGet(const tContext *pContext, const char *pcString, long lLength)
  87. {
  88. const unsigned short *pusOffset;
  89. const unsigned char *pucData;
  90. unsigned char ucFirst, ucLast, ucAbsent;
  91. long lWidth;
  92. //
  93. // Check the arguments.
  94. //
  95. assert(pContext);
  96. assert(pcString);
  97. //
  98. // Get some pointers to relevant information in the font to make things
  99. // easier, and give the compiler a hint about extraneous loads that it can
  100. // avoid.
  101. //
  102. if(pContext->pFont->ucFormat & FONT_EX_MARKER)
  103. {
  104. tFontEx *pFont;
  105. pFont = (tFontEx *)(pContext->pFont);
  106. pucData = pFont->pucData;
  107. pusOffset = pFont->pusOffset;
  108. ucFirst = pFont->ucFirst;
  109. ucLast = pFont->ucLast;
  110. //
  111. // Does the default absent character replacement exist in the font?
  112. //
  113. if((ABSENT_CHAR_REPLACEMENT >= ucFirst) &&
  114. (ABSENT_CHAR_REPLACEMENT <= ucLast))
  115. {
  116. //
  117. // Yes - use the standard character when an absent character is
  118. // found.
  119. //
  120. ucAbsent = ABSENT_CHAR_REPLACEMENT;
  121. }
  122. else
  123. {
  124. //
  125. // The default absent character is not present in the font so use
  126. // the first character (we only use its width here) instead.
  127. //
  128. ucAbsent = pFont->ucFirst;
  129. }
  130. }
  131. else
  132. {
  133. pucData = pContext->pFont->pucData;
  134. pusOffset = pContext->pFont->pusOffset;
  135. ucFirst = 32;
  136. ucLast = 126;
  137. ucAbsent = ABSENT_CHAR_REPLACEMENT;
  138. }
  139. //
  140. // Loop through the characters in the string.
  141. //
  142. for(lWidth = 0; *pcString && lLength; pcString++, lLength--)
  143. {
  144. //
  145. // Get a pointer to the font data for the next character from the
  146. // string. If there is not a glyph for the next character, replace it
  147. // with a ".".
  148. //
  149. if((*pcString >= ucFirst) && (*pcString <= ucLast))
  150. {
  151. //
  152. // Add the width of this character as drawn with the given font.
  153. //
  154. lWidth += pucData[pusOffset[*pcString - ucFirst] + 1];
  155. }
  156. else
  157. {
  158. //
  159. // This character does not exist in the font so replace it with
  160. // a '.' instead. This matches the approach taken in GrStringDraw
  161. // and ensures that the width returned here represents the
  162. // rendered dimension of the string.
  163. //
  164. lWidth += pucData[pusOffset[ucAbsent - ucFirst] + 1];
  165. }
  166. }
  167. //
  168. // Return the width of the string.
  169. //
  170. return(lWidth);
  171. }
  172. //*****************************************************************************
  173. //
  174. //! Draws a string.
  175. //!
  176. //! \param pContext is a pointer to the drawing context to use.
  177. //! \param pcString is a pointer to the string to be drawn.
  178. //! \param lLength is the number of characters from the string that should be
  179. //! drawn on the screen.
  180. //! \param lX is the X coordinate of the upper left corner of the string
  181. //! position on the screen.
  182. //! \param lY is the Y coordinate of the upper left corner of the string
  183. //! position on the screen.
  184. //! \param bOpaque is true of the background of each character should be drawn
  185. //! and false if it should not (leaving the background as is).
  186. //!
  187. //! This function draws a string of test on the screen. The \e lLength
  188. //! parameter allows a portion of the string to be examined without having to
  189. //! insert a NULL character at the stopping point (which would not be possible
  190. //! if the string was located in flash); specifying a length of -1 will cause
  191. //! the entire string to be rendered (subject to clipping).
  192. //!
  193. //! \return None.
  194. //
  195. //*****************************************************************************
  196. void
  197. GrStringDraw(const tContext *pContext, const char *pcString, long lLength,
  198. long lX, long lY, unsigned long bOpaque)
  199. {
  200. long lIdx, lX0, lY0, lCount, lOff, lOn, lBit;
  201. const unsigned char *pucData;
  202. const unsigned char *pucGlyphs;
  203. const unsigned short *pusOffset;
  204. unsigned char ucFirst, ucLast, ucAbsent;
  205. tContext sCon;
  206. long lYSave = lY;
  207. lY = 0;
  208. //
  209. // Check the arguments.
  210. //
  211. assert(pContext);
  212. assert(pcString);
  213. //
  214. // Copy the drawing context into a local structure that can be modified.
  215. //
  216. sCon = *pContext;
  217. //
  218. // Extract various parameters from the font depending upon whether it's
  219. // in the tFont or tFontEx format.
  220. //
  221. if(pContext->pFont->ucFormat & FONT_EX_MARKER)
  222. {
  223. tFontEx *pFont;
  224. pFont = (tFontEx *)(pContext->pFont);
  225. pucGlyphs = pFont->pucData;
  226. pusOffset = pFont->pusOffset;
  227. ucFirst = pFont->ucFirst;
  228. ucLast = pFont->ucLast;
  229. //
  230. // Does the default absent character replacement exist in the font?
  231. //
  232. if((ABSENT_CHAR_REPLACEMENT >= ucFirst) &&
  233. (ABSENT_CHAR_REPLACEMENT <= ucLast))
  234. {
  235. //
  236. // Yes - use the standard character when an absent character is
  237. // found.
  238. //
  239. ucAbsent = ABSENT_CHAR_REPLACEMENT;
  240. }
  241. else
  242. {
  243. //
  244. // The default absent character is not present in the font so use
  245. // the first character instead.
  246. //
  247. ucAbsent = pFont->ucFirst;
  248. }
  249. }
  250. else
  251. {
  252. pucGlyphs = pContext->pFont->pucData;
  253. pusOffset = pContext->pFont->pusOffset;
  254. ucFirst = 32;
  255. ucLast = 126;
  256. ucAbsent = ABSENT_CHAR_REPLACEMENT;
  257. }
  258. //
  259. // Loop through the characters in the string.
  260. //
  261. while(*pcString && lLength--)
  262. {
  263. //
  264. // Stop drawing the string if the right edge of the clipping region has
  265. // been exceeded.
  266. //
  267. if(lX > sCon.sClipRegion.sXMax)
  268. {
  269. break;
  270. }
  271. //
  272. // Get a pointer to the font data for the next character from the
  273. // string. If there is not a glyph for the next character, replace it
  274. // with the "absent" character (usually '.').
  275. //
  276. if((*pcString >= ucFirst) && (*pcString <= ucLast))
  277. {
  278. pucData = (pucGlyphs + pusOffset[*pcString - ucFirst]);
  279. }
  280. else
  281. {
  282. pucData = (pucGlyphs + pusOffset[ucAbsent - ucFirst]);
  283. }
  284. pcString++;
  285. //
  286. // See if the entire character is to the left of the clipping region.
  287. //
  288. if((lX + pucData[1]) < sCon.sClipRegion.sXMin)
  289. {
  290. //
  291. // Increment the X coordinate by the width of the character.
  292. //
  293. lX += pucData[1];
  294. //
  295. // Go to the next character in the string.
  296. //
  297. continue;
  298. }
  299. //
  300. // Loop through the bytes in the encoded data for this glyph.
  301. //
  302. for(lIdx = 2, lX0 = 0, lBit = 0, lY0 = 0; lIdx < pucData[0]; )
  303. {
  304. //
  305. // See if the bottom of the clipping region has been exceeded.
  306. //
  307. if((lY + lY0) > sCon.sClipRegion.sYMax)
  308. {
  309. //
  310. // Stop drawing this character.
  311. //
  312. break;
  313. }
  314. //
  315. // See if the font is uncompressed.
  316. //
  317. if((sCon.pFont->ucFormat & ~FONT_EX_MARKER) ==
  318. FONT_FMT_UNCOMPRESSED)
  319. {
  320. //
  321. // Count the number of off pixels from this position in the
  322. // glyph image.
  323. //
  324. for(lOff = 0; lIdx < pucData[0]; )
  325. {
  326. //
  327. // Get the number of zero pixels at this position.
  328. //
  329. lCount = NumLeadingZeros(pucData[lIdx] << lBit);
  330. //
  331. // If there were more than 8, then it is a "false" result
  332. // since it counted beyond the end of the current byte.
  333. // Therefore, simply limit it to the number of pixels
  334. // remaining in this byte.
  335. //
  336. if(lCount > 8)
  337. {
  338. lCount = 8 - lBit;
  339. }
  340. //
  341. // Increment the number of off pixels.
  342. //
  343. lOff += lCount;
  344. //
  345. // Increment the bit position within the byte.
  346. //
  347. lBit += lCount;
  348. //
  349. // See if the end of the byte has been reached.
  350. //
  351. if(lBit == 8)
  352. {
  353. //
  354. // Advance to the next byte and continue counting off
  355. // pixels.
  356. //
  357. lBit = 0;
  358. lIdx++;
  359. }
  360. else
  361. {
  362. //
  363. // Since the end of the byte was not reached, there
  364. // must be an on pixel. Therefore, stop counting off
  365. // pixels.
  366. //
  367. break;
  368. }
  369. }
  370. //
  371. // Count the number of on pixels from this position in the
  372. // glyph image.
  373. //
  374. for(lOn = 0; lIdx < pucData[0]; )
  375. {
  376. //
  377. // Get the number of one pixels at this location (by
  378. // inverting the data and counting the number of zeros).
  379. //
  380. lCount = NumLeadingZeros(~(pucData[lIdx] << lBit));
  381. //
  382. // If there were more than 8, then it is a "false" result
  383. // since it counted beyond the end of the current byte.
  384. // Therefore, simply limit it to the number of pixels
  385. // remaining in this byte.
  386. //
  387. if(lCount > 8)
  388. {
  389. lCount = 8 - lBit;
  390. }
  391. //
  392. // Increment the number of on pixels.
  393. //
  394. lOn += lCount;
  395. //
  396. // Increment the bit position within the byte.
  397. //
  398. lBit += lCount;
  399. //
  400. // See if the end of the byte has been reached.
  401. //
  402. if(lBit == 8)
  403. {
  404. //
  405. // Advance to the next byte and continue counting on
  406. // pixels.
  407. //
  408. lBit = 0;
  409. lIdx++;
  410. }
  411. else
  412. {
  413. //
  414. // Since the end of the byte was not reached, there
  415. // must be an off pixel. Therefore, stop counting on
  416. // pixels.
  417. //
  418. break;
  419. }
  420. }
  421. }
  422. //
  423. // Otherwise, the font is compressed with a pixel RLE scheme.
  424. //
  425. else
  426. {
  427. //
  428. // See if this is a byte that encodes some on and off pixels.
  429. //
  430. if(pucData[lIdx])
  431. {
  432. //
  433. // Extract the number of off pixels.
  434. //
  435. lOff = (pucData[lIdx] >> 4) & 15;
  436. //
  437. // Extract the number of on pixels.
  438. //
  439. lOn = pucData[lIdx] & 15;
  440. //
  441. // Skip past this encoded byte.
  442. //
  443. lIdx++;
  444. }
  445. //
  446. // Otherwise, see if this is a repeated on pixel byte.
  447. //
  448. else if(pucData[lIdx + 1] & 0x80)
  449. {
  450. //
  451. // There are no off pixels in this encoding.
  452. //
  453. lOff = 0;
  454. //
  455. // Extract the number of on pixels.
  456. //
  457. lOn = (pucData[lIdx + 1] & 0x7f) * 8;
  458. //
  459. // Skip past these two encoded bytes.
  460. //
  461. lIdx += 2;
  462. }
  463. //
  464. // Otherwise, this is a repeated off pixel byte.
  465. //
  466. else
  467. {
  468. //
  469. // Extract the number of off pixels.
  470. //
  471. lOff = pucData[lIdx + 1] * 8;
  472. //
  473. // There are no on pixels in this encoding.
  474. //
  475. lOn = 0;
  476. //
  477. // Skip past these two encoded bytes.
  478. //
  479. lIdx += 2;
  480. }
  481. }
  482. //
  483. // Loop while there are any off pixels.
  484. //
  485. while(lOff)
  486. {
  487. //
  488. // See if the bottom of the clipping region has been exceeded.
  489. //
  490. if((lY + lY0) > sCon.sClipRegion.sYMax)
  491. {
  492. //
  493. // Ignore the remainder of the on pixels.
  494. //
  495. break;
  496. }
  497. //
  498. // See if there is more than one on pixel that will fit onto
  499. // the current row.
  500. //
  501. if((lOff > 1) && ((lX0 + 1) < pucData[1]))
  502. {
  503. //
  504. // Determine the number of on pixels that will fit on this
  505. // row.
  506. //
  507. lCount = (((lX0 + lOff) > pucData[1]) ? pucData[1] - lX0 :
  508. lOff);
  509. //
  510. // If this row is within the clipping region, draw a
  511. // horizontal line that corresponds to the sequence of on
  512. // pixels.
  513. //
  514. if(((lY + lY0) >= sCon.sClipRegion.sYMin) && bOpaque)
  515. {
  516. sCon.ulForeground = pContext->ulBackground;
  517. GrLineDrawH(&sCon, lX + lX0, lX + lX0 + lCount - 1,
  518. lYSave + lY + lY0);
  519. }
  520. //
  521. // Decrement the count of on pixels by the number on this
  522. // row.
  523. //
  524. lOff -= lCount;
  525. //
  526. // Increment the X offset by the number of on pixels.
  527. //
  528. lX0 += lCount;
  529. }
  530. //
  531. // Otherwise, there is only a single on pixel that can be
  532. // drawn.
  533. //
  534. else
  535. {
  536. //
  537. // If this pixel is within the clipping region, then draw
  538. // it.
  539. //
  540. if(((lX + lX0) >= sCon.sClipRegion.sXMin) &&
  541. ((lX + lX0) <= sCon.sClipRegion.sXMax) &&
  542. ((lY + lY0) >= sCon.sClipRegion.sYMin) && bOpaque)
  543. {
  544. DpyPixelDraw(pContext->pDisplay, lX + lX0, lYSave + lY + lY0,
  545. pContext->ulBackground);
  546. }
  547. //
  548. // Decrement the count of on pixels.
  549. //
  550. lOff--;
  551. //
  552. // Increment the X offset.
  553. //
  554. lX0++;
  555. }
  556. //
  557. // See if the X offset has reached the right side of the
  558. // character glyph.
  559. //
  560. if(lX0 == pucData[1])
  561. {
  562. //
  563. // Increment the Y offset.
  564. //
  565. lY0++;
  566. //
  567. // Reset the X offset to the left side of the character
  568. // glyph.
  569. //
  570. lX0 = 0;
  571. }
  572. }
  573. //
  574. // Loop while there are any on pixels.
  575. //
  576. while(lOn)
  577. {
  578. //
  579. // See if the bottom of the clipping region has been exceeded.
  580. //
  581. if((lY + lY0) > sCon.sClipRegion.sYMax)
  582. {
  583. //
  584. // Ignore the remainder of the on pixels.
  585. //
  586. break;
  587. }
  588. //
  589. // See if there is more than one on pixel that will fit onto
  590. // the current row.
  591. //
  592. if((lOn > 1) && ((lX0 + 1) < pucData[1]))
  593. {
  594. //
  595. // Determine the number of on pixels that will fit on this
  596. // row.
  597. //
  598. lCount = (((lX0 + lOn) > pucData[1]) ? pucData[1] - lX0 :
  599. lOn);
  600. //
  601. // If this row is within the clipping region, draw a
  602. // horizontal line that corresponds to the sequence of on
  603. // pixels.
  604. //
  605. if((lY + lY0) >= sCon.sClipRegion.sYMin)
  606. {
  607. sCon.ulForeground = pContext->ulForeground;
  608. GrLineDrawH(&sCon, lX + lX0, lX + lX0 + lCount - 1,
  609. lYSave + lY + lY0);
  610. }
  611. //
  612. // Decrement the count of on pixels by the number on this
  613. // row.
  614. //
  615. lOn -= lCount;
  616. //
  617. // Increment the X offset by the number of on pixels.
  618. //
  619. lX0 += lCount;
  620. }
  621. //
  622. // Otherwise, there is only a single on pixel that can be
  623. // drawn.
  624. //
  625. else
  626. {
  627. //
  628. // If this pixel is within the clipping region, then draw
  629. // it.
  630. //
  631. if(((lX + lX0) >= sCon.sClipRegion.sXMin) &&
  632. ((lX + lX0) <= sCon.sClipRegion.sXMax) &&
  633. ((lY + lY0) >= sCon.sClipRegion.sYMin))
  634. DpyPixelDraw(pContext->pDisplay, lX + lX0, lYSave + lY + lY0,
  635. pContext->ulForeground);
  636. //
  637. // Decrement the count of on pixels.
  638. //
  639. lOn--;
  640. //
  641. // Increment the X offset.
  642. //
  643. lX0++;
  644. }
  645. //
  646. // See if the X offset has reached the right side of the
  647. // character glyph.
  648. //
  649. if(lX0 == pucData[1])
  650. {
  651. //
  652. // Increment the Y offset.
  653. //
  654. lY0++;
  655. //
  656. // Reset the X offset to the left side of the character
  657. // glyph.
  658. //
  659. lX0 = 0;
  660. }
  661. }
  662. }
  663. //
  664. // Increment the X coordinate by the width of the character.
  665. //
  666. lX += pucData[1];
  667. }
  668. }
  669. //*****************************************************************************
  670. //
  671. // Close the Doxygen group.
  672. //! @}
  673. //
  674. //*****************************************************************************