Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve text rendering performance, closes #2478, closes #2515 #2509

Merged
merged 19 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,10 @@ private void handleLaunchingIntent(final Intent intent) {
final Document doc = new Document(file);
Integer startLine = null;
if (intent.hasExtra(Document.EXTRA_FILE_LINE_NUMBER)) {
startLine = intent.getIntExtra(Document.EXTRA_FILE_LINE_NUMBER, Document.EXTRA_FILE_LINE_NUMBER_LAST);
startLine = intent.getIntExtra(Document.EXTRA_FILE_LINE_NUMBER, -1);
} else if (intentData != null) {
final String line = intentData.getQueryParameter("line");
if (line != null) {
startLine = GsTextUtils.tryParseInt(line, -1);
}
startLine = GsTextUtils.tryParseInt(line, -1);
}

// Start in a specific mode if required. Otherwise let the fragment decide
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Typeface;
Expand All @@ -33,7 +32,6 @@
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.SearchView;
import android.widget.Toast;
Expand Down Expand Up @@ -93,11 +91,11 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do
private HighlightingEditor _hlEditor;
private WebView _webView;
private MarkorWebViewClient _webViewClient;
private FrameLayout _editorHolder;
private ViewGroup _editorHolder;
private ViewGroup _textActionsBar;

private DraggableScrollbarScrollView _primaryScrollView;
private HorizontalScrollView _hsView;
private DraggableScrollbarScrollView _verticalScrollView;
private HorizontalScrollView _horizontalScrollView;
private LineNumbersTextView _lineNumbersView;
private SearchView _menuSearchViewForViewMode;
private Document _document;
Expand All @@ -108,7 +106,6 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do
private boolean _isPreviewVisible;
private boolean _nextConvertToPrintMode = false;


public DocumentEditAndViewFragment() {
super();
}
Expand Down Expand Up @@ -139,10 +136,10 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
_editorHolder = view.findViewById(R.id.document__fragment__edit__editor_holder);
_textActionsBar = view.findViewById(R.id.document__fragment__edit__text_actions_bar);
_webView = view.findViewById(R.id.document__fragment_view_webview);
_primaryScrollView = view.findViewById(R.id.document__fragment__edit__content_editor__scrolling_parent);
_verticalScrollView = view.findViewById(R.id.document__fragment__edit__content_editor__scrolling_parent);
_lineNumbersView = view.findViewById(R.id.document__fragment__edit__line_numbers_view);

_cu = new MarkorContextUtils(activity);
_editTextUndoRedoHelper = new TextViewUndoRedo();

// Using `if (_document != null)` everywhere is dangerous
// It may cause reads or writes to _silently fail_
Expand Down Expand Up @@ -203,7 +200,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
setViewModeVisibility(startInPreview, false);
}

// Configure the editor. Doing so after load helps prevent some errors
// Configure the editor
// ---------------------------------------------------------
_hlEditor.setLineSpacing(0, _appSettings.getEditorLineSpacing());
_hlEditor.setTextSize(TypedValue.COMPLEX_UNIT_SP, _appSettings.getDocumentFontSize(_document.path));
Expand All @@ -213,23 +210,19 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
_hlEditor.setGravity(_appSettings.isEditorStartEditingInCenter() ? Gravity.CENTER : Gravity.NO_GRAVITY);
_hlEditor.setHighlightingEnabled(_appSettings.getDocumentHighlightState(_document.path, _hlEditor.getText()));
_hlEditor.setAutoFormatEnabled(_appSettings.getDocumentAutoFormatEnabled(_document.path));
_hlEditor.setSaveInstanceState(false); // We will reload from disk
_hlEditor.setOverScrollMode(View.OVER_SCROLL_ALWAYS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Do not need to send contents to accessibility
_hlEditor.setImportantForAccessibility(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
}

// Various settings
setHorizontalScrollMode(isDisplayedAtMainActivity() || _appSettings.getDocumentWrapState(_document.path));
setWrapState(isDisplayedAtMainActivity() || _appSettings.getDocumentWrapState(_document.path));
updateMenuToggleStates(0);
// ---------------------------------------------------------

_hlEditor.setSaveInstanceState(false); // We will reload from disk
_document.resetChangeTracking(); // Force next reload
loadDocument();
// If not set the undo-redo helper by loadDocument, set it here
if (_editTextUndoRedoHelper == null) {
_editTextUndoRedoHelper = new TextViewUndoRedo(_hlEditor);
}
// ---------------------------------------------------------
_document.resetChangeTracking(); // Force next reload in onResume

final Runnable debounced = TextViewUtils.makeDebounced(500, () -> {
checkTextChangeState();
Expand Down Expand Up @@ -263,27 +256,30 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
@Override
protected void onFragmentFirstTimeVisible() {
final Bundle args = getArguments();

int startPos = _appSettings.getLastEditPosition(_document.path, _hlEditor.length());
if (args != null && args.containsKey(Document.EXTRA_FILE_LINE_NUMBER)) {
final int lno = args.getInt(Document.EXTRA_FILE_LINE_NUMBER);
if (lno >= 0) {
startPos = TextViewUtils.getIndexFromLineOffset(_hlEditor.getText(), lno, 0);
} else if (lno == Document.EXTRA_FILE_LINE_NUMBER_LAST) {
} else {
startPos = _hlEditor.length();
}
}

_primaryScrollView.invalidate();
// Can affect layout so run before setting scroll position
_hlEditor.recomputeHighlighting();
_hlEditor.recomputeHighlighting(); // Run before setting scroll position
TextViewUtils.setSelectionAndShow(_hlEditor, startPos);

_editorHolder.invalidate();
_editorHolder.post(() -> _hlEditor.setMinHeight(_editorHolder.getHeight()));
}

@Override
public void onResume() {
loadDocument();
_webView.onResume();
loadDocument();
if (_editTextUndoRedoHelper != null && _editTextUndoRedoHelper.getTextView() != _hlEditor) {
_editTextUndoRedoHelper.setTextView(_hlEditor);
}
super.onResume();
}

Expand Down Expand Up @@ -438,31 +434,15 @@ public boolean loadDocument() {
}

if (!_document.isContentSame(_hlEditor.getText())) {

final int[] sel = TextViewUtils.getSelection(_hlEditor);
sel[0] = Math.min(sel[0], content.length());
sel[1] = Math.min(sel[1], content.length());

if (_editTextUndoRedoHelper != null) {
_editTextUndoRedoHelper.disconnect();
_editTextUndoRedoHelper.clearHistory();
}

_hlEditor.withAutoFormatDisabled(() -> _hlEditor.setText(content));

if (_editTextUndoRedoHelper == null) {
_editTextUndoRedoHelper = new TextViewUndoRedo(_hlEditor);
} else {
_editTextUndoRedoHelper.setTextView(_hlEditor);
}

TextViewUtils.setSelectionAndShow(_hlEditor, sel);
_hlEditor.withAutoFormatDisabled(() -> _hlEditor.setTextKeepState(content));
}

checkTextChangeState();

if (_isPreviewVisible) {
updateViewModeText();
}

return true;
}
return false;
Expand Down Expand Up @@ -558,12 +538,12 @@ public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
setViewModeVisibility(true);
Toast.makeText(activity, R.string.please_wait, Toast.LENGTH_LONG).show();
_webView.postDelayed(() -> {
if (item.getItemId() == R.id.action_share_pdf) {
if (itemId == R.id.action_share_pdf) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
_cu.printOrCreatePdfFromWebview(_webView, _document, getTextString().contains("beamer\n"));
}
} else {
Bitmap bmp = _cu.getBitmapFromWebView(_webView, item.getItemId() == R.id.action_share_image);
Bitmap bmp = _cu.getBitmapFromWebView(_webView, itemId == R.id.action_share_image);
_cu.shareImage(getContext(), bmp, null);
}
}, 7000);
Expand Down Expand Up @@ -619,7 +599,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) {
case R.id.action_wrap_words: {
final boolean newState = !isWrapped();
_appSettings.setDocumentWrapState(_document.path, newState);
setHorizontalScrollMode(newState);
setWrapState(newState);
updateMenuToggleStates(0);
return true;
}
Expand Down Expand Up @@ -659,10 +639,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) {
}
case R.id.action_show_file_browser: {
// Delay because I want menu to close before we open the file browser
_hlEditor.postDelayed(() -> {
final Intent intent = new Intent(activity, MainActivity.class).putExtra(Document.EXTRA_FILE, _document.file);
GsContextUtils.instance.animateToActivity(activity, intent, false, null);
}, 250);
_hlEditor.postDelayed(() -> MainActivity.launch(activity, _document.file, false), 250);
return true;
}
case R.id.action_toggle_case:
Expand Down Expand Up @@ -765,34 +742,39 @@ private void updateMenuToggleStates(final int selectedFormatActionId) {
}

private boolean isWrapped() {
return _hsView == null || (_hlEditor.getParent() == _editorHolder);
return _horizontalScrollView == null || (_hlEditor.getParent() != _horizontalScrollView);
}

private void setHorizontalScrollMode(final boolean wrap) {
private void makeHorizontalScrollView() {
if (_horizontalScrollView != null) {
return;
}

_horizontalScrollView = new HorizontalScrollView(getContext());
_horizontalScrollView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
_horizontalScrollView.setFillViewport(true);
}

private void setWrapState(final boolean wrap) {
final Context context = getContext();
if (context != null && _hlEditor != null && isWrapped() != wrap) {
final int[] sel = TextViewUtils.getSelection(_hlEditor);
final boolean hlEnabled = _hlEditor.getHighlightingEnabled();
_hlEditor.setHighlightingEnabled(false);
final boolean hlEnabled = _hlEditor.setHighlightingEnabled(false);

_editorHolder.removeAllViews();
if (_hsView != null) {
_hsView.removeAllViews();
}
if (!wrap) {
if (_hsView == null) {
_hsView = new HorizontalScrollView(context);
_hsView.setFillViewport(true);
}
_hsView.addView(_hlEditor);
_editorHolder.addView(_hsView);
makeHorizontalScrollView();

if (wrap) {
_horizontalScrollView.removeView(_hlEditor);
_editorHolder.removeView(_horizontalScrollView);
_editorHolder.addView(_hlEditor, 1);
} else {
_editorHolder.addView(_hlEditor);
_editorHolder.removeView(_hlEditor);
_horizontalScrollView.addView(_hlEditor);
_editorHolder.addView(_horizontalScrollView, 1);
}

_hlEditor.setHighlightingEnabled(hlEnabled);
// Run after layout() of immediate parent completes
(wrap ? _editorHolder : _hsView).post(() -> TextViewUtils.setSelectionAndShow(_hlEditor, sel));
_editorHolder.post(() -> TextViewUtils.setSelectionAndShow(_hlEditor, sel));
}
}

Expand Down Expand Up @@ -890,10 +872,10 @@ public void setViewModeVisibility(boolean show, final boolean animate) {
_cu.showSoftKeyboard(activity, false, _hlEditor);
_hlEditor.clearFocus();
_hlEditor.postDelayed(() -> _cu.showSoftKeyboard(activity, false, _hlEditor), 300);
GsContextUtils.fadeInOut(_webView, _primaryScrollView, animate);
GsContextUtils.fadeInOut(_webView, _verticalScrollView, animate);
} else {
_webViewClient.setRestoreScrollY(_webView.getScrollY());
GsContextUtils.fadeInOut(_primaryScrollView, _webView, animate);
GsContextUtils.fadeInOut(_verticalScrollView, _webView, animate);
}

_nextConvertToPrintMode = false;
Expand Down
15 changes: 13 additions & 2 deletions app/src/main/java/net/gsantner/markor/activity/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package net.gsantner.markor.activity;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Intent;
import android.graphics.Color;
Expand Down Expand Up @@ -43,6 +44,7 @@
import net.gsantner.opoc.frontend.filebrowser.GsFileBrowserFragment;
import net.gsantner.opoc.frontend.filebrowser.GsFileBrowserListAdapter;
import net.gsantner.opoc.frontend.filebrowser.GsFileBrowserOptions;
import net.gsantner.opoc.util.GsContextUtils;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -200,6 +202,15 @@ protected void onNewIntent(final Intent intent) {
}
}

public static void launch(final Activity activity, final File file, final boolean finishfromActivity) {
if (activity != null && file != null) {
final Intent intent = new Intent(activity, MainActivity.class);
intent.putExtra(Document.EXTRA_FILE, file);
// intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
GsContextUtils.instance.animateToActivity(activity, intent, finishfromActivity, null);
}
}

private void optShowRate() {
try {
new com.pixplicity.generate.Rate.Builder(this)
Expand Down Expand Up @@ -455,9 +466,9 @@ public Fragment createFragment(final int pos) {
final GsFragmentBase<?, ?> frag;
final int id = tabIdFromPos(pos);
if (id == R.id.nav_quicknote) {
frag = _quicknote = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getQuickNoteFile()), Document.EXTRA_FILE_LINE_NUMBER_LAST, false);
frag = _quicknote = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getQuickNoteFile()), -1, false);
} else if (id == R.id.nav_todo) {
frag = _todo = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getTodoFile()), Document.EXTRA_FILE_LINE_NUMBER_LAST, false);
frag = _todo = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getTodoFile()), -1, false);
} else if (id == R.id.nav_more) {
frag = _more = MoreFragment.newInstance();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@

import androidx.annotation.Nullable;

import net.gsantner.markor.model.Document;

public class OpenEditorQuickNoteActivity extends OpenEditorActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openEditorForFile(_appSettings.getQuickNoteFile(), Document.EXTRA_FILE_LINE_NUMBER_LAST);
openEditorForFile(_appSettings.getQuickNoteFile(), -1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@

import androidx.annotation.Nullable;

import net.gsantner.markor.model.Document;

public class OpenEditorTodoActivity extends OpenEditorActivity {

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
openEditorForFile(_appSettings.getTodoFile(), Document.EXTRA_FILE_LINE_NUMBER_LAST);
openEditorForFile(_appSettings.getTodoFile(), -1);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
Expand Down Expand Up @@ -887,7 +888,10 @@ public static void moveLineSelectionBy1(final HighlightingEditor hlEditor, final
final int[][] offsets = TextViewUtils.getLineOffsetFromIndex(text, sel);

hlEditor.withAutoFormatDisabled(() -> {
final String newPair = String.format("%s\n%s", isUp ? lines : altLine, isUp ? altLine : lines);
final SpannableStringBuilder newPair = new SpannableStringBuilder()
.append(isUp ? lines : altLine)
.append("\n")
.append(isUp ? altLine : lines);
text.replace(Math.min(lineSel[0], altSel[0]), Math.max(lineSel[1], altSel[1]), newPair);
});

Expand Down
Loading