Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2011, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #define LOG_TAG "ViewStateSerializer"
     27 #define LOG_NDEBUG 1
     28 
     29 #include "config.h"
     30 
     31 #include "BaseLayerAndroid.h"
     32 #include "CreateJavaOutputStreamAdaptor.h"
     33 #include "DumpLayer.h"
     34 #include "FixedPositioning.h"
     35 #include "ImagesManager.h"
     36 #include "IFrameContentLayerAndroid.h"
     37 #include "IFrameLayerAndroid.h"
     38 #include "Layer.h"
     39 #include "LayerAndroid.h"
     40 #include "LayerContent.h"
     41 #include "PictureLayerContent.h"
     42 #include "ScrollableLayerAndroid.h"
     43 #include "SkData.h"
     44 #include "SkOrderedReadBuffer.h"
     45 #include "SkOrderedWriteBuffer.h"
     46 #include "SkPicture.h"
     47 #include "TilesManager.h"
     48 
     49 #include <JNIUtility.h>
     50 #include <JNIHelp.h>
     51 #include <jni.h>
     52 
     53 namespace android {
     54 
     55 enum LayerTypes {
     56     LTNone = 0,
     57     LTLayerAndroid = 1,
     58     LTScrollableLayerAndroid = 2,
     59     LTFixedLayerAndroid = 3
     60 };
     61 
     62 #define ID "mID"
     63 #define LEFT "layout:mLeft"
     64 #define TOP "layout:mTop"
     65 #define WIDTH "layout:getWidth()"
     66 #define HEIGHT "layout:getHeight()"
     67 
     68 class HierarchyLayerDumper : public LayerDumper {
     69 public:
     70     HierarchyLayerDumper(SkWStream* stream, int level)
     71         : LayerDumper(level)
     72         , m_stream(stream)
     73     {}
     74 
     75     virtual void beginLayer(const char* className, const LayerAndroid* layerPtr) {
     76         LayerDumper::beginLayer(className, layerPtr);
     77         for (int i = 0; i < m_indentLevel; i++) {
     78             m_stream->writeText(" ");
     79         }
     80         m_stream->writeText(className);
     81         m_stream->writeText("@");
     82         m_stream->writeHexAsText(layerPtr->uniqueId());
     83         m_stream->writeText(" ");
     84 
     85         writeHexVal(ID, (int) layerPtr);
     86         writeIntVal(LEFT, layerPtr->getPosition().fX);
     87         writeIntVal(TOP, layerPtr->getPosition().fY);
     88         writeIntVal(WIDTH, layerPtr->getWidth());
     89         writeIntVal(HEIGHT, layerPtr->getHeight());
     90     }
     91 
     92     virtual void beginChildren(int childCount) {
     93         m_stream->writeText("\n");
     94         LayerDumper::beginChildren(childCount);
     95     }
     96 
     97 protected:
     98     virtual void writeEntry(const char* label, const char* value) {
     99         m_stream->writeText(label);
    100         m_stream->writeText("=");
    101         int len = strlen(value);
    102         m_stream->writeDecAsText(len);
    103         m_stream->writeText(",");
    104         m_stream->writeText(value);
    105         m_stream->writeText(" ");
    106     }
    107 
    108 private:
    109     SkWStream* m_stream;
    110 };
    111 
    112 static void nativeDumpLayerHierarchy(JNIEnv* env, jobject, jint jbaseLayer, jint level,
    113                                      jobject jstream, jbyteArray jstorage)
    114 {
    115     SkWStream *stream = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
    116     BaseLayerAndroid* baseLayer = reinterpret_cast<BaseLayerAndroid*>(jbaseLayer);
    117     SkSafeRef(baseLayer);
    118     HierarchyLayerDumper dumper(stream, level);
    119     baseLayer->dumpLayers(&dumper);
    120     SkSafeUnref(baseLayer);
    121     delete stream;
    122 }
    123 
    124 static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer,
    125                                      jobject jstream, jbyteArray jstorage)
    126 {
    127     BaseLayerAndroid* baseLayer = (BaseLayerAndroid*) jbaseLayer;
    128     if (!baseLayer)
    129         return false;
    130 
    131     SkWStream *stream = CreateJavaOutputStreamAdaptor(env, jstream, jstorage);
    132 #if USE(ACCELERATED_COMPOSITING)
    133     stream->write32(baseLayer->getBackgroundColor().rgb());
    134 #else
    135     stream->write32(0);
    136 #endif
    137     if (!stream)
    138         return false;
    139     if (baseLayer->content())
    140         baseLayer->content()->serialize(stream);
    141     else
    142         return false;
    143     int childCount = baseLayer->countChildren();
    144     ALOGV("BaseLayer has %d child(ren)", childCount);
    145     stream->write32(childCount);
    146     for (int i = 0; i < childCount; i++) {
    147         LayerAndroid* layer = static_cast<LayerAndroid*>(baseLayer->getChild(i));
    148         serializeLayer(layer, stream);
    149     }
    150     delete stream;
    151     return true;
    152 }
    153 
    154 static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jint version,
    155                                                     jobject jstream, jbyteArray jstorage)
    156 {
    157     SkStream* javaStream = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
    158     if (!javaStream)
    159         return 0;
    160 
    161     // read everything into memory so that we can get the offset into the stream
    162     // when necessary. This is needed for the LegacyPictureLayerContent.
    163     SkDynamicMemoryWStream tempStream;
    164     const int bufferSize = 256*1024; // 256KB
    165     uint8_t buffer[bufferSize];
    166     int bytesRead = 0;
    167 
    168     do {
    169       bytesRead = javaStream->read(buffer, bufferSize);
    170       tempStream.write(buffer, bytesRead);
    171     } while (bytesRead != 0);
    172 
    173     SkMemoryStream stream;
    174     stream.setData(tempStream.copyToData())->unref();
    175 
    176     // clean up the javaStream now that we have everything in memory
    177     delete javaStream;
    178 
    179     Color color = stream.readU32();
    180 
    181 
    182 
    183     LayerContent* content;
    184     if (version == 1) {
    185         content = new LegacyPictureLayerContent(&stream);
    186     } else {
    187         SkPicture* picture = new SkPicture(&stream);
    188         content = new PictureLayerContent(picture);
    189         SkSafeUnref(picture);
    190     }
    191 
    192     BaseLayerAndroid* layer = new BaseLayerAndroid(content);
    193     layer->setBackgroundColor(color);
    194 
    195     SkRegion dirtyRegion;
    196     dirtyRegion.setRect(0, 0, content->width(), content->height());
    197     layer->markAsDirty(dirtyRegion);
    198 
    199     SkSafeUnref(content);
    200     int childCount = stream.readS32();
    201     for (int i = 0; i < childCount; i++) {
    202         LayerAndroid* childLayer = deserializeLayer(version, &stream);
    203         if (childLayer)
    204             layer->addChild(childLayer);
    205     }
    206     return layer;
    207 }
    208 
    209 // Serialization helpers
    210 
    211 void writeMatrix(SkWStream *stream, const SkMatrix& matrix)
    212 {
    213     for (int i = 0; i < 9; i++)
    214         stream->writeScalar(matrix[i]);
    215 }
    216 
    217 SkMatrix readMatrix(SkStream *stream)
    218 {
    219     SkMatrix matrix;
    220     for (int i = 0; i < 9; i++)
    221         matrix.set(i, stream->readScalar());
    222     return matrix;
    223 }
    224 
    225 void writeSkLength(SkWStream *stream, SkLength length)
    226 {
    227     stream->write32(length.type);
    228     stream->writeScalar(length.value);
    229 }
    230 
    231 SkLength readSkLength(SkStream *stream)
    232 {
    233     SkLength len;
    234     len.type = (SkLength::SkLengthType) stream->readU32();
    235     len.value = stream->readScalar();
    236     return len;
    237 }
    238 
    239 void writeSkRect(SkWStream *stream, SkRect rect)
    240 {
    241     stream->writeScalar(rect.fLeft);
    242     stream->writeScalar(rect.fTop);
    243     stream->writeScalar(rect.fRight);
    244     stream->writeScalar(rect.fBottom);
    245 }
    246 
    247 SkRect readSkRect(SkStream *stream)
    248 {
    249     SkRect rect;
    250     rect.fLeft = stream->readScalar();
    251     rect.fTop = stream->readScalar();
    252     rect.fRight = stream->readScalar();
    253     rect.fBottom = stream->readScalar();
    254     return rect;
    255 }
    256 
    257 void writeTransformationMatrix(SkWStream *stream, TransformationMatrix& matrix)
    258 {
    259     double value;
    260     int dsize = sizeof(double);
    261     value = matrix.m11();
    262     stream->write(&value, dsize);
    263     value = matrix.m12();
    264     stream->write(&value, dsize);
    265     value = matrix.m13();
    266     stream->write(&value, dsize);
    267     value = matrix.m14();
    268     stream->write(&value, dsize);
    269     value = matrix.m21();
    270     stream->write(&value, dsize);
    271     value = matrix.m22();
    272     stream->write(&value, dsize);
    273     value = matrix.m23();
    274     stream->write(&value, dsize);
    275     value = matrix.m24();
    276     stream->write(&value, dsize);
    277     value = matrix.m31();
    278     stream->write(&value, dsize);
    279     value = matrix.m32();
    280     stream->write(&value, dsize);
    281     value = matrix.m33();
    282     stream->write(&value, dsize);
    283     value = matrix.m34();
    284     stream->write(&value, dsize);
    285     value = matrix.m41();
    286     stream->write(&value, dsize);
    287     value = matrix.m42();
    288     stream->write(&value, dsize);
    289     value = matrix.m43();
    290     stream->write(&value, dsize);
    291     value = matrix.m44();
    292     stream->write(&value, dsize);
    293 }
    294 
    295 void readTransformationMatrix(SkStream *stream, TransformationMatrix& matrix)
    296 {
    297     double value;
    298     int dsize = sizeof(double);
    299     stream->read(&value, dsize);
    300     matrix.setM11(value);
    301     stream->read(&value, dsize);
    302     matrix.setM12(value);
    303     stream->read(&value, dsize);
    304     matrix.setM13(value);
    305     stream->read(&value, dsize);
    306     matrix.setM14(value);
    307     stream->read(&value, dsize);
    308     matrix.setM21(value);
    309     stream->read(&value, dsize);
    310     matrix.setM22(value);
    311     stream->read(&value, dsize);
    312     matrix.setM23(value);
    313     stream->read(&value, dsize);
    314     matrix.setM24(value);
    315     stream->read(&value, dsize);
    316     matrix.setM31(value);
    317     stream->read(&value, dsize);
    318     matrix.setM32(value);
    319     stream->read(&value, dsize);
    320     matrix.setM33(value);
    321     stream->read(&value, dsize);
    322     matrix.setM34(value);
    323     stream->read(&value, dsize);
    324     matrix.setM41(value);
    325     stream->read(&value, dsize);
    326     matrix.setM42(value);
    327     stream->read(&value, dsize);
    328     matrix.setM43(value);
    329     stream->read(&value, dsize);
    330     matrix.setM44(value);
    331 }
    332 
    333 void serializeLayer(LayerAndroid* layer, SkWStream* stream)
    334 {
    335     if (!layer) {
    336         ALOGV("NULL layer!");
    337         stream->write8(LTNone);
    338         return;
    339     }
    340     if (layer->isMedia() || layer->isVideo()) {
    341         ALOGV("Layer isn't supported for serialization: isMedia: %s, isVideo: %s",
    342              layer->isMedia() ? "true" : "false",
    343              layer->isVideo() ? "true" : "false");
    344         stream->write8(LTNone);
    345         return;
    346     }
    347     LayerTypes type = LTLayerAndroid;
    348     if (layer->contentIsScrollable())
    349         type = LTScrollableLayerAndroid;
    350     stream->write8(type);
    351 
    352     // Start with Layer fields
    353     stream->writeBool(layer->shouldInheritFromRootTransform());
    354     stream->writeScalar(layer->getOpacity());
    355     stream->writeScalar(layer->getSize().width());
    356     stream->writeScalar(layer->getSize().height());
    357     stream->writeScalar(layer->getPosition().x());
    358     stream->writeScalar(layer->getPosition().y());
    359     stream->writeScalar(layer->getAnchorPoint().x());
    360     stream->writeScalar(layer->getAnchorPoint().y());
    361     writeMatrix(stream, layer->getMatrix());
    362     writeMatrix(stream, layer->getChildrenMatrix());
    363 
    364     // Next up, LayerAndroid fields
    365     stream->writeBool(layer->m_haveClip);
    366     stream->writeBool(layer->isPositionFixed());
    367     stream->writeBool(layer->m_backgroundColorSet);
    368     stream->writeBool(layer->isIFrame());
    369 
    370     // With the current LayerAndroid hierarchy, LayerAndroid doesn't have
    371     // those fields anymore. Let's keep the current serialization format for
    372     // now and output blank fields... not great, but probably better than
    373     // dealing with multiple versions.
    374     if (layer->fixedPosition()) {
    375         FixedPositioning* fixedPosition = layer->fixedPosition();
    376         writeSkLength(stream, fixedPosition->m_fixedLeft);
    377         writeSkLength(stream, fixedPosition->m_fixedTop);
    378         writeSkLength(stream, fixedPosition->m_fixedRight);
    379         writeSkLength(stream, fixedPosition->m_fixedBottom);
    380         writeSkLength(stream, fixedPosition->m_fixedMarginLeft);
    381         writeSkLength(stream, fixedPosition->m_fixedMarginTop);
    382         writeSkLength(stream, fixedPosition->m_fixedMarginRight);
    383         writeSkLength(stream, fixedPosition->m_fixedMarginBottom);
    384         writeSkRect(stream, fixedPosition->m_fixedRect);
    385         stream->write32(fixedPosition->m_renderLayerPos.x());
    386         stream->write32(fixedPosition->m_renderLayerPos.y());
    387     } else {
    388         SkLength length;
    389         SkRect rect;
    390         writeSkLength(stream, length); // fixedLeft
    391         writeSkLength(stream, length); // fixedTop
    392         writeSkLength(stream, length); // fixedRight
    393         writeSkLength(stream, length); // fixedBottom
    394         writeSkLength(stream, length); // fixedMarginLeft
    395         writeSkLength(stream, length); // fixedMarginTop
    396         writeSkLength(stream, length); // fixedMarginRight
    397         writeSkLength(stream, length); // fixedMarginBottom
    398         writeSkRect(stream, rect);     // fixedRect
    399         stream->write32(0);            // renderLayerPos.x()
    400         stream->write32(0);            // renderLayerPos.y()
    401     }
    402 
    403     stream->writeBool(layer->m_backfaceVisibility);
    404     stream->writeBool(layer->m_visible);
    405     stream->write32(layer->m_backgroundColor);
    406     stream->writeBool(layer->m_preserves3D);
    407     stream->writeScalar(layer->m_anchorPointZ);
    408     stream->writeScalar(layer->m_drawOpacity);
    409     bool hasContentsImage = layer->m_imageCRC != 0;
    410     stream->writeBool(hasContentsImage);
    411     if (hasContentsImage) {
    412         SkOrderedWriteBuffer buffer(1024);
    413         buffer.setFlags(SkFlattenableWriteBuffer::kCrossProcess_Flag);
    414         ImageTexture* imagetexture =
    415                 ImagesManager::instance()->retainImage(layer->m_imageCRC);
    416         if (imagetexture && imagetexture->bitmap())
    417             imagetexture->bitmap()->flatten(buffer);
    418         ImagesManager::instance()->releaseImage(layer->m_imageCRC);
    419         stream->write32(buffer.size());
    420         buffer.writeToStream(stream);
    421     }
    422     bool hasRecordingPicture = layer->m_content != 0 && !layer->m_content->isEmpty();
    423     stream->writeBool(hasRecordingPicture);
    424     if (hasRecordingPicture)
    425         layer->m_content->serialize(stream);
    426     // TODO: support m_animations (maybe?)
    427     stream->write32(0); // placeholder for m_animations.size();
    428     writeTransformationMatrix(stream, layer->m_transform);
    429     writeTransformationMatrix(stream, layer->m_childrenTransform);
    430     if (type == LTScrollableLayerAndroid) {
    431         ScrollableLayerAndroid* scrollableLayer =
    432                 static_cast<ScrollableLayerAndroid*>(layer);
    433         stream->writeScalar(scrollableLayer->m_scrollLimits.fLeft);
    434         stream->writeScalar(scrollableLayer->m_scrollLimits.fTop);
    435         stream->writeScalar(scrollableLayer->m_scrollLimits.width());
    436         stream->writeScalar(scrollableLayer->m_scrollLimits.height());
    437     }
    438     int childCount = layer->countChildren();
    439     stream->write32(childCount);
    440     for (int i = 0; i < childCount; i++)
    441         serializeLayer(layer->getChild(i), stream);
    442 }
    443 
    444 LayerAndroid* deserializeLayer(int version, SkMemoryStream* stream)
    445 {
    446     int type = stream->readU8();
    447     if (type == LTNone)
    448         return 0;
    449     // Cast is to disambiguate between ctors.
    450     LayerAndroid *layer;
    451     if (type == LTLayerAndroid)
    452         layer = new LayerAndroid((RenderLayer*) 0);
    453     else if (type == LTScrollableLayerAndroid)
    454         layer = new ScrollableLayerAndroid((RenderLayer*) 0);
    455     else {
    456         ALOGV("Unexpected layer type: %d, aborting!", type);
    457         return 0;
    458     }
    459 
    460     // Layer fields
    461     layer->setShouldInheritFromRootTransform(stream->readBool());
    462     layer->setOpacity(stream->readScalar());
    463     layer->setSize(stream->readScalar(), stream->readScalar());
    464     layer->setPosition(stream->readScalar(), stream->readScalar());
    465     layer->setAnchorPoint(stream->readScalar(), stream->readScalar());
    466     layer->setMatrix(readMatrix(stream));
    467     layer->setChildrenMatrix(readMatrix(stream));
    468 
    469     // LayerAndroid fields
    470     layer->m_haveClip = stream->readBool();
    471 
    472     // Keep the legacy serialization/deserialization format...
    473     bool isFixed = stream->readBool();
    474 
    475     layer->m_backgroundColorSet = stream->readBool();
    476 
    477     bool isIframe = stream->readBool();
    478     // If we are a scrollable layer android, we are an iframe content
    479     if (isIframe && type == LTScrollableLayerAndroid) {
    480          IFrameContentLayerAndroid* iframeContent = new IFrameContentLayerAndroid(*layer);
    481          layer->unref();
    482          layer = iframeContent;
    483     } else if (isIframe) { // otherwise we are just the iframe (we use it to compute offset)
    484          IFrameLayerAndroid* iframe = new IFrameLayerAndroid(*layer);
    485          layer->unref();
    486          layer = iframe;
    487     }
    488 
    489     if (isFixed) {
    490         FixedPositioning* fixedPosition = new FixedPositioning(layer);
    491 
    492         fixedPosition->m_fixedLeft = readSkLength(stream);
    493         fixedPosition->m_fixedTop = readSkLength(stream);
    494         fixedPosition->m_fixedRight = readSkLength(stream);
    495         fixedPosition->m_fixedBottom = readSkLength(stream);
    496         fixedPosition->m_fixedMarginLeft = readSkLength(stream);
    497         fixedPosition->m_fixedMarginTop = readSkLength(stream);
    498         fixedPosition->m_fixedMarginRight = readSkLength(stream);
    499         fixedPosition->m_fixedMarginBottom = readSkLength(stream);
    500         fixedPosition->m_fixedRect = readSkRect(stream);
    501         fixedPosition->m_renderLayerPos.setX(stream->readS32());
    502         fixedPosition->m_renderLayerPos.setY(stream->readS32());
    503 
    504         layer->setFixedPosition(fixedPosition);
    505     } else {
    506         // Not a fixed element, bypass the values in the stream
    507         readSkLength(stream); // fixedLeft
    508         readSkLength(stream); // fixedTop
    509         readSkLength(stream); // fixedRight
    510         readSkLength(stream); // fixedBottom
    511         readSkLength(stream); // fixedMarginLeft
    512         readSkLength(stream); // fixedMarginTop
    513         readSkLength(stream); // fixedMarginRight
    514         readSkLength(stream); // fixedMarginBottom
    515         readSkRect(stream);   // fixedRect
    516         stream->readS32();    // renderLayerPos.x()
    517         stream->readS32();    // renderLayerPos.y()
    518     }
    519 
    520     layer->m_backfaceVisibility = stream->readBool();
    521     layer->m_visible = stream->readBool();
    522     layer->m_backgroundColor = stream->readU32();
    523     layer->m_preserves3D = stream->readBool();
    524     layer->m_anchorPointZ = stream->readScalar();
    525     layer->m_drawOpacity = stream->readScalar();
    526     bool hasContentsImage = stream->readBool();
    527     if (hasContentsImage) {
    528         int size = stream->readU32();
    529         SkAutoMalloc storage(size);
    530         stream->read(storage.get(), size);
    531         SkOrderedReadBuffer buffer(storage.get(), size);
    532         SkBitmap contentsImage;
    533         contentsImage.unflatten(buffer);
    534         SkBitmapRef* imageRef = new SkBitmapRef(contentsImage);
    535         layer->setContentsImage(imageRef);
    536         delete imageRef;
    537     }
    538     bool hasRecordingPicture = stream->readBool();
    539     if (hasRecordingPicture) {
    540       LayerContent* content;
    541         if (version == 1) {
    542             content = new LegacyPictureLayerContent(stream);
    543         } else {
    544             SkPicture* picture = new SkPicture(stream);
    545             content = new PictureLayerContent(picture);
    546             SkSafeUnref(picture);
    547         }
    548         layer->setContent(content);
    549         SkSafeUnref(content);
    550     }
    551     int animationCount = stream->readU32(); // TODO: Support (maybe?)
    552     readTransformationMatrix(stream, layer->m_transform);
    553     readTransformationMatrix(stream, layer->m_childrenTransform);
    554     if (type == LTScrollableLayerAndroid) {
    555         ScrollableLayerAndroid* scrollableLayer =
    556                 static_cast<ScrollableLayerAndroid*>(layer);
    557         scrollableLayer->m_scrollLimits.set(
    558                 stream->readScalar(),
    559                 stream->readScalar(),
    560                 stream->readScalar(),
    561                 stream->readScalar());
    562     }
    563     int childCount = stream->readU32();
    564     for (int i = 0; i < childCount; i++) {
    565         LayerAndroid *childLayer = deserializeLayer(version, stream);
    566         if (childLayer)
    567             layer->addChild(childLayer);
    568     }
    569     ALOGV("Created layer with id %d", layer->uniqueId());
    570     return layer;
    571 }
    572 
    573 /*
    574  * JNI registration
    575  */
    576 static JNINativeMethod gSerializerMethods[] = {
    577     { "nativeDumpLayerHierarchy", "(IILjava/io/OutputStream;[B)V",
    578         (void*) nativeDumpLayerHierarchy },
    579     { "nativeSerializeViewState", "(ILjava/io/OutputStream;[B)Z",
    580         (void*) nativeSerializeViewState },
    581     { "nativeDeserializeViewState", "(ILjava/io/InputStream;[B)I",
    582         (void*) nativeDeserializeViewState },
    583 };
    584 
    585 int registerViewStateSerializer(JNIEnv* env)
    586 {
    587     return jniRegisterNativeMethods(env, "android/webkit/ViewStateSerializer",
    588                                     gSerializerMethods, NELEM(gSerializerMethods));
    589 }
    590 
    591 }
    592