javauis/lcdui_akn/javalcdui/javasrc/javax/microedition/lcdui/Buffer.java
branchRCL_3
changeset 26 2455ef1f5bbc
parent 14 04becd199f91
equal deleted inserted replaced
25:ae942d28ec0e 26:2455ef1f5bbc
       
     1 /*
       
     2 * Copyright (c) 1999 - 2004 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 package javax.microedition.lcdui;
       
    19 
       
    20 import com.nokia.mj.impl.rt.legacy.NativeError;
       
    21 
       
    22 /**
       
    23  * Buffer for LCDUI/LCDGR commands.
       
    24  *
       
    25  * Commands placed in buffer consist of a header followed by
       
    26  * optional data. The header is always a 32bit integer in
       
    27  * one of the following two forms.
       
    28  *
       
    29  * An activation header has the ACTIVATE marker (the top bit) set
       
    30  * and contains a component handle in the lower 30 bits.
       
    31  *
       
    32  * A command header has the top four bits clear, and the remaining
       
    33  * 28 bits are divided as follows:
       
    34  *
       
    35  * bits 0-15 contain the command size including the header as the
       
    36  * number of integers (or words) in the buffer occupied by the
       
    37  * commadn.
       
    38  *
       
    39  * bits 16-27 contain an unsigned integer opcode.
       
    40  *
       
    41  */
       
    42 final class Buffer
       
    43 {
       
    44     private static final int BUFFER_SIZE = 1024;    // 4KB buffer
       
    45     private static final int CHAR_BUFFER_SIZE = 128;
       
    46 
       
    47     public static final int NOP      = 0;
       
    48     public static final int ACTIVATE = (1<<31);
       
    49     public static final int OP_MASK  = 0x0FFF;
       
    50 
       
    51     /**
       
    52      * JavaUnhand<> mangled pointer to CMIDBuffer
       
    53      */
       
    54     private int         iHandle;
       
    55 
       
    56     /**
       
    57      * Java side buffer and write pointer.
       
    58      */
       
    59     private int[]       iBuffer;
       
    60     private int         iCount;
       
    61 
       
    62     /**
       
    63      * Tracks current buffer processor to minimize ACTIVATE commands.
       
    64      */
       
    65     private int         iCurrent;
       
    66     // index of activation size
       
    67     private int         iStart;     // index of activation size
       
    68     private char[] iCharBuffer;
       
    69 
       
    70 
       
    71     /**
       
    72      *
       
    73      */
       
    74     Buffer(Toolkit aToolkit)
       
    75     {
       
    76         iBuffer    = new int[BUFFER_SIZE];
       
    77         iCharBuffer = new char[CHAR_BUFFER_SIZE];
       
    78         iCount     = 0;
       
    79         iCurrent   = -1;
       
    80         iStart     = 0;
       
    81         iHandle    = NativeError.check(_open(aToolkit.getEventServerHandle()));
       
    82     }
       
    83 
       
    84     /**
       
    85      * Sync any pending commands and then shutdown buffer processing
       
    86      */
       
    87     synchronized void close()
       
    88     {
       
    89         if (iHandle <= 0)
       
    90         {
       
    91             return;
       
    92         }
       
    93         sync();
       
    94         _close(iHandle);
       
    95         iHandle = 0;
       
    96     }
       
    97 
       
    98     /**
       
    99      *
       
   100      */
       
   101     int getHandle()
       
   102     {
       
   103         if (iHandle <= 0)
       
   104         {
       
   105             throw new RuntimeException("Buffer closed");
       
   106         }
       
   107         return iHandle;
       
   108     }
       
   109 
       
   110 
       
   111     /**
       
   112      * writes a command with no parameters into the buffer.
       
   113      */
       
   114     final void write(int aHandle, int aCommand)
       
   115     {
       
   116         if (iHandle <= 0)
       
   117         {
       
   118             throw new RuntimeException("Buffer closed");
       
   119         }
       
   120 
       
   121         if (aHandle != iCurrent)
       
   122         {
       
   123             deactivate();       // remove existing target
       
   124             activate(aHandle);  // set new target - this may cause a flush.
       
   125         }
       
   126 
       
   127         // size = 1;
       
   128         final int opc  = (aCommand << 16) | 1;
       
   129         ensureSpace(1);
       
   130 
       
   131         iBuffer[iCount++] = opc;
       
   132     }
       
   133 
       
   134     /**
       
   135      *
       
   136      */
       
   137     final void write(int aHandle, int aCommand, int aArg)
       
   138     {
       
   139         if (iHandle <= 0)
       
   140         {
       
   141             throw new RuntimeException("Buffer closed");
       
   142         }
       
   143 
       
   144         if (aHandle != iCurrent)
       
   145         {
       
   146             deactivate();       // remove existing target
       
   147             activate(aHandle);  // set new target - this may cause a flush.
       
   148         }
       
   149 
       
   150         // size = 2;
       
   151         final int opc  = (aCommand << 16) | 2;
       
   152         ensureSpace(2);
       
   153 
       
   154         iBuffer[iCount++] = opc;
       
   155         iBuffer[iCount++] = aArg;
       
   156     }
       
   157 
       
   158     /**
       
   159      *
       
   160      */
       
   161     final void write(int aHandle, int aCommand, int aArg1, int aArg2)
       
   162     {
       
   163         if (iHandle <= 0)
       
   164         {
       
   165             throw new RuntimeException("Buffer closed");
       
   166         }
       
   167 
       
   168         if (aHandle != iCurrent)
       
   169         {
       
   170             deactivate();       // remove existing target
       
   171             activate(aHandle);  // set new target - this may cause a flush.
       
   172         }
       
   173 
       
   174         // size = 3;
       
   175         final int opc  = (aCommand << 16) | 3;
       
   176         ensureSpace(3);
       
   177 
       
   178         final int[] buffer = iBuffer;
       
   179         int count = iCount;
       
   180         buffer[count++] = opc;
       
   181         buffer[count++] = aArg1;
       
   182         buffer[count++] = aArg2;
       
   183         iCount = count;
       
   184     }
       
   185 
       
   186     /**
       
   187      *
       
   188      */
       
   189     final void write(int aHandle, int aCommand, int aArg1, int aArg2, int aArg3)
       
   190     {
       
   191         if (iHandle <= 0)
       
   192         {
       
   193             throw new RuntimeException("Buffer closed");
       
   194         }
       
   195 
       
   196         if (aHandle != iCurrent)
       
   197         {
       
   198             deactivate();       // remove existing target
       
   199             activate(aHandle);  // set new target - this may cause a flush.
       
   200         }
       
   201 
       
   202         // size = 4;
       
   203         final int opc  = (aCommand << 16) | 4;
       
   204         ensureSpace(4);
       
   205 
       
   206         final int[] buffer = iBuffer;
       
   207         int count = iCount;
       
   208         buffer[count++] = opc;
       
   209         buffer[count++] = aArg1;
       
   210         buffer[count++] = aArg2;
       
   211         buffer[count++] = aArg3;
       
   212         iCount = count;
       
   213     }
       
   214 
       
   215     /**
       
   216      *
       
   217      */
       
   218     final void write(int aHandle, int aCommand, int aArg1, int aArg2,
       
   219                      int aArg3, int aArg4)
       
   220     {
       
   221         if (iHandle <= 0)
       
   222         {
       
   223             throw new RuntimeException("Buffer closed");
       
   224         }
       
   225 
       
   226         if (aHandle != iCurrent)
       
   227         {
       
   228             deactivate();       // remove existing target
       
   229             activate(aHandle);  // set new target - this may cause a flush.
       
   230         }
       
   231 
       
   232         // size = 5;
       
   233         final int opc  = (aCommand << 16) | 5;
       
   234         ensureSpace(5);
       
   235 
       
   236         final int[] buffer = iBuffer;
       
   237         int count = iCount;
       
   238         buffer[count++] = opc;
       
   239         buffer[count++] = aArg1;
       
   240         buffer[count++] = aArg2;
       
   241         buffer[count++] = aArg3;
       
   242         buffer[count++] = aArg4;
       
   243         iCount = count;
       
   244     }
       
   245 
       
   246     /**
       
   247      *
       
   248      */
       
   249     final void write(int aHandle, int aCommand, int aArg1, int aArg2,
       
   250                      int aArg3, int aArg4, int aArg5)
       
   251     {
       
   252         if (iHandle <= 0)
       
   253         {
       
   254             throw new RuntimeException("Buffer closed");
       
   255         }
       
   256 
       
   257         if (aHandle != iCurrent)
       
   258         {
       
   259             deactivate();       // remove existing target
       
   260             activate(aHandle);  // set new target - this may cause a flush.
       
   261         }
       
   262 
       
   263         // size = 6;
       
   264         final int opc  = (aCommand << 16) | 6;
       
   265         ensureSpace(6);
       
   266 
       
   267         final int[] buffer = iBuffer;
       
   268         int count = iCount;
       
   269         buffer[count++] = opc;
       
   270         buffer[count++] = aArg1;
       
   271         buffer[count++] = aArg2;
       
   272         buffer[count++] = aArg3;
       
   273         buffer[count++] = aArg4;
       
   274         buffer[count++] = aArg5;
       
   275         iCount = count;
       
   276     }
       
   277 
       
   278     /**
       
   279      *
       
   280      */
       
   281     final void write(int aHandle, int aCommand, int aArg1, int aArg2,
       
   282                      int aArg3, int aArg4, int aArg5, int aArg6)
       
   283     {
       
   284         if (iHandle <= 0)
       
   285         {
       
   286             throw new RuntimeException("Buffer closed");
       
   287         }
       
   288 
       
   289         if (aHandle != iCurrent)
       
   290         {
       
   291             deactivate();       // remove existing target
       
   292             activate(aHandle);  // set new target - this may cause a flush.
       
   293         }
       
   294 
       
   295         // size = 7;
       
   296         final int opc  = (aCommand << 16) | 7;
       
   297         ensureSpace(7);
       
   298 
       
   299         final int[] buffer = iBuffer;
       
   300         int count = iCount;
       
   301         buffer[count++] = opc;
       
   302         buffer[count++] = aArg1;
       
   303         buffer[count++] = aArg2;
       
   304         buffer[count++] = aArg3;
       
   305         buffer[count++] = aArg4;
       
   306         buffer[count++] = aArg5;
       
   307         buffer[count++] = aArg6;
       
   308         iCount = count;
       
   309     }
       
   310 
       
   311     /**
       
   312      *
       
   313      */
       
   314     final void write(int aHandle, int aCommand, int aArg1, int aArg2,
       
   315                      int aArg3, int aArg4, int aArg5, int aArg6, int aArg7)
       
   316     {
       
   317         if (iHandle <= 0)
       
   318         {
       
   319             throw new RuntimeException("Buffer closed");
       
   320         }
       
   321 
       
   322         if (aHandle != iCurrent)
       
   323         {
       
   324             deactivate();       // remove existing target
       
   325             activate(aHandle);  // set new target - this may cause a flush.
       
   326         }
       
   327 
       
   328         // size = 8;
       
   329         final int opc  = (aCommand << 16) | 8;
       
   330         ensureSpace(8);
       
   331 
       
   332         final int[] buffer = iBuffer;
       
   333         int count = iCount;
       
   334         buffer[count++] = opc;
       
   335         buffer[count++] = aArg1;
       
   336         buffer[count++] = aArg2;
       
   337         buffer[count++] = aArg3;
       
   338         buffer[count++] = aArg4;
       
   339         buffer[count++] = aArg5;
       
   340         buffer[count++] = aArg6;
       
   341         buffer[count++] = aArg7;
       
   342         iCount = count;
       
   343     }
       
   344 
       
   345     /**
       
   346      *
       
   347      */
       
   348     final void write(int aHandle, int aCommand, int aArg1, int aArg2,
       
   349                      int aArg3, int aArg4, int aArg5, int aArg6, int aArg7,
       
   350                      int aArg8, int aArg9)
       
   351     {
       
   352         if (iHandle <= 0)
       
   353         {
       
   354             throw new RuntimeException("Buffer closed");
       
   355         }
       
   356 
       
   357         if (aHandle != iCurrent)
       
   358         {
       
   359             deactivate();       // remove existing target
       
   360             activate(aHandle);  // set new target - this may cause a flush.
       
   361         }
       
   362 
       
   363         // size = 10;
       
   364         final int opc  = (aCommand << 16) | 10;
       
   365         ensureSpace(10);
       
   366 
       
   367         final int[] buffer = iBuffer;
       
   368         int count = iCount;
       
   369         buffer[count++] = opc;
       
   370         buffer[count++] = aArg1;
       
   371         buffer[count++] = aArg2;
       
   372         buffer[count++] = aArg3;
       
   373         buffer[count++] = aArg4;
       
   374         buffer[count++] = aArg5;
       
   375         buffer[count++] = aArg6;
       
   376         buffer[count++] = aArg7;
       
   377         buffer[count++] = aArg8;
       
   378         buffer[count++] = aArg9;
       
   379         iCount = count;
       
   380     }
       
   381 
       
   382     /**
       
   383      * Writes a string command into the buffer, intended to support
       
   384      * Graphics.drawString(), this method also passes three additional
       
   385      * integer parameters.
       
   386      *
       
   387      */
       
   388     final void writeStr(int aHandle, int aCmd, String aString, int aOff,
       
   389                         int aLen, int aArg1, int aArg2, int aArg3)
       
   390     {
       
   391         //
       
   392         // Implementation note: We cannot avoid two copies as even a native method
       
   393         // would still have to use GetStringChars() which makes a copy. There is
       
   394         // no equivalent to GetIntArrayRegion.
       
   395         //
       
   396         if (aLen > 0)
       
   397         {
       
   398             final char[] array = (aLen <= CHAR_BUFFER_SIZE ? iCharBuffer : new char[aLen]);
       
   399             aString.getChars(aOff, aOff+aLen, array, 0);
       
   400             writeChars(aHandle, aCmd, array, 0, aLen, aArg1, aArg2, aArg3);
       
   401         }
       
   402     }
       
   403 
       
   404     /**
       
   405      * Writes a character array command into the buffer, intended to support
       
   406      * Graphics.drawChars(), this method also passes three additional
       
   407      * integer parameters.
       
   408      */
       
   409     final void writeChars(int aHandle, int aCommand, char[] aChars, int aOff,
       
   410                           int aLen, int aArg1, int aArg2, int aArg3)
       
   411     {
       
   412         if (aLen < 1)
       
   413         {
       
   414             return;
       
   415         }
       
   416 
       
   417         //
       
   418         // cmd, x, y, anchor, len, char[0..len-1]
       
   419         //
       
   420         final int cmdLen = 4 + ((aLen+1)>>1);
       
   421 
       
   422         if (cmdLen < BUFFER_SIZE)
       
   423         {
       
   424             if (iHandle <= 0)
       
   425             {
       
   426                 throw new RuntimeException("Buffer closed");
       
   427             }
       
   428 
       
   429             if (aHandle != iCurrent)
       
   430             {
       
   431                 deactivate();       // remove existing target
       
   432                 activate(aHandle);  // set new target - this may cause a flush.
       
   433             }
       
   434 
       
   435             final int size = cmdLen + 1;
       
   436             final int opc  = (aCommand << 16) | size;
       
   437             ensureSpace(size);
       
   438 
       
   439             iBuffer[iCount++] = opc;
       
   440             iBuffer[iCount++] = aArg1;
       
   441             iBuffer[iCount++] = aArg2;
       
   442             iBuffer[iCount++] = aArg3;
       
   443 
       
   444             writeCharsInLine(aChars, aOff, aLen);
       
   445         }
       
   446         else
       
   447         {
       
   448             // Not enough space in the buffer
       
   449             throw new OutOfMemoryError();
       
   450             //
       
   451             // Possible alternatives:
       
   452             //
       
   453             // 1. Allocate an HBufC, write the chars into it, stick it in the buffer.
       
   454             //
       
   455             //      writeCharsOutOfLine();
       
   456             //
       
   457         }
       
   458     }
       
   459 
       
   460     /**
       
   461      *
       
   462      */
       
   463     private void writeCharsInLine(char[] aChars, int aOff, int aLen)
       
   464     {
       
   465         final int[] buffer = iBuffer;
       
   466         int count = iCount;
       
   467 
       
   468         buffer[count++] = aLen; // | CHAR_DATA_INLINE
       
   469 
       
   470         final int wend = aOff + (aLen & ~1);
       
   471 
       
   472         while (aOff < wend)
       
   473         {
       
   474             final int ch1 = aChars[aOff++];
       
   475             final int ch2 = aChars[aOff++];
       
   476 
       
   477             //
       
   478             // Pack two chars into each int.
       
   479             //
       
   480             // Assumes:
       
   481             //
       
   482             // ints are little endian.
       
   483             // char to int promotion doesn't sign extend
       
   484             //
       
   485 
       
   486             buffer[count++] = (ch2 << 16) | ch1;
       
   487         }
       
   488 
       
   489         if ((aLen & 1) == 1)
       
   490         {
       
   491             buffer[count++] = aChars[aOff];     // last char in first half-word
       
   492         }
       
   493 
       
   494         iCount = count;
       
   495     }
       
   496 
       
   497     /**
       
   498      * ensures there is at least aSize words of space remaining in the buffer,
       
   499      * and flushes the buffer if not.
       
   500      */
       
   501     final void ensureSpace(int aSize)
       
   502     {
       
   503         if ((iCount+aSize) > iBuffer.length)
       
   504         {
       
   505             pump();
       
   506             if (aSize > iBuffer.length)
       
   507             {
       
   508                 throw new RuntimeException("Insufficient space in buffer for command: " + aSize);
       
   509             }
       
   510         }
       
   511     }
       
   512 
       
   513     /**
       
   514      * Flushes buffer and waits for native processing to complete.
       
   515      */
       
   516     final void sync()
       
   517     {
       
   518         synchronized (this)
       
   519         {
       
   520             if (iCount > 0)
       
   521             {
       
   522                 deactivate();
       
   523                 _flush(iHandle, iBuffer, iCount);
       
   524                 iCount=0;
       
   525                 iStart=0;
       
   526                 iCurrent=-1;
       
   527             }
       
   528         }
       
   529     }
       
   530 
       
   531     /**
       
   532      *
       
   533      */
       
   534     private void deactivate()
       
   535     {
       
   536         if (-1 != iCurrent)
       
   537         {
       
   538             iBuffer[iStart] = iCount - iStart - 1;
       
   539             iCurrent = -1;
       
   540         }
       
   541     }
       
   542 
       
   543     /**
       
   544      *
       
   545      */
       
   546     private void activate(int aHandle)
       
   547     {
       
   548         if (0 != aHandle)
       
   549         {
       
   550             // flush if insufficient space for activation
       
   551             // command.
       
   552             // RECURSION NOTE: we do not use pump() here
       
   553             // to avoid any risk of recursion.
       
   554             if ((iCount + 2) > iBuffer.length)
       
   555             {
       
   556                 sync();
       
   557             }
       
   558 
       
   559             iBuffer[ iCount++ ] = (aHandle | ACTIVATE);
       
   560             iCurrent = aHandle;
       
   561             iStart   = iCount;
       
   562             iBuffer[ iCount++ ] = 0;
       
   563         }
       
   564         else
       
   565         {
       
   566             throw new RuntimeException("Invalid handle " + aHandle);
       
   567         }
       
   568     }
       
   569 
       
   570     /**
       
   571      * Flush the current contents of the buffer and reset the current writer.
       
   572      */
       
   573     private void pump()
       
   574     {
       
   575         final int current = iCurrent;
       
   576         sync();
       
   577         activate(current);
       
   578     }
       
   579 
       
   580     private native int  _open(int aEventServerHandle);
       
   581     private native void _flush(int aHandle, int[] aBuffer, int aCount);
       
   582     private native void _close(int aHandle);
       
   583 }
       
   584