Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. package com.artifex.mupdf;
  2.  
  3. import android.app.*;
  4. import android.os.*;
  5. import android.content.*;
  6. import android.content.res.*;
  7. import android.graphics.*;
  8. import android.util.*;
  9. import android.view.*;
  10. import android.widget.*;
  11. import java.net.*;
  12. import java.io.*;
  13.  
  14. public class PixmapView extends SurfaceView implements SurfaceHolder.Callback
  15. {
  16.         private SurfaceHolder holder;
  17.         private MuPDFThread thread = null;
  18.         private boolean threadStarted = false;
  19.         private MuPDFCore core;
  20.  
  21.         /* Constructor */
  22.         public PixmapView(Context context, MuPDFCore core)
  23.         {
  24.                 super(context);
  25.                 System.out.println("PixmapView construct");
  26.                 this.core = core;
  27.                 holder = getHolder();
  28.                 holder.addCallback(this);
  29.                 thread = new MuPDFThread(holder, core);
  30.                 setFocusable(true); // need to get the key events
  31.         }
  32.  
  33.         /* load our native library */
  34.         static {
  35.                 System.loadLibrary("mupdf");
  36.         }
  37.  
  38.         /* Handlers for keys - so we can actually do stuff */
  39.         @Override
  40.         public boolean onKeyDown(int keyCode, KeyEvent event)
  41.         {
  42.                 if (thread.onKeyDown(keyCode, event))
  43.                         return true;
  44.                 return super.onKeyDown(keyCode, event);
  45.         }
  46.  
  47.         @Override
  48.         public boolean onKeyUp(int keyCode, KeyEvent event)
  49.         {
  50.                 if (thread.onKeyUp(keyCode, event))
  51.                         return true;
  52.                 return super.onKeyUp(keyCode, event);
  53.         }
  54.  
  55.         @Override
  56.         public boolean onTouchEvent(MotionEvent event)
  57.         {
  58.                 if (thread.onTouchEvent(event))
  59.                         return true;
  60.                 return super.onTouchEvent(event);
  61.         }
  62.  
  63.         public void changePage(int delta)
  64.         {
  65.                 thread.changePage(delta);
  66.         }
  67.  
  68.         /* Handlers for SurfaceHolder callbacks; these are called when the
  69.          * surface is created/destroyed/changed. We need to ensure that we only
  70.          * draw into the surface between the created and destroyed calls.
  71.          * Therefore, we start/stop the thread that actually runs MuPDF on
  72.          * creation/destruction. */
  73.         public void surfaceCreated(SurfaceHolder holder)
  74.         {
  75.         }
  76.  
  77.         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
  78.         {
  79.                 thread.newScreenSize(width, height);
  80.                 if (!threadStarted)
  81.                 {
  82.                         threadStarted = true;
  83.                         thread.setRunning(true);
  84.                         thread.start();
  85.                 }
  86.         }
  87.  
  88.         public void surfaceDestroyed(SurfaceHolder holder)
  89.         {
  90.                 boolean retry = true;
  91.                 System.out.println("Surface destroyed 1 this="+this);
  92.                 thread.setRunning(false);
  93.                 System.out.println("Surface destroyed 2");
  94.                 while (retry)
  95.                 {
  96.                         try
  97.                         {
  98.                                 thread.join();
  99.                                 retry = false;
  100.                         }
  101.                         catch (InterruptedException e)
  102.                         {
  103.                         }
  104.                 }
  105.                 threadStarted = false;
  106.                 System.out.println("Surface destroyed 3");
  107.         }
  108.  
  109.         class MuPDFThread extends Thread
  110.         {
  111.                 private SurfaceHolder holder;
  112.                 private boolean running = false;
  113.                 private int keycode = -1;
  114.                 private int screenWidth;
  115.                 private int screenHeight;
  116.                 private int screenGeneration;
  117.                 private Bitmap bitmap;
  118.                 private MuPDFCore core;
  119.  
  120.                 /* The following variables deal with the size of the current page;
  121.                  * specifically, its position on the screen, its raw size, its
  122.                  * current scale, and its current scaled size (in terms of whole
  123.                  * pixels).
  124.                  */
  125.                 private int pageOriginX;
  126.                 private int pageOriginY;
  127.                 private float pageScale;
  128.                 private int pageWidth;
  129.                 private int pageHeight;
  130.  
  131.                 /* The following variables deal with the multitouch handling */
  132.                 private final int NONE = 0;
  133.                 private final int DRAG = 1;
  134.                 private final int ZOOM = 2;
  135.                 private int touchMode = NONE;
  136.                 private float touchInitialSpacing;
  137.                 private float touchDragStartX;
  138.                 private float touchDragStartY;
  139.                 private float touchInitialOriginX;
  140.                 private float touchInitialOriginY;
  141.                 private float touchInitialScale;
  142.                 private PointF touchZoomMidpoint;
  143.  
  144.                 /* The following control the inner loop; other events etc cause
  145.                  * action to be set. The inner loop runs around a tight loop
  146.                  * performing the action requested of it.
  147.                  */
  148.                 private boolean wakeMe = false;
  149.                 private int action;
  150.                 private final int SLEEP = 0;
  151.                 private final int REDRAW = 1;
  152.                 private final int DIE = 2;
  153.                 private final int GOTOPAGE = 3;
  154.                 private int actionPageNum;
  155.  
  156.                 /* Members for blitting, declared here to avoid causing gcs */
  157.                 private Rect srcRect;
  158.                 private RectF dstRect;
  159.  
  160.                 public MuPDFThread(SurfaceHolder holder, MuPDFCore core)
  161.                 {
  162.                         this.holder = holder;
  163.                         this.core = core;
  164.                         touchZoomMidpoint = new PointF(0,0);
  165.                         srcRect = new Rect(0,0,0,0);
  166.                         dstRect = new RectF(0,0,0,0);
  167.                 }
  168.  
  169.                 public void setRunning(boolean running)
  170.                 {
  171.                         this.running = running;
  172.                         if (!running)
  173.                         {
  174.                                 System.out.println("killing 1");
  175.                                 synchronized(this)
  176.                                 {
  177.                                         System.out.println("killing 2");
  178.                                         action = DIE;
  179.                                         if (wakeMe)
  180.                                         {
  181.                                                 wakeMe = false;
  182.                                                 System.out.println("killing 3");
  183.                                                 this.notify();
  184.                                                 System.out.println("killing 4");
  185.                                         }
  186.                                 }
  187.                         }
  188.                 }
  189.  
  190.                 public void newScreenSize(int width, int height)
  191.                 {
  192.                         this.screenWidth = width;
  193.                         this.screenHeight = height;
  194.                         this.screenGeneration++;
  195.                 }
  196.  
  197.                 public boolean onKeyDown(int keyCode, KeyEvent msg)
  198.                 {
  199.                         keycode = keyCode;
  200.                         return false;
  201.                 }
  202.  
  203.                 public boolean onKeyUp(int keyCode, KeyEvent msg)
  204.                 {
  205.                         return false;
  206.                 }
  207.  
  208.                 public synchronized void changePage(int delta)
  209.                 {
  210.                         action = GOTOPAGE;
  211.                         if (delta == Integer.MIN_VALUE)
  212.                                 actionPageNum = 0;
  213.                         else if (delta == Integer.MAX_VALUE)
  214.                                 actionPageNum = core.numPages-1;
  215.                         else
  216.                         {
  217.                                 actionPageNum += delta;
  218.                                 if (actionPageNum < 0)
  219.                                         actionPageNum = 0;
  220.                                 if (actionPageNum > core.numPages-1)
  221.                                         actionPageNum = core.numPages-1;
  222.                         }
  223.                         if (wakeMe)
  224.                         {
  225.                                 wakeMe = false;
  226.                                 this.notify();
  227.                         }
  228.                 }
  229.  
  230.                 private float spacing(MotionEvent event)
  231.                 {
  232.                         float x = event.getX(0) - event.getX(1);
  233.                         float y = event.getY(0) - event.getY(1);
  234.                         return FloatMath.sqrt(x*x+y*y);
  235.                 }
  236.  
  237.                 private void midpoint(PointF point, MotionEvent event)
  238.                 {
  239.                         float x = event.getX(0) + event.getX(1);
  240.                         float y = event.getY(0) + event.getY(1);
  241.                         point.set(x/2, y/2);
  242.                 }
  243.  
  244.                 private synchronized void forceRedraw()
  245.                 {
  246.                         if (wakeMe)
  247.                         {
  248.                                 wakeMe = false;
  249.                                 this.notify();
  250.                         }
  251.                         action = REDRAW;
  252.                 }
  253.  
  254.                 public synchronized void setPageOriginTo(int x, int y)
  255.                 {
  256.                         /* Adjust the coordinates so that the page always covers the
  257.                          * centre of the screen. */
  258.                         if (x + pageWidth < screenWidth/2)
  259.                         {
  260.                                 x = screenWidth/2 - pageWidth;
  261.                         }
  262.                         else if (x > screenWidth/2)
  263.                         {
  264.                                 x = screenWidth/2;
  265.                         }
  266.                         if (y + pageHeight < screenHeight/2)
  267.                         {
  268.                                 y = screenHeight/2 - pageHeight;
  269.                         }
  270.                         else if (y > screenHeight/2)
  271.                         {
  272.                                 y = screenHeight/2;
  273.                         }
  274.                         if ((x != pageOriginX) || (y != pageOriginY))
  275.                         {
  276.                                 pageOriginX = x;
  277.                                 pageOriginY = y;
  278.                         }
  279.                         forceRedraw();
  280.                 }
  281.  
  282.                 public void setPageScaleTo(float scale, PointF midpoint)
  283.                 {
  284.                         float x, y;
  285.                         /* Convert midpoint (in screen coords) to page coords */
  286.                         x = (midpoint.x - pageOriginX)/pageScale;
  287.                         y = (midpoint.y - pageOriginY)/pageScale;
  288.                         /* Find new scaled page sizes */
  289.                         synchronized(this)
  290.                         {
  291.                                 pageWidth = (int)(core.pageWidth*scale+0.5);
  292.                                 if (pageWidth < screenWidth/2)
  293.                                 {
  294.                                         scale = screenWidth/2/core.pageWidth;
  295.                                         pageWidth = (int)(core.pageWidth*scale+0.5);
  296.                                 }
  297.                                 pageHeight = (int)(core.pageHeight*scale+0.5);
  298.                                 if (pageHeight < screenHeight/2)
  299.                                 {
  300.                                         scale = screenHeight/2/core.pageHeight;
  301.                                         pageWidth = (int)(core.pageWidth *scale+0.5);
  302.                                         pageHeight = (int)(core.pageHeight*scale+0.5);
  303.                                 }
  304.                                 pageScale = scale;
  305.                                 /* Now given this new scale, calculate page origins so that
  306.                                  * x and y are at midpoint */
  307.                                 float xscale = (float)pageWidth /core.pageWidth;
  308.                                 float yscale = (float)pageHeight/core.pageHeight;
  309.                                 setPageOriginTo((int)(midpoint.x - x*xscale + 0.5),
  310.                                                 (int)(midpoint.y - y*yscale + 0.5));
  311.                         }
  312.                 }
  313.  
  314.                 public void scalePageToScreen()
  315.                 {
  316.                         float scaleX, scaleY;
  317.                         scaleX = (float)screenWidth /core.pageWidth;
  318.                         scaleY = (float)screenHeight/core.pageHeight;
  319.                         synchronized(this)
  320.                         {
  321.                                 if (scaleX < scaleY)
  322.                                         pageScale = scaleX;
  323.                                 else
  324.                                         pageScale = scaleY;
  325.                                 pageWidth = (int)(core.pageWidth * pageScale + 0.5);
  326.                                 pageHeight = (int)(core.pageHeight * pageScale + 0.5);
  327.                                 pageOriginX = (screenWidth - pageWidth)/2;
  328.                                 pageOriginY = (screenHeight - pageHeight)/2;
  329.                                 forceRedraw();
  330.                         }
  331.                         System.out.println("scalePageToScreen: Raw="+
  332.                                         core.pageWidth+"x"+core.pageHeight+" scaled="+
  333.                                         pageWidth+","+pageHeight+" pageScale="+
  334.                                         pageScale);
  335.                 }
  336.  
  337.                 public boolean onTouchEvent(MotionEvent event)
  338.                 {
  339.                         int action = event.getAction();
  340.                         boolean done = false;
  341.                         switch (action & MotionEvent.ACTION_MASK)
  342.                         {
  343.                                 case MotionEvent.ACTION_DOWN:
  344.                                         touchMode = DRAG;
  345.                                         touchDragStartX = event.getX();
  346.                                         touchDragStartY = event.getY();
  347.                                         touchInitialOriginX = pageOriginX;
  348.                                         touchInitialOriginY = pageOriginY;
  349.                                         System.out.println("Starting dragging from: "+touchDragStartX+","+touchDragStartY+" ("+pageOriginX+","+pageOriginY+")");
  350.                                         done = true;
  351.                                         break;
  352.                                 case MotionEvent.ACTION_POINTER_DOWN:
  353.                                         touchInitialSpacing = spacing(event);
  354.                                         if (touchInitialSpacing > 10f)
  355.                                         {
  356.                                                 System.out.println("Started zooming: spacing="+touchInitialSpacing);
  357.                                                 touchInitialScale = pageScale;
  358.                                                 touchMode = ZOOM;
  359.                                                 done = true;
  360.                                         }
  361.                                         break;
  362.                                 case MotionEvent.ACTION_UP:
  363.                                 case MotionEvent.ACTION_POINTER_UP:
  364.                                         if (touchMode != NONE)
  365.                                         {
  366.                                                 System.out.println("Released!");
  367.                                                 touchMode = NONE;
  368.                                                 done = true;
  369.                                         }
  370.                                         break;
  371.                                 case MotionEvent.ACTION_MOVE:
  372.                                         if (touchMode == DRAG)
  373.                                         {
  374.                                                 float x = touchInitialOriginX+event.getX()-touchDragStartX;
  375.                                                 float y = touchInitialOriginY+event.getY()-touchDragStartY;
  376.                                                 System.out.println("Dragged to "+x+","+y);
  377.                                                 setPageOriginTo((int)(x+0.5),(int)(y+0.5));
  378.                                                 done = true;
  379.                                         }
  380.                                         else if (touchMode == ZOOM)
  381.                                         {
  382.                                                 float newSpacing = spacing(event);
  383.                                                 if (newSpacing > 10f)
  384.                                                 {
  385.                                                         float newScale = touchInitialScale*newSpacing/touchInitialSpacing;
  386.                                                         System.out.println("Zoomed to "+newSpacing);
  387.                                                         midpoint(touchZoomMidpoint,event);
  388.                                                         setPageScaleTo(newScale,touchZoomMidpoint);
  389.                                                         done = true;
  390.                                                 }
  391.                                         }
  392.                         }
  393.                         return done;
  394.                 }
  395.  
  396.                 public void run()
  397.                 {
  398.                         boolean redraw = false;
  399.                         int patchW = 0;
  400.                         int patchH = 0;
  401.                         int patchX = 0;
  402.                         int patchY = 0;
  403.                         int localPageW = 0;
  404.                         int localPageH = 0;
  405.                         int localScreenGeneration = screenGeneration;
  406.                         int localAction;
  407.                         int localActionPageNum = core.pageNum;
  408.  
  409.                         /* Set up our default action */
  410.                         action = GOTOPAGE;
  411.                         actionPageNum = core.pageNum;
  412.                         while (action != DIE)
  413.                         {
  414.                                 synchronized(this)
  415.                                 {
  416.                                         while (action == SLEEP)
  417.                                         {
  418.                                                 wakeMe = true;
  419.                                                 try
  420.                                                 {
  421.                                                         System.out.println("Render thread sleeping");
  422.                                                         this.wait();
  423.                                                         System.out.println("Render thread woken");
  424.                                                 }
  425.                                                 catch (java.lang.InterruptedException e)
  426.                                                 {
  427.                                                         System.out.println("Render thread exception:"+e);
  428.                                                 }
  429.                                         }
  430.  
  431.                                         /* Now we do as little as we can get away with while
  432.                                          * synchronised. In general this means copying any action
  433.                                          * or global variables into local ones so that when we
  434.                                          * unsynchronoise, other people can alter them again.
  435.                                          */
  436.                                         switch (action)
  437.                                         {
  438.                                                 case DIE:
  439.                                                         System.out.println("Woken to die!");
  440.                                                         break;
  441.                                                 case GOTOPAGE:
  442.                                                         localActionPageNum = actionPageNum;
  443.                                                         break;
  444.                                                 case REDRAW:
  445.                                                         /* Figure out what area of the page we want to
  446.                                                          * redraw (in local variables, in docspace).
  447.                                                          * We'll always draw a screensized lump, unless
  448.                                                          * that's too big. */
  449.                                                         System.out.println("page="+pageWidth+","+pageHeight+" ("+core.pageWidth+","+core.pageHeight+"@"+pageScale+") @ "+pageOriginX+","+pageOriginY);
  450.                                                         localPageW = pageWidth;
  451.                                                         localPageH = pageHeight;
  452.                                                         patchW = pageWidth;
  453.                                                         patchH = pageHeight;
  454.                                                         patchX = -pageOriginX;
  455.                                                         patchY = -pageOriginY;
  456.                                                         if (patchX < 0)
  457.                                                                 patchX = 0;
  458.                                                         if (patchW > screenWidth)
  459.                                                                 patchW = screenWidth;
  460.                                                         srcRect.left = 0;
  461.                                                         if (patchX+patchW > pageWidth)
  462.                                                         {
  463.                                                                 srcRect.left += patchX+patchW-pageWidth;
  464.                                                                 patchX = pageWidth-patchW;
  465.                                                         }
  466.                                                         if (patchY < 0)
  467.                                                                 patchY = 0;
  468.                                                         if (patchH > screenHeight)
  469.                                                                 patchH = screenHeight;
  470.                                                         srcRect.top = 0;
  471.                                                         if (patchY+patchH > pageHeight)
  472.                                                         {
  473.                                                                 srcRect.top += patchY+patchH-pageHeight;
  474.                                                                 patchY = pageHeight-patchH;
  475.                                                         }
  476.                                                         dstRect.left = pageOriginX;
  477.                                                         if (dstRect.left < 0)
  478.                                                                 dstRect.left = 0;
  479.                                                         dstRect.top = pageOriginY;
  480.                                                         if (dstRect.top < 0)
  481.                                                                 dstRect.top = 0;
  482.                                                         dstRect.right = dstRect.left + patchW;
  483.                                                         srcRect.right = srcRect.left + patchW;
  484.                                                         if (srcRect.right > screenWidth)
  485.                                                         {
  486.                                                                 dstRect.right -= srcRect.right-screenWidth;
  487.                                                                 srcRect.right = screenWidth;
  488.                                                         }
  489.                                                         if (dstRect.right > screenWidth)
  490.                                                         {
  491.                                                                 srcRect.right -= dstRect.right-screenWidth;
  492.                                                                 dstRect.right = screenWidth;
  493.                                                         }
  494.                                                         dstRect.bottom = dstRect.top + patchH;
  495.                                                         srcRect.bottom = srcRect.top + patchH;
  496.                                                         if (srcRect.bottom > screenHeight)
  497.                                                         {
  498.                                                                 dstRect.bottom -=srcRect.bottom-screenHeight;
  499.                                                                 srcRect.bottom = screenHeight;
  500.                                                         }
  501.                                                         if (dstRect.bottom > screenHeight)
  502.                                                         {
  503.                                                                 srcRect.bottom -=dstRect.bottom-screenHeight;
  504.                                                                 dstRect.bottom = screenHeight;
  505.                                                         }
  506.                                                         System.out.println("patch=["+patchX+","+patchY+","+patchW+","+patchH+"]");
  507.                                                         break;
  508.                                         }
  509.                                         localAction = action;
  510.                                         if (action != DIE)
  511.                                                 action = SLEEP;
  512.                                 }
  513.  
  514.                                 /* In the redraw case:
  515.                                  * pW, pH, pX, pY, localPageW, localPageH are now all set
  516.                                  * in local variables, and we are safe from the global vars
  517.                                  * being altered in calls from other threads. This is all
  518.                                  * the information we need to actually do our render.
  519.                                  */
  520.                                 switch (localAction)
  521.                                 {
  522.                                         case GOTOPAGE:
  523.                                                 core.gotoPage(localActionPageNum);
  524.                                                 scalePageToScreen();
  525.                                                 action = REDRAW;
  526.                                                 break;
  527.                                         case REDRAW:
  528.                                                 if ((bitmap == null) ||
  529.                                                         (bitmap.getWidth() != patchW) ||
  530.                                                         (bitmap.getHeight() != patchH))
  531.                                                 {
  532.                                                         /* make bitmap of required size */
  533.                                                         bitmap = Bitmap.createBitmap(patchW, patchH, Bitmap.Config.ARGB_8888);
  534.                                                 }
  535.                                                 System.out.println("Calling redraw native method");
  536.                                                 core.drawPage(bitmap, localPageW, localPageH, patchX, patchY, patchW, patchH);
  537.                                                 System.out.println("Called native method");
  538.                                                 {
  539.                                                         Canvas c = null;
  540.                                                         try
  541.                                                         {
  542.                                                                 c = holder.lockCanvas(null);
  543.                                                                 synchronized(holder)
  544.                                                                 {
  545.                                                                         if (localScreenGeneration == screenGeneration)
  546.                                                                         {
  547.                                                                                 doDraw(c);
  548.                                                                         }
  549.                                                                         else
  550.                                                                         {
  551.                                                                                 /* Someone has changed the screen
  552.                                                                                  * under us! Better redraw again...
  553.                                                                                  */
  554.                                                                                 action = REDRAW;
  555.                                                                         }
  556.                                                                 }
  557.                                                         }
  558.                                                         finally
  559.                                                         {
  560.                                                                 if (c != null)
  561.                                                                         holder.unlockCanvasAndPost(c);
  562.                                                         }
  563.                                                 }
  564.                                 }
  565.                         }
  566.                 }
  567.  
  568.                 protected void doDraw(Canvas canvas)
  569.                 {
  570.                         if ((canvas == null) || (bitmap == null))
  571.                                 return;
  572.                         /* Clear the screen */
  573.                         canvas.drawRGB(128,128,128);
  574.                         /* Draw our bitmap on top */
  575.                         System.out.println("Blitting bitmap from "+srcRect.left+","+srcRect.top+","+srcRect.right+","+srcRect.bottom+" to "+dstRect.left+","+dstRect.top+","+dstRect.right+","+dstRect.bottom);
  576.                         canvas.drawBitmap(bitmap, srcRect, dstRect, (Paint)null);
  577.                 }
  578.         }
  579. }
  580.