Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/tesseract/java/com/google/scrollview/ScrollView.java @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/tesseract/java/com/google/scrollview/ScrollView.java Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,402 @@ +// Copyright 2007 Google Inc. All Rights Reserved. +// +// 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 com.google.scrollview; + +import com.google.scrollview.events.SVEvent; +import com.google.scrollview.ui.SVImageHandler; +import com.google.scrollview.ui.SVWindow; +import org.piccolo2d.nodes.PImage; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.regex.Pattern; + +/** + * The ScrollView class is the main class which gets started from the command + * line. It sets up LUA and handles the network processing. + * @author wanke@google.com + */ +public class ScrollView { + + /** The port our server listens at. */ + public static int SERVER_PORT = 8461; + + /** + * All SVWindow objects share the same connection stream. The socket is needed + * to detect when the connection got closed, in/out are used to send and + * receive messages. + */ + private static Socket socket; + private static PrintStream out; + public static BufferedReader in; + public static float polylineXCoords[]; // The coords being received. + public static float polylineYCoords[]; // The coords being received. + public static int polylineSize; // The size of the coords arrays. + public static int polylineScanned; // The size read so far. + private static ArrayList<SVWindow> windows; // The id to SVWindow map. + private static Pattern intPattern; // For checking integer arguments. + private static Pattern floatPattern; // For checking float arguments. + + /** Keeps track of the number of messages received. */ + static int nrInputLines = 0; + + /** Prints all received messages to the console if true. */ + static boolean debugViewNetworkTraffic = false; + + /** Add a new message to the outgoing queue. */ + public static void addMessage(SVEvent e) { + if (debugViewNetworkTraffic) { + System.out.println("(S->c) " + e.toString()); + } + String str = e.toString(); + // Send the whole thing as UTF8. + try { + byte [] utf8 = str.getBytes("UTF8"); + out.write(utf8, 0, utf8.length); + } catch (java.io.UnsupportedEncodingException ex) { + System.out.println("Oops... can't encode to UTF8... Exiting"); + System.exit(0); + } + out.println(); + // Flush the output and check for errors. + boolean error = out.checkError(); + if (error) { + System.out.println("Connection error. Quitting ScrollView Server..."); + System.exit(0); + } + } + + /** Read one message from client (assuming there are any). */ + public static String receiveMessage() throws IOException { + return in.readLine(); + } + + /** + * The main program loop. Basically loops through receiving messages and + * processing them and then sending messages (if there are any). + */ + private static void IOLoop() { + String inputLine; + + try { + while (!socket.isClosed() && !socket.isInputShutdown() && + !socket.isOutputShutdown() && + socket.isConnected() && socket.isBound()) { + inputLine = receiveMessage(); + if (inputLine == null) { + // End of stream reached. + break; + } + nrInputLines++; + if (debugViewNetworkTraffic) { + System.out.println("(c->S," + nrInputLines + ")" + inputLine); + } + + if (polylineSize > polylineScanned) { + // We are processing a polyline. + // Read pairs of coordinates separated by commas. + boolean first = true; + for (String coordStr : inputLine.split(",")) { + int coord = Integer.parseInt(coordStr); + if (first) { + polylineXCoords[polylineScanned] = coord; + } else { + polylineYCoords[polylineScanned++] = coord; + } + first = !first; + } + assert first; + } else { + // Process this normally. + processInput(inputLine); + } + } + } + // Some connection error + catch (IOException e) { + System.out.println("Connection error. Quitting ScrollView Server..."); + } + System.exit(0); + } + + // Parse a comma-separated list of arguments into ArrayLists of the + // possible types. Each type is stored in order, but the order + // distinction between types is lost. + // Note that the format is highly constrained to what the client used + // to send to LUA: + // Quoted string -> String. + // true or false -> Boolean. + // %f format number -> Float (no %e allowed) + // Sequence of digits -> Integer + // Nothing else allowed. + private static void parseArguments(String argList, + ArrayList<Integer> intList, + ArrayList<Float> floatList, + ArrayList<String> stringList, + ArrayList<Boolean> boolList) { + // str is only non-null if an argument starts with a single or double + // quote. str is set back to null on completion of the string with a + // matching quote. If the string contains a comma then str will stay + // non-null across multiple argStr values until a matching closing quote. + // Backslash escaped quotes do not count as terminating the string. + String str = null; + for (String argStr : argList.split(",")) { + if (str != null) { + // Last string was incomplete. Append argStr to it and restore comma. + // Execute str += "," + argStr in Java. + int length = str.length() + 1 + argStr.length(); + StringBuilder appended = new StringBuilder(length); + appended.append(str); + appended.append(","); + appended.append(argStr); + str = appended.toString(); + } else if (argStr.length() == 0) { + continue; + } else { + char quote = argStr.charAt(0); + // If it begins with a quote then it is a string, but may not + // end this time if it contained a comma. + if (quote == '\'' || quote == '"') { + str = argStr; + } + } + if (str != null) { + // It began with a quote. Check that it still does. + assert str.charAt(0) == '\'' || str.charAt(0) == '"'; + int len = str.length(); + if (len > 1 && str.charAt(len - 1) == str.charAt(0)) { + // We have an ending quote of the right type. Now check that + // it is not escaped. Must have an even number of slashes before. + int slash = len - 1; + while (slash > 0 && str.charAt(slash - 1) == '\\') + --slash; + if ((len - 1 - slash) % 2 == 0) { + // It is now complete. Chop off the quotes and save. + // TODO(rays) remove the first backslash of each pair. + stringList.add(str.substring(1, len - 1)); + str = null; + } + } + // If str is not null here, then we have a string with a comma in it. + // Append, and the next argument at the next iteration, but check + // that str is null after the loop terminates in case it was an + // unterminated string. + } else if (floatPattern.matcher(argStr).matches()) { + // It is a float. + floatList.add(Float.parseFloat(argStr)); + } else if (argStr.equals("true")) { + boolList.add(true); + } else if (argStr.equals("false")) { + boolList.add(false); + } else if (intPattern.matcher(argStr).matches()) { + // Only contains digits so must be an int. + intList.add(Integer.parseInt(argStr)); + } + // else ignore all incompatible arguments for forward compatibility. + } + // All strings must have been terminated. + assert str == null; + } + + /** Executes the LUA command parsed as parameter. */ + private static void processInput(String inputLine) { + if (inputLine == null) { + return; + } + // Execute a function encoded as a LUA statement! Yuk! + if (inputLine.charAt(0) == 'w') { + // This is a method call on a window. Parse it. + String noWLine = inputLine.substring(1); + String[] idStrs = noWLine.split("[ :]", 2); + int windowID = Integer.parseInt(idStrs[0]); + // Find the parentheses. + int start = inputLine.indexOf('('); + int end = inputLine.lastIndexOf(')'); + // Parse the args. + ArrayList<Integer> intList = new ArrayList<Integer>(4); + ArrayList<Float> floatList = new ArrayList<Float>(2); + ArrayList<String> stringList = new ArrayList<String>(4); + ArrayList<Boolean> boolList = new ArrayList<Boolean>(3); + parseArguments(inputLine.substring(start + 1, end), + intList, floatList, stringList, boolList); + int colon = inputLine.indexOf(':'); + if (colon > 1 && colon < start) { + // This is a regular function call. Look for the name and call it. + String func = inputLine.substring(colon + 1, start); + if (func.equals("drawLine")) { + windows.get(windowID).drawLine(intList.get(0), intList.get(1), + intList.get(2), intList.get(3)); + } else if (func.equals("createPolyline")) { + windows.get(windowID).createPolyline(intList.get(0)); + } else if (func.equals("drawPolyline")) { + windows.get(windowID).drawPolyline(); + } else if (func.equals("drawRectangle")) { + windows.get(windowID).drawRectangle(intList.get(0), intList.get(1), + intList.get(2), intList.get(3)); + } else if (func.equals("setVisible")) { + windows.get(windowID).setVisible(boolList.get(0)); + } else if (func.equals("setAlwaysOnTop")) { + windows.get(windowID).setAlwaysOnTop(boolList.get(0)); + } else if (func.equals("addMessage")) { + windows.get(windowID).addMessage(stringList.get(0)); + } else if (func.equals("addMessageBox")) { + windows.get(windowID).addMessageBox(); + } else if (func.equals("clear")) { + windows.get(windowID).clear(); + } else if (func.equals("setStrokeWidth")) { + windows.get(windowID).setStrokeWidth(floatList.get(0)); + } else if (func.equals("drawEllipse")) { + windows.get(windowID).drawEllipse(intList.get(0), intList.get(1), + intList.get(2), intList.get(3)); + } else if (func.equals("pen")) { + if (intList.size() == 4) { + windows.get(windowID).pen(intList.get(0), intList.get(1), + intList.get(2), intList.get(3)); + } else { + windows.get(windowID).pen(intList.get(0), intList.get(1), + intList.get(2)); + } + } else if (func.equals("brush")) { + if (intList.size() == 4) { + windows.get(windowID).brush(intList.get(0), intList.get(1), + intList.get(2), intList.get(3)); + } else { + windows.get(windowID).brush(intList.get(0), intList.get(1), + intList.get(2)); + } + } else if (func.equals("textAttributes")) { + windows.get(windowID).textAttributes(stringList.get(0), + intList.get(0), + boolList.get(0), + boolList.get(1), + boolList.get(2)); + } else if (func.equals("drawText")) { + windows.get(windowID).drawText(intList.get(0), intList.get(1), + stringList.get(0)); + } else if (func.equals("addMenuBarItem")) { + if (boolList.size() > 0) { + windows.get(windowID).addMenuBarItem(stringList.get(0), + stringList.get(1), + intList.get(0), + boolList.get(0)); + } else if (intList.size() > 0) { + windows.get(windowID).addMenuBarItem(stringList.get(0), + stringList.get(1), + intList.get(0)); + } else { + windows.get(windowID).addMenuBarItem(stringList.get(0), + stringList.get(1)); + } + } else if (func.equals("addPopupMenuItem")) { + if (stringList.size() == 4) { + windows.get(windowID).addPopupMenuItem(stringList.get(0), + stringList.get(1), + intList.get(0), + stringList.get(2), + stringList.get(3)); + } else { + windows.get(windowID).addPopupMenuItem(stringList.get(0), + stringList.get(1)); + } + } else if (func.equals("update")) { + windows.get(windowID).update(); + } else if (func.equals("showInputDialog")) { + windows.get(windowID).showInputDialog(stringList.get(0)); + } else if (func.equals("showYesNoDialog")) { + windows.get(windowID).showYesNoDialog(stringList.get(0)); + } else if (func.equals("zoomRectangle")) { + windows.get(windowID).zoomRectangle(intList.get(0), intList.get(1), + intList.get(2), intList.get(3)); + } else if (func.equals("readImage")) { + PImage image = SVImageHandler.readImage(intList.get(2), in); + windows.get(windowID).drawImage(image, intList.get(0), intList.get(1)); + } else if (func.equals("drawImage")) { + PImage image = new PImage(stringList.get(0)); + windows.get(windowID).drawImage(image, intList.get(0), intList.get(1)); + } else if (func.equals("destroy")) { + windows.get(windowID).destroy(); + } + // else for forward compatibility purposes, silently ignore any + // unrecognized function call. + } else { + // No colon. Check for create window. + if (idStrs[1].startsWith("= luajava.newInstance")) { + while (windows.size() <= windowID) { + windows.add(null); + } + windows.set(windowID, new SVWindow(stringList.get(1), + intList.get(0), intList.get(1), + intList.get(2), intList.get(3), + intList.get(4), intList.get(5), + intList.get(6))); + } + // else for forward compatibility purposes, silently ignore any + // unrecognized function call. + } + } else if (inputLine.startsWith("svmain")) { + // Startup or end. Startup is a lua bind, which is now a no-op. + if (inputLine.startsWith("svmain:exit")) { + exit(); + } + // else for forward compatibility purposes, silently ignore any + // unrecognized function call. + } + // else for forward compatibility purposes, silently ignore any + // unrecognized function call. + } + + /** Called from the client to make the server exit. */ + public static void exit() { + System.exit(0); + } + + /** + * The main function. Sets up LUA and the server connection and then calls the + * IOLoop. + */ + public static void main(String[] args) { + if (args.length > 0) { + SERVER_PORT = Integer.parseInt(args[0]); + } + windows = new ArrayList<SVWindow>(100); + intPattern = Pattern.compile("[0-9-][0-9]*"); + floatPattern = Pattern.compile("[0-9-][0-9]*\\.[0-9]*"); + + // Open a socket to listen on. + try (ServerSocket serverSocket = new ServerSocket(SERVER_PORT)) { + System.out.println("Socket started on port " + SERVER_PORT); + + // Wait (blocking) for an incoming connection + socket = serverSocket.accept(); + System.out.println("Client connected"); + + // Setup the streams + out = new PrintStream(socket.getOutputStream(), true, "UTF-8"); + in = + new BufferedReader(new InputStreamReader(socket.getInputStream(), + "UTF8")); + } catch (IOException e) { + // Something went wrong and we were unable to set up a connection. This is + // pretty much a fatal error. + // Note: The server does not get restarted automatically if this happens. + e.printStackTrace(); + System.exit(1); + } + + // Enter the main program loop. + IOLoop(); + } +}
