Comments (27)
不过我个人不建议逐个字符绘制,这在显示字符较多的时候效率较低,尤其是在较旧的设备上。而且这样就和TextWarrior的绘制方式几乎无异。我十分关注编辑器在显示方面的性能,因此我才使用了按Span绘制的方案。
我目前使用的R7s,编辑器绘制我的CodeEditor.java的部分区域会超过16ms线,字体较小时部分区域甚至达16ms的2.5倍左右。这还是去除了绘制过程中额外用于计算最大滑动X位置的measureText()过程的数据(现在已经改在插入/删除时计算需要刷新的行)。之后measure这一步还将移动位置。
对比如图所示:
可以发现,字体大小相同的情况下,在TextWarrior中拥有更少的高亮区域,但是时间仍然较高,以至掉帧。
from sora-editor.
对的。向系统频繁提交measure/draw是很费时的。这一般与代码行数无关(至少在我这里是),而与单行的长度有关。一般来说,横向滑动到的位置越大,字体越小(可见行越多),绘制越困难。
在绘制单行超长文本的时候,会更慢,因此我引入了二分来减少损耗,但是效果也不是很明显。
我曾经试过把100KB的文本挤在同一行,即使二分也无法拯救掉帧。而且在滑动到的位置较小的时候,由于前部有高亮,后面全部被识别为注释,使用二分反而比有序绘制慢了。但是从总体上来说这种情况必须使用二分。
我的二分不在所有条件下使用的原因是,在绘制小文本的时候二分反而会导致性能轻微下降。
from sora-editor.
现在已经加入了对空白符号的绘制支持(仅限tab和空格),支持设定单行文本区域的哪些部位需要绘制它们(Leading, Inner, Railing)。
此外,对于光标闪烁的支持(可选,可定闪烁间隔)也已添加。
from sora-editor.
对了,Gutter是什么位置😂
gutter就是行号栏,取名参照ace、codemirror的
from sora-editor.
应该就是measureText的问题了,上次我测试了复制出char[],基本没有消耗。而二分之后drawText的任务很小,所以应该是measure问题。
我测试发现发现缓存确实十分有效,尤其是在多次测量中能体现巨大的优势。
我刚刚开了#15,准备使用缓存。
from sora-editor.
这个主意确实很好,我会考虑如何在将来编辑器中融合这一特点和现今的方式。
from sora-editor.
主要是面向接口编程,抽出主题色彩接口,实现用户自定义配色,自定义配色方案是代码编辑器的标配了,通过该接口可以轻松导入主流代码编辑器或者IDE的主题
from sora-editor.
对了,Gutter是什么位置😂
from sora-editor.
再请教一下,Secondary的Foreground/Background分别是什么位置呢?
还有当前代码块的划线的颜色是取消了吗?还有选择小手柄的颜色在哪里
from sora-editor.
还有NonPrintable的显示很不错,我之后也将会加入它
from sora-editor.
还有NonPrintable的显示很不错,我之后也将会加入它
不可打印字符目前我只实现了制表符和空格,utf8的bom头、回车换行符还没完全弄好
from sora-editor.
Secondary的Foreground/Background,是次要的前景色和背景色,可用在工具栏等其他地方,和编辑器关系不大了
from sora-editor.
再请教一下,Secondary的Foreground/Background分别是什么位置呢?
还有当前代码块的划线的颜色是取消了吗?还有选择小手柄的颜色在哪里
当前代码块的那个矩形颜色,我看好多IDE都没用有,效果也不太好,有那个代码块的折叠线足够了。光标手柄颜色是有的,我用的是光标的颜色,没单独提供定义,最近我又改进了配色方案,更改了主题配色接口。
from sora-editor.
/*
* Copyright 2020 Rosemoe
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.rosemoe.editor.interfaces;
import androidx.annotation.ColorInt;
/**
* Theme scheme for all UI
*
* @author gzu-liyujiang ([email protected])
* @since 2020/08/12 17:20
*/
public interface ThemeScheme {
/**
* 元数据的颜色,如注解
*/
@ColorInt
int getMetadataColor();
/**
* 函数名/方法名的颜色
*/
@ColorInt
int getFunctionColor();
/**
* 标识名的颜色,如变量声明标识、标签属性标识
*/
@ColorInt
int getIdentifierColor();
/**
* 变量名的颜色
*/
@ColorInt
int getVariableColor();
/**
* 字符/字符串的颜色
*/
@ColorInt
int getStringColor();
/**
* 数字的颜色,包括整数、小数、二进制数、十六进制数等
*/
@ColorInt
int getNumberColor();
/**
* 特殊操作符的颜色,如 @$;,
*/
@ColorInt
int getOperatorColor();
/**
* 块注释或文档注释的颜色
*/
@ColorInt
int getBlockCommentColor();
/**
* 单行注释的颜色
*/
@ColorInt
int getLineCommentColor();
/**
* 关键字/保留字的颜色
*/
@ColorInt
int getKeywordColor();
/**
* 主要的背景色
*/
@ColorInt
int getPrimaryBackgroundColor();
/**
* 主要的前景色
*/
@ColorInt
int getPrimaryForegroundColor();
/**
* 次要的背景色
*/
@ColorInt
int getSecondaryBackgroundColor();
/**
* 次要的前景色
*/
@ColorInt
int getSecondaryForegroundColor();
/**
* 行号栏的背景色
*/
@ColorInt
int getGutterBackgroundColor();
/**
* 行号栏的前景色
*/
@ColorInt
int getGutterForegroundColor();
/**
* 行号栏的分割线色
*/
@ColorInt
int getGutterDividerColor();
/**
* 滚动条块普通状态的颜色
*/
@ColorInt
int getScrollBarThumbNormalColor();
/**
* 滚动条块按下状态的颜色
*/
@ColorInt
int getScrollBarThumbPressedColor();
/**
* 选取文字的背景色
*/
@ColorInt
int getTextSelectedColor();
/**
* 搜索匹配文字的颜色
*/
@ColorInt
int getTextMatchedColor();
/**
* 光标所在行的颜色
*/
@ColorInt
int getCurrentLineColor();
/**
* 光标及其选择手柄的颜色
*/
@ColorInt
int getCaretColor();
/**
* 不可打印字符的颜色,如空格、制表符、换行符
*/
@ColorInt
int getNonPrintableCharColor();
/**
* 折叠线/代码块指示线的颜色
*/
@ColorInt
int getFoldLineColor();
/**
* 下滑线/波浪线的颜色
*/
@ColorInt
int getUnderlineColor();
/**
* 着重强调的颜色,如 TODO、FIXME
*/
@ColorInt
int getEmphasizeColor();
/**
* 是否暗色系/夜间模式
*/
boolean isDark();
}
from sora-editor.
/*
* Copyright 2020 Rosemoe
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.rosemoe.editor.theme;
import io.github.rosemoe.editor.interfaces.ThemeScheme;
/**
* `Eclipse` style, color picked from Eclipse IDE for Java Developers Version 2019-12 (4.14.0)
*
* @author gzu-liyujiang ([email protected])
* @since 2020/08/15 01:49
*/
public class Eclipse implements ThemeScheme {
@Override
public int getMetadataColor() {
return 0xff646464;
}
@Override
public int getFunctionColor() {
return 0xff000000;
}
@Override
public int getIdentifierColor() {
return 0xff000000;
}
@Override
public int getVariableColor() {
return 0xffb8633e;
}
@Override
public int getStringColor() {
return 0xff2a00ff;
}
@Override
public int getNumberColor() {
return 0xff000000;
}
@Override
public int getOperatorColor() {
return 0xff3a0000;
}
@Override
public int getBlockCommentColor() {
return 0xff3f5fbf;
}
@Override
public int getLineCommentColor() {
return 0xff3f7f5f;
}
@Override
public int getKeywordColor() {
return 0xff7f0074;
}
@Override
public int getPrimaryBackgroundColor() {
return 0xffffffff;
}
@Override
public int getPrimaryForegroundColor() {
return 0xff000000;
}
@Override
public int getSecondaryBackgroundColor() {
return 0xffe1e6f6;
}
@Override
public int getSecondaryForegroundColor() {
return 0xff282828;
}
@Override
public int getGutterBackgroundColor() {
return 0xffffffff;
}
@Override
public int getGutterForegroundColor() {
return 0xff787878;
}
@Override
public int getGutterDividerColor() {
return 0xfff8f8f8;
}
@Override
public int getScrollBarThumbNormalColor() {
return 0xffd8d8d8;
}
@Override
public int getScrollBarThumbPressedColor() {
return 0xffc800a4;
}
@Override
public int getTextSelectedColor() {
return 0xff3399ff;
}
@Override
public int getTextMatchedColor() {
return 0xffd4d4d4;
}
@Override
public int getCurrentLineColor() {
return 0xffe8f2fe;
}
@Override
public int getCaretColor() {
return 0xff03ebeb;
}
@Override
public int getNonPrintableCharColor() {
return 0xffe8e8e8;
}
@Override
public int getFoldLineColor() {
return 0xffd8d8d8;
}
@Override
public int getUnderlineColor() {
return 0xffff0000;
}
@Override
public int getEmphasizeColor() {
return 0xff7f9fc9;
}
@Override
public boolean isDark() {
return false;
}
}
from sora-editor.
还有NonPrintable的显示很不错,我之后也将会加入它
private static final char CHAR_BOM_HEADER = '\ufeff';
private static final char CHAR_SPACE = 0x20;
private static final char CHAR_TAB = '\t';
private static final char CHAR_NEWLINE = '\n';
private static final String GRAPH_BOM_HEADER = "¤";
private static final String GRAPH_SPACE = "·";
private static final String GRAPH_TAB = "»";
private static final String GRAPH_HARD_WRAP = "↵";
private static final String GRAPH_SOFT_WRAP_START = "↩";
private static final String GRAPH_SOFT_WRAP_END = "↪";
/**
* 绘制高亮文本
*/
private void drawTextWithSpans(...) {
char[] chars = getCharsAtLine(line);
LogUtils.print("Draw line " + line + ": region[" + regionStart + ", " + regionEnd +
"] charLength=" + chars.length);
...
if (nonPrintableCharVisible) {
drawNonPrintableChar(canvas, width, baseline, GRAPH_HARD_WRAP);
}
}
/**
* 绘制已进行过跨度处理的字符
*/
private void drawSpanChars(Canvas canvas, char[] src, int index, int count, float offX, float offY) {
for (int i = index, n = index + count; i < n; i++) {
switch (src[i]) {
case 0xd83c:
case 0xd83d:
emojiCharPrefix = src[i];
break;
case CHAR_BOM_HEADER:
if (nonPrintableCharVisible) {
drawNonPrintableChar(canvas, offX, offY, GRAPH_BOM_HEADER);
offX += paint.measureText(GRAPH_BOM_HEADER);
}
break;
case CHAR_TAB:
if (nonPrintableCharVisible) {
drawNonPrintableChar(canvas, offX, offY, GRAPH_TAB);
float tabWidth = paint.measureText(GRAPH_TAB);
tabWidth = Math.max(tabWidth, tabSize * spaceWidthPx);
offX += tabWidth;
} else {
canvas.drawText(new char[]{CHAR_SPACE}, 0, 1, offX, offY, paint);
offX += tabSize * spaceWidthPx;
}
break;
case CHAR_SPACE:
if (nonPrintableCharVisible) {
drawNonPrintableChar(canvas, offX, offY, GRAPH_SPACE);
} else {
canvas.drawText(new char[]{CHAR_SPACE}, 0, 1, offX, offY, paint);
}
offX += spaceWidthPx;
break;
default:
char[] ch;
if (emojiCharPrefix != 0) {
ch = new char[]{emojiCharPrefix, src[i]};
emojiCharPrefix = 0;
} else {
ch = new char[]{src[i]};
}
canvas.drawText(ch, 0, ch.length, offX, offY, paint);
offX += paint.measureText(ch, 0, ch.length);
break;
}
}
}
/**
* 绘制不可打印字符
*/
private void drawNonPrintableChar(Canvas canvas, float x, float y, String graph) {
int originColor = paint.getColor();
float originTextSize = paint.getTextSize();
if (graph.equals(GRAPH_BOM_HEADER)) {
paint.setColor(0xffff0000);
} else {
paint.setColor(themeScheme.getNonPrintableCharColor());
}
paint.setTextSize(originTextSize * 0.9f);
canvas.drawText(graph, x, y, paint);
paint.setColor(originColor);
paint.setTextSize(originTextSize);
}
from sora-editor.
好的,谢谢了。
from sora-editor.
@Rosemoe 老铁你在性能方面优化的还不错,我倒是忽略性能方面了,其实不可打印字符的实现方式我就是参考了TextWarrior
,不逐个字符绘制的话,那么不可打印字符(尤其是制表符和空格)应该可以当做Span
的一部分。
from sora-editor.
其实一般的编辑器都是绘制每行前部的不可见字符,和行末回车,中间的其实可以不必绘制😃
from sora-editor.
Android Studio这个强,支持设置首尾及内部空白符是否显示。
@Rosemoe
顺便说一下:有必要绘制光标闪烁:
/**
* @author gzu-liyujiang ([email protected])
* @since 2020/8/14 22:07
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
public final class CaretBlink implements Runnable {
private final TextEditor editor;
public CaretBlink(TextEditor editor) {
this.editor = editor;
}
@Override
public void run() {
editor.reverseCaretVisibility();
editor.postDelayed(this, 500);
}
}
/**
* Initialize variants
*/
private void init() {
...
caretBlink = new CaretBlink(this);
startCaretBlink();
...
}
public void startCaretBlink() {
stopCaretBlink();
postDelayed(caretBlink, 500);
}
public void stopCaretBlink() {
caretVisible = true;
removeCallbacks(caretBlink);
invalidate();
}
void reverseCaretVisibility() {
this.caretVisible = !caretVisible;
invalidate();
}
/**
* 绘制光标
*/
private void drawCaret(Canvas canvas, int line, int column) {
if (isRowVisible(line) && caretVisible) {
int offsetX = getGutterOffsetX();
char[] chars = getCharsAtLine(line);
float width = measureText(chars, 0, column);
rect.top = getRowTop(line) - getCurrentScrollY();
rect.bottom = getRowBottom(line) - getCurrentScrollY();
rect.left = offsetX + width;
rect.right = offsetX + width + caretWidthPx;
drawRect(canvas, themeScheme.getCaretColor(), rect);
}
}
from sora-editor.
确实如此。目前主要在做wordwrap,这个可能会在之后加。
光标移动后,可见性可能应该保留一段时间。
另外这个工作可以在onAttachedToWindow和onDetachedFromWindow对光标闪烁进行启动/停止,以便减少性能损耗。
from sora-editor.
确实如此。目前主要在做wordwrap,这个可能会在之后加。
光标移动后,可见性可能应该保留一段时间。
另外这个工作可以在onAttachedToWindow和onDetachedFromWindow对光标闪烁进行启动/停止,以便减少性能损耗。
感谢你的提点,还有正在滚动的时候也应该暂停光标闪烁。兄弟加油,感谢你的无私奉献!
from sora-editor.
逐字绘制的确损耗了太多性能啊!绘制9779行的codemirror.js
的内容,最高花费35毫秒。按行绘制则最高只要18毫秒,损耗了一半的时间。
from sora-editor.
然而,我发现MT的编辑器的效率比我的更高,这说明有其他优化方案,我还会继续改进。
from sora-editor.
吐了,不小心close了
from sora-editor.
粘贴120KB的单行文本,我现在十分不明白为什么MT的测量可以秒出,而我的测量却用了大约10s,这实在让我迷惑。
而且MT绘制也不是很卡顿,大约50ms,而我的却会几乎无法绘制完成
而且似乎也没有使用二分,滑动位置为0的时候绘制时间与正常文本无异
简直就像常数很小的O(N)
我初步怀疑它具有字体缓存或其它优化。
可能是直接使用measureText太慢。系统可能会每次都重新测量字体,无论画笔属性是否改变。
(自言自语,可以忽略它)
from sora-editor.
粘贴120KB的单行文本,我现在十分不明白为什么MT的测量可以秒出,而我的测量却用了大约10s,这实在让我迷惑。
而且MT绘制也不是很卡顿,大约50ms,而我的却会几乎无法绘制完成
而且似乎也没有使用二分,滑动位置为0的时候绘制时间与正常文本无异
简直就像常数很小的O(N)
我初步怀疑它具有字体缓存或其它优化。
可能是直接使用measureText太慢。系统可能会每次都重新测量字体,无论画笔属性是否改变。
(自言自语,可以忽略它)
能检测出是哪一步耗时最多吗?找出来才好对症下药。若是measureText
耗时最多,那可以在初始化画笔及字体改变的时候测量好一个字所占的宽度存起来,不用在onDraw
里处处测量。
from sora-editor.
Related Issues (20)
- Feature: built-in git and GitHub support HOT 2
- @drawable/magnifier _background Not Found HOT 3
- Enhance support for RTL languages
- Sticky scroll window should be hidden on select all HOT 2
- Invalid cursor placement after "Format code" action
- Add Support for Mouse Motions
- Add Support for Lens mode
- Add support for markdown viewer HOT 1
- Better control of the fast scrolling handle
- The code or text does not appear when using EditorColorScheme HOT 2
- Question: delete,empty line HOT 3
- Issue:Failed resolution of: Lres/Hex;
- Wrong cursor drawing
- Thread-safety issues with tree sitter implementation
- Add Proper Documentation HOT 2
- Better cursor position after a ctrl+x (maybe also ctrl+c) HOT 1
- [Question]: How to Use in project by Source Code HOT 2
- How to use styles
- Desktop Support ? HOT 4
- [Refactor]: Rename `AnalyzeManager` to `AnalysisManager` HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sora-editor.