PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/textarea/ChunkCache.java

#
Java | 835 lines | 496 code | 95 blank | 244 comment | 105 complexity | 2fb4034ebbc025b803732bb8c414d994 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * ChunkCache.java - Intermediate layer between token lists from a TokenMarker
  3. * and what you see on screen
  4. * :tabSize=8:indentSize=8:noTabs=false:
  5. * :folding=explicit:collapseFolds=1:
  6. *
  7. * Copyright (C) 2001, 2005 Slava Pestov
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. */
  23. package org.gjt.sp.jedit.textarea;
  24. //{{{ Imports
  25. import java.util.*;
  26. import javax.swing.text.TabExpander;
  27. import org.gjt.sp.jedit.buffer.JEditBuffer;
  28. import org.gjt.sp.jedit.Debug;
  29. import org.gjt.sp.jedit.syntax.*;
  30. import org.gjt.sp.util.Log;
  31. //}}}
  32. /**
  33. * Manages low-level text display tasks - the visible lines in the TextArea.
  34. * The ChunkCache contains an array of LineInfo object.
  35. * Each LineInfo object is associated to one screen line of the TextArea and
  36. * contains informations about this line.
  37. * The array is resized when the TextArea geometry changes
  38. *
  39. * @author Slava Pestov
  40. * @version $Id: ChunkCache.java 18774 2010-10-14 20:26:12Z shlomy $
  41. */
  42. class ChunkCache
  43. {
  44. //{{{ ChunkCache constructor
  45. ChunkCache(TextArea textArea)
  46. {
  47. this.textArea = textArea;
  48. out = new ArrayList<Chunk>();
  49. tokenHandler = new DisplayTokenHandler();
  50. } //}}}
  51. //{{{ getMaxHorizontalScrollWidth() method
  52. /**
  53. * Returns the max line width of the textarea.
  54. * It will check all lines the first invalid line.
  55. *
  56. * @return the max line width
  57. */
  58. int getMaxHorizontalScrollWidth()
  59. {
  60. int max = 0;
  61. for(int i = 0; i < firstInvalidLine; i++)
  62. {
  63. LineInfo info = lineInfo[i];
  64. if(info.width > max)
  65. max = info.width;
  66. }
  67. return max;
  68. } //}}}
  69. //{{{ getScreenLineOfOffset() method
  70. /**
  71. * @param line physical line number of document
  72. * @param offset number of characters from the left of the line.
  73. * @return returns the screen line number where the line and offset are.
  74. * It returns -1 if this position is not currently visible
  75. */
  76. int getScreenLineOfOffset(int line, int offset)
  77. {
  78. if(lineInfo.length == 0)
  79. return -1;
  80. if(line < textArea.getFirstPhysicalLine())
  81. return -1;
  82. if(line == textArea.getFirstPhysicalLine()
  83. && offset < getLineInfo(0).offset)
  84. return -1;
  85. if(line > textArea.getLastPhysicalLine())
  86. return -1;
  87. if(line == lastScreenLineP)
  88. {
  89. LineInfo last = getLineInfo(lastScreenLine);
  90. if(offset >= last.offset
  91. && offset < last.offset + last.length)
  92. {
  93. return lastScreenLine;
  94. }
  95. }
  96. int screenLine = -1;
  97. // Find the screen line containing this offset
  98. for(int i = 0; i < textArea.getVisibleLines(); i++)
  99. {
  100. LineInfo info = getLineInfo(i);
  101. if(info.physicalLine > line)
  102. {
  103. // line is invisible?
  104. return i - 1;
  105. //return -1;
  106. }
  107. if(info.physicalLine == line)
  108. {
  109. if(offset >= info.offset
  110. && offset < info.offset + info.length)
  111. {
  112. screenLine = i;
  113. break;
  114. }
  115. }
  116. }
  117. if(screenLine == -1)
  118. return -1;
  119. lastScreenLineP = line;
  120. lastScreenLine = screenLine;
  121. return screenLine;
  122. } //}}}
  123. //{{{ recalculateVisibleLines() method
  124. /**
  125. * Recalculate visible lines.
  126. * This is called when the TextArea geometry is changed or when the font is changed.
  127. */
  128. void recalculateVisibleLines()
  129. {
  130. LineInfo[] newLineInfo = new LineInfo[textArea.getVisibleLines()];
  131. int start;
  132. if(lineInfo == null)
  133. start = 0;
  134. else
  135. {
  136. start = Math.min(lineInfo.length,newLineInfo.length);
  137. System.arraycopy(lineInfo,0,newLineInfo,0,start);
  138. }
  139. for(int i = start; i < newLineInfo.length; i++)
  140. newLineInfo[i] = new LineInfo();
  141. lineInfo = newLineInfo;
  142. lastScreenLine = lastScreenLineP = -1;
  143. } //}}}
  144. //{{{ setBuffer() method
  145. void setBuffer(JEditBuffer buffer)
  146. {
  147. this.buffer = buffer;
  148. lastScreenLine = lastScreenLineP = -1;
  149. } //}}}
  150. //{{{ scrollDown() method
  151. void scrollDown(int amount)
  152. {
  153. int visibleLines = textArea.getVisibleLines();
  154. System.arraycopy(lineInfo,amount,lineInfo,0,visibleLines - amount);
  155. for(int i = visibleLines - amount; i < visibleLines; i++)
  156. {
  157. lineInfo[i] = new LineInfo();
  158. }
  159. firstInvalidLine -= amount;
  160. if(firstInvalidLine < 0)
  161. firstInvalidLine = 0;
  162. if(Debug.CHUNK_CACHE_DEBUG)
  163. {
  164. System.err.println("f > t.f: only " + amount
  165. + " need updates");
  166. }
  167. lastScreenLine = lastScreenLineP = -1;
  168. } //}}}
  169. //{{{ scrollUp() method
  170. void scrollUp(int amount)
  171. {
  172. System.arraycopy(lineInfo,0,lineInfo,amount,
  173. textArea.getVisibleLines() - amount);
  174. for(int i = 0; i < amount; i++)
  175. {
  176. lineInfo[i] = new LineInfo();
  177. }
  178. // don't try this at home
  179. int oldFirstInvalidLine = firstInvalidLine;
  180. firstInvalidLine = 0;
  181. updateChunksUpTo(amount);
  182. firstInvalidLine = oldFirstInvalidLine + amount;
  183. if(firstInvalidLine > textArea.getVisibleLines())
  184. firstInvalidLine = textArea.getVisibleLines();
  185. if(Debug.CHUNK_CACHE_DEBUG)
  186. {
  187. Log.log(Log.DEBUG,this,"f > t.f: only " + amount
  188. + " need updates");
  189. }
  190. lastScreenLine = lastScreenLineP = -1;
  191. } //}}}
  192. //{{{ invalidateAll() method
  193. void invalidateAll()
  194. {
  195. firstInvalidLine = 0;
  196. lastScreenLine = lastScreenLineP = -1;
  197. } //}}}
  198. //{{{ invalidateChunksFromPhys() method
  199. void invalidateChunksFromPhys(int physicalLine)
  200. {
  201. for(int i = 0; i < firstInvalidLine; i++)
  202. {
  203. LineInfo info = lineInfo[i];
  204. if(info.physicalLine == -1 || info.physicalLine >= physicalLine)
  205. {
  206. firstInvalidLine = i;
  207. if(i <= lastScreenLine)
  208. lastScreenLine = lastScreenLineP = -1;
  209. break;
  210. }
  211. }
  212. } //}}}
  213. //{{{ getLineInfo() method
  214. /**
  215. * Returns the line informations for a given screen line
  216. * @param screenLine the screen line
  217. * @return the LineInfo for the screenLine
  218. */
  219. LineInfo getLineInfo(int screenLine)
  220. {
  221. updateChunksUpTo(screenLine);
  222. return lineInfo[screenLine];
  223. } //}}}
  224. //{{{ getLineSubregionCount() method
  225. /**
  226. * Returns the number of subregions of a physical line
  227. * @param physicalLine a physical line
  228. * @return the number of subregions of this physical line
  229. */
  230. int getLineSubregionCount(int physicalLine)
  231. {
  232. if(!textArea.softWrap)
  233. return 1;
  234. out.clear();
  235. lineToChunkList(physicalLine,out);
  236. int size = out.size();
  237. if(size == 0)
  238. return 1;
  239. else
  240. return size;
  241. } //}}}
  242. //{{{ getSubregionOfOffset() method
  243. /**
  244. * Returns the subregion containing the specified offset. A subregion
  245. * is a subset of a physical line. Each screen line corresponds to one
  246. * subregion. Unlike the {@link #getScreenLineOfOffset(int, int)} method,
  247. * this method works with non-visible lines too.
  248. *
  249. * @param offset the offset
  250. * @param lineInfos a lineInfos array. Usualy the array is the result of
  251. * {@link #getLineInfosForPhysicalLine(int)} call
  252. *
  253. * @return the subregion of the offset, or -1 if the offset was not in one of the given lineInfos
  254. */
  255. static int getSubregionOfOffset(int offset, LineInfo[] lineInfos)
  256. {
  257. for(int i = 0; i < lineInfos.length; i++)
  258. {
  259. LineInfo info = lineInfos[i];
  260. if(offset >= info.offset && offset < info.offset + info.length)
  261. return i;
  262. }
  263. return -1;
  264. } //}}}
  265. //{{{ xToSubregionOffset() method
  266. /**
  267. * Converts an x co-ordinate within a subregion into an offset from the
  268. * start of that subregion.
  269. * @param physicalLine The physical line number
  270. * @param subregion The subregion; if -1, then this is the last
  271. * subregion.
  272. * @param x The x co-ordinate
  273. * @param round Round up to next character if x is past the middle of a
  274. * character?
  275. * @return the offset from the start of the subregion
  276. */
  277. int xToSubregionOffset(int physicalLine, int subregion, int x,
  278. boolean round)
  279. {
  280. LineInfo[] infos = getLineInfosForPhysicalLine(physicalLine);
  281. if(subregion == -1)
  282. subregion += infos.length;
  283. return xToSubregionOffset(infos[subregion],x,round);
  284. } //}}}
  285. //{{{ xToSubregionOffset() method
  286. /**
  287. * Converts an x co-ordinate within a subregion into an offset from the
  288. * start of that subregion.
  289. * @param info The line info object
  290. * @param x The x co-ordinate
  291. * @param round Round up to next character if x is past the middle of a
  292. * character?
  293. * @return the offset from the start of the subregion
  294. */
  295. static int xToSubregionOffset(LineInfo info, int x,
  296. boolean round)
  297. {
  298. int offset = Chunk.xToOffset(info.chunks,x,round);
  299. if(offset == -1 || offset == info.offset + info.length)
  300. offset = info.offset + info.length - 1;
  301. return offset;
  302. } //}}}
  303. //{{{ subregionOffsetToX() method
  304. /**
  305. * Converts an offset within a subregion into an x co-ordinate.
  306. * @param physicalLine The physical line
  307. * @param offset The offset
  308. * @return the x co-ordinate of the offset within a subregion
  309. */
  310. int subregionOffsetToX(int physicalLine, int offset)
  311. {
  312. LineInfo[] infos = getLineInfosForPhysicalLine(physicalLine);
  313. LineInfo info = infos[getSubregionOfOffset(offset,infos)];
  314. return subregionOffsetToX(info,offset);
  315. } //}}}
  316. //{{{ subregionOffsetToX() method
  317. /**
  318. * Converts an offset within a subregion into an x co-ordinate.
  319. * @param info The line info object
  320. * @param offset The offset
  321. * @return the x co-ordinate of the offset within a subregion
  322. */
  323. static int subregionOffsetToX(LineInfo info, int offset)
  324. {
  325. return (int)Chunk.offsetToX(info.chunks,offset);
  326. } //}}}
  327. //{{{ getSubregionStartOffset() method
  328. /**
  329. * Returns the start offset of the specified subregion of the specified
  330. * physical line.
  331. * @param line The physical line number
  332. * @param offset An offset
  333. * @return the start offset of the subregion of the line
  334. */
  335. int getSubregionStartOffset(int line, int offset)
  336. {
  337. LineInfo[] lineInfos = getLineInfosForPhysicalLine(line);
  338. LineInfo info = lineInfos[getSubregionOfOffset(offset,lineInfos)];
  339. return textArea.getLineStartOffset(info.physicalLine)
  340. + info.offset;
  341. } //}}}
  342. //{{{ getSubregionEndOffset() method
  343. /**
  344. * Returns the end offset of the specified subregion of the specified
  345. * physical line.
  346. * @param line The physical line number
  347. * @param offset An offset
  348. * @return the end offset of the subregion of the line
  349. */
  350. int getSubregionEndOffset(int line, int offset)
  351. {
  352. LineInfo[] lineInfos = getLineInfosForPhysicalLine(line);
  353. LineInfo info = lineInfos[getSubregionOfOffset(offset,lineInfos)];
  354. return textArea.getLineStartOffset(info.physicalLine)
  355. + info.offset + info.length;
  356. } //}}}
  357. //{{{ getBelowPosition() method
  358. /**
  359. * @param physicalLine The physical line number
  360. * @param offset The offset
  361. * @param x The location
  362. * @param ignoreWrap If true, behave as if soft wrap is off even if it
  363. * is on
  364. */
  365. int getBelowPosition(int physicalLine, int offset, int x,
  366. boolean ignoreWrap)
  367. {
  368. LineInfo[] lineInfos = getLineInfosForPhysicalLine(physicalLine);
  369. int subregion = getSubregionOfOffset(offset,lineInfos);
  370. if(subregion != lineInfos.length - 1 && !ignoreWrap)
  371. {
  372. return textArea.getLineStartOffset(physicalLine)
  373. + xToSubregionOffset(lineInfos[subregion + 1],
  374. x,true);
  375. }
  376. else
  377. {
  378. int nextLine = textArea.displayManager
  379. .getNextVisibleLine(physicalLine);
  380. if(nextLine == -1)
  381. return -1;
  382. else
  383. {
  384. return textArea.getLineStartOffset(nextLine)
  385. + xToSubregionOffset(nextLine,0,
  386. x,true);
  387. }
  388. }
  389. } //}}}
  390. //{{{ getAbovePosition() method
  391. /**
  392. * @param physicalLine The physical line number
  393. * @param offset The offset
  394. * @param x The location
  395. * @param ignoreWrap If true, behave as if soft wrap is off even if it
  396. * is on
  397. */
  398. int getAbovePosition(int physicalLine, int offset, int x,
  399. boolean ignoreWrap)
  400. {
  401. LineInfo[] lineInfos = getLineInfosForPhysicalLine(physicalLine);
  402. int subregion = getSubregionOfOffset(offset,lineInfos);
  403. if(subregion != 0 && !ignoreWrap)
  404. {
  405. return textArea.getLineStartOffset(physicalLine)
  406. + xToSubregionOffset(lineInfos[subregion - 1],
  407. x,true);
  408. }
  409. else
  410. {
  411. int prevLine = textArea.displayManager
  412. .getPrevVisibleLine(physicalLine);
  413. if(prevLine == -1)
  414. return -1;
  415. else
  416. {
  417. return textArea.getLineStartOffset(prevLine)
  418. + xToSubregionOffset(prevLine,-1,
  419. x,true);
  420. }
  421. }
  422. } //}}}
  423. //{{{ needFullRepaint() method
  424. /**
  425. * The needFullRepaint variable becomes true when the number of screen
  426. * lines in a physical line changes.
  427. * @return true if the TextArea needs full repaint
  428. */
  429. boolean needFullRepaint()
  430. {
  431. boolean retVal = needFullRepaint;
  432. needFullRepaint = false;
  433. return retVal;
  434. } //}}}
  435. //{{{ getLineInfosForPhysicalLine() method
  436. LineInfo[] getLineInfosForPhysicalLine(int physicalLine)
  437. {
  438. out.clear();
  439. if(!buffer.isLoading())
  440. lineToChunkList(physicalLine,out);
  441. if(out.isEmpty())
  442. out.add(null);
  443. List<LineInfo> returnValue = new ArrayList<LineInfo>(out.size());
  444. getLineInfosForPhysicalLine(physicalLine,returnValue);
  445. return returnValue.toArray(new LineInfo[out.size()]);
  446. } //}}}
  447. //{{{ Private members
  448. //{{{ Instance variables
  449. private final TextArea textArea;
  450. private JEditBuffer buffer;
  451. /**
  452. * The lineInfo array. There is LineInfo for each line that is visible in the textArea.
  453. * it can be resized by {@link #recalculateVisibleLines()}.
  454. * The content is valid from 0 to {@link #firstInvalidLine}
  455. */
  456. private LineInfo[] lineInfo;
  457. private final List<Chunk> out;
  458. /** The first invalid line. All lines before this one are valid. */
  459. private int firstInvalidLine;
  460. private int lastScreenLineP;
  461. private int lastScreenLine;
  462. private boolean needFullRepaint;
  463. private final DisplayTokenHandler tokenHandler;
  464. //}}}
  465. //{{{ getLineInfosForPhysicalLine() method
  466. private void getLineInfosForPhysicalLine(int physicalLine, List<LineInfo> list)
  467. {
  468. for(int i = 0; i < out.size(); i++)
  469. {
  470. Chunk chunks = out.get(i);
  471. LineInfo info = new LineInfo();
  472. info.physicalLine = physicalLine;
  473. if(i == 0)
  474. {
  475. info.firstSubregion = true;
  476. info.offset = 0;
  477. }
  478. else
  479. info.offset = chunks.offset;
  480. if(i == out.size() - 1)
  481. {
  482. info.lastSubregion = true;
  483. info.length = textArea.getLineLength(physicalLine)
  484. - info.offset + 1;
  485. }
  486. else
  487. {
  488. info.length = out.get(i + 1).offset
  489. - info.offset;
  490. }
  491. info.chunks = chunks;
  492. list.add(info);
  493. }
  494. } //}}}
  495. //{{{ getFirstScreenLine() method
  496. /**
  497. * Find a valid line closest to the last screen line.
  498. */
  499. private int getFirstScreenLine()
  500. {
  501. for(int i = firstInvalidLine - 1; i >= 0; i--)
  502. {
  503. if(lineInfo[i].lastSubregion)
  504. return i + 1;
  505. }
  506. return 0;
  507. } //}}}
  508. //{{{ getUpdateStartLine() method
  509. /**
  510. * Return a physical line number.
  511. */
  512. private int getUpdateStartLine(int firstScreenLine)
  513. {
  514. // for the first line displayed, take its physical line to be
  515. // the text area's first physical line
  516. if(firstScreenLine == 0)
  517. {
  518. return textArea.getFirstPhysicalLine();
  519. }
  520. // otherwise, determine the next visible line
  521. else
  522. {
  523. int prevPhysLine = lineInfo[
  524. firstScreenLine - 1]
  525. .physicalLine;
  526. // if -1, the empty space at the end of the text area
  527. // when the buffer has less lines than are visible
  528. if(prevPhysLine == -1)
  529. return -1;
  530. else
  531. {
  532. return textArea.displayManager
  533. .getNextVisibleLine(prevPhysLine);
  534. }
  535. }
  536. } //}}}
  537. //{{{ updateChunksUpTo() method
  538. private void updateChunksUpTo(int lastScreenLine)
  539. {
  540. // this method is a nightmare
  541. if(lastScreenLine >= lineInfo.length)
  542. throw new ArrayIndexOutOfBoundsException(lastScreenLine);
  543. // if one line's chunks are invalid, remaining lines are also
  544. // invalid
  545. if(lastScreenLine < firstInvalidLine)
  546. return;
  547. int firstScreenLine = getFirstScreenLine();
  548. int physicalLine = getUpdateStartLine(firstScreenLine);
  549. if(Debug.CHUNK_CACHE_DEBUG)
  550. {
  551. Log.log(Log.DEBUG,this,"Updating chunks from " + firstScreenLine
  552. + " to " + lastScreenLine);
  553. }
  554. // Note that we rely on the fact that when a physical line is
  555. // invalidated, all screen lines/subregions of that line are
  556. // invalidated as well. See below comment for code that tries
  557. // to uphold this assumption.
  558. out.clear();
  559. int offset;
  560. int length;
  561. for(int i = firstScreenLine; i <= lastScreenLine; i++)
  562. {
  563. LineInfo info = lineInfo[i];
  564. Chunk chunks;
  565. // get another line of chunks
  566. if(out.isEmpty())
  567. {
  568. // unless this is the first time, increment
  569. // the line number
  570. if(physicalLine != -1 && i != firstScreenLine)
  571. {
  572. physicalLine = textArea.displayManager
  573. .getNextVisibleLine(physicalLine);
  574. }
  575. // empty space
  576. if(physicalLine == -1)
  577. {
  578. info.chunks = null;
  579. info.physicalLine = -1;
  580. // fix the bug where the horiz.
  581. // scroll bar was not updated
  582. // after creating a new file.
  583. info.width = 0;
  584. continue;
  585. }
  586. // chunk the line.
  587. lineToChunkList(physicalLine,out);
  588. info.firstSubregion = true;
  589. // if the line has no text, out.size() == 0
  590. if(out.isEmpty())
  591. {
  592. if(i == 0)
  593. {
  594. if(textArea.displayManager.firstLine.skew > 0)
  595. {
  596. Log.log(Log.ERROR,this,"BUG: skew=" + textArea.displayManager.firstLine.skew + ",out.size()=" + out.size());
  597. textArea.displayManager.firstLine.skew = 0;
  598. needFullRepaint = true;
  599. lastScreenLine = lineInfo.length - 1;
  600. }
  601. }
  602. chunks = null;
  603. offset = 0;
  604. length = 1;
  605. }
  606. // otherwise, the number of subregions
  607. else
  608. {
  609. if(i == 0)
  610. {
  611. int skew = textArea.displayManager.firstLine.skew;
  612. if(skew >= out.size())
  613. {
  614. // The skew cannot be greater than the chunk count of the line
  615. // we need at least one chunk per subregion in a line
  616. Log.log(Log.ERROR,this,"BUG: skew=" + skew + ",out.size()=" + out.size());
  617. needFullRepaint = true;
  618. lastScreenLine = lineInfo.length - 1;
  619. }
  620. else if(skew > 0)
  621. {
  622. info.firstSubregion = false;
  623. for(int j = 0; j < skew; j++)
  624. out.remove(0);
  625. }
  626. }
  627. chunks = out.remove(0);
  628. offset = chunks.offset;
  629. if (!out.isEmpty())
  630. length = out.get(0).offset - offset;
  631. else
  632. length = textArea.getLineLength(physicalLine) - offset + 1;
  633. }
  634. }
  635. else
  636. {
  637. info.firstSubregion = false;
  638. chunks = out.remove(0);
  639. offset = chunks.offset;
  640. if (!out.isEmpty())
  641. length = out.get(0).offset - offset;
  642. else
  643. length = textArea.getLineLength(physicalLine) - offset + 1;
  644. }
  645. boolean lastSubregion = out.isEmpty();
  646. if(i == lastScreenLine
  647. && lastScreenLine != lineInfo.length - 1)
  648. {
  649. /* if the user changes the syntax token at the
  650. * end of a line, need to do a full repaint. */
  651. if(tokenHandler.getLineContext() !=
  652. info.lineContext)
  653. {
  654. lastScreenLine++;
  655. needFullRepaint = true;
  656. }
  657. /* If this line has become longer or shorter
  658. * (in which case the new physical line number
  659. * is different from the cached one) we need to:
  660. * - continue updating past the last line
  661. * - advise the text area to repaint
  662. * On the other hand, if the line wraps beyond
  663. * lastScreenLine, we need to keep updating the
  664. * chunk list to ensure proper alignment of
  665. * invalidation flags (see start of method) */
  666. else if(info.physicalLine != physicalLine
  667. || info.lastSubregion != lastSubregion)
  668. {
  669. lastScreenLine++;
  670. needFullRepaint = true;
  671. }
  672. /* We only cache entire physical lines at once;
  673. * don't want to split a physical line into
  674. * screen lines and only have some valid. */
  675. else if (!out.isEmpty())
  676. lastScreenLine++;
  677. }
  678. info.physicalLine = physicalLine;
  679. info.lastSubregion = lastSubregion;
  680. info.offset = offset;
  681. info.length = length;
  682. info.chunks = chunks;
  683. info.lineContext = tokenHandler.getLineContext();
  684. }
  685. firstInvalidLine = Math.max(lastScreenLine + 1,firstInvalidLine);
  686. } //}}}
  687. //{{{ lineToChunkList() method
  688. private void lineToChunkList(int physicalLine, List<Chunk> out)
  689. {
  690. TextAreaPainter painter = textArea.getPainter();
  691. TabExpander expander= textArea.getTabExpander();
  692. tokenHandler.init(painter.getStyles(),
  693. painter.getFontRenderContext(),
  694. expander,out,
  695. textArea.softWrap
  696. ? textArea.wrapMargin : 0.0f, buffer.getLineStartOffset(physicalLine));
  697. buffer.markTokens(physicalLine,tokenHandler);
  698. } //}}}
  699. //}}}
  700. //{{{ LineInfo class
  701. /**
  702. * The informations on a line. (for fast access)
  703. * When using softwrap, a line is divided in n
  704. * subregions.
  705. */
  706. static class LineInfo
  707. {
  708. /**
  709. * The physical line.
  710. */
  711. int physicalLine;
  712. /**
  713. * The offset where begins the line.
  714. */
  715. int offset;
  716. /**
  717. * The line length.
  718. */
  719. int length;
  720. /**
  721. * true if it is the first subregion of a line.
  722. */
  723. boolean firstSubregion;
  724. /**
  725. * True if it is the last subregion of a line.
  726. */
  727. boolean lastSubregion;
  728. Chunk chunks;
  729. /** The line width. */
  730. int width;
  731. TokenMarker.LineContext lineContext;
  732. @Override
  733. public String toString()
  734. {
  735. return "LineInfo[" + physicalLine + ',' + offset + ','
  736. + length + ',' + firstSubregion + ',' +
  737. lastSubregion + "]";
  738. }
  739. } //}}}
  740. }