Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2007, 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 "webhistory"
     27 
     28 #include "config.h"
     29 #include "WebHistory.h"
     30 
     31 #include "BackForwardList.h"
     32 #include "BackForwardListImpl.h"
     33 #include "DocumentLoader.h"
     34 #include "Frame.h"
     35 #include "FrameLoader.h"
     36 #include "FrameLoaderClientAndroid.h"
     37 #include "FrameTree.h"
     38 #include "HistoryItem.h"
     39 #include "IconDatabase.h"
     40 #include "Page.h"
     41 #include "TextEncoding.h"
     42 #include "WebCoreFrameBridge.h"
     43 #include "WebCoreJni.h"
     44 #include "WebIconDatabase.h"
     45 
     46 #include <JNIHelp.h>
     47 #include "JNIUtility.h"
     48 #include <SkUtils.h>
     49 #include <utils/misc.h>
     50 #include <wtf/OwnPtr.h>
     51 #include <wtf/Platform.h>
     52 #include <wtf/text/CString.h>
     53 
     54 namespace android {
     55 
     56 // Forward declarations
     57 static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item);
     58 static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent);
     59 static bool read_item_recursive(WebCore::HistoryItem* child, const char** pData, int length);
     60 
     61 // Field ids for WebHistoryItems
     62 struct WebHistoryItemFields {
     63     jmethodID   mInit;
     64     jmethodID   mUpdate;
     65     jfieldID    mTitle;
     66     jfieldID    mUrl;
     67 } gWebHistoryItem;
     68 
     69 struct WebBackForwardListFields {
     70     jmethodID   mAddHistoryItem;
     71     jmethodID   mRemoveHistoryItem;
     72     jmethodID   mSetCurrentIndex;
     73 } gWebBackForwardList;
     74 
     75 //--------------------------------------------------------------------------
     76 // WebBackForwardList native methods.
     77 //--------------------------------------------------------------------------
     78 
     79 static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame)
     80 {
     81     LOG_ASSERT(frame, "Close needs a valid Frame pointer!");
     82     WebCore::Frame* pFrame = (WebCore::Frame*)frame;
     83 
     84     WebCore::BackForwardListImpl* list = static_cast<WebCore::BackForwardListImpl*>(pFrame->page()->backForwardList());
     85     RefPtr<WebCore::HistoryItem> current = list->currentItem();
     86     // Remove each item instead of using close(). close() is intended to be used
     87     // right before the list is deleted.
     88     WebCore::HistoryItemVector& entries = list->entries();
     89     int size = entries.size();
     90     for (int i = size - 1; i >= 0; --i)
     91         list->removeItem(entries[i].get());
     92     // Add the current item back to the list.
     93     if (current) {
     94         current->setBridge(0);
     95         // addItem will update the children to match the newly created bridge
     96         list->addItem(current);
     97 
     98         /*
     99          * The Grand Prix site uses anchor navigations to change the display.
    100          * WebKit tries to be smart and not load child frames that have the
    101          * same history urls during an anchor navigation. This means that the
    102          * current history item stored in the child frame's loader does not
    103          * match the item found in the history tree. If we remove all the
    104          * entries in the back/foward list, we have to restore the entire tree
    105          * or else a HistoryItem might have a deleted parent.
    106          *
    107          * In order to restore the history tree correctly, we have to look up
    108          * all the frames first and then look up the history item. We do this
    109          * because the history item in the tree may be null at this point.
    110          * Unfortunately, a HistoryItem can only search its immediately
    111          * children so we do a breadth-first rebuild of the tree.
    112          */
    113 
    114         // Keep a small list of child frames to traverse.
    115         WTF::Vector<WebCore::Frame*> frameQueue;
    116         // Fix the top-level item.
    117         pFrame->loader()->history()->setCurrentItem(current.get());
    118         WebCore::Frame* child = pFrame->tree()->firstChild();
    119         // Remember the parent history item so we can search for a child item.
    120         RefPtr<WebCore::HistoryItem> parent = current;
    121         while (child) {
    122             // Use the old history item since the current one may have a
    123             // deleted parent.
    124             WebCore::HistoryItem* item = parent->childItemWithTarget(child->tree()->name());
    125             child->loader()->history()->setCurrentItem(item);
    126             // Append the first child to the queue if it exists. If there is no
    127             // item, then we do not need to traverse the children since there
    128             // will be no parent history item.
    129             WebCore::Frame* firstChild;
    130             if (item && (firstChild = child->tree()->firstChild()))
    131                 frameQueue.append(firstChild);
    132             child = child->tree()->nextSibling();
    133             // If we don't have a sibling for this frame and the queue isn't
    134             // empty, use the next entry in the queue.
    135             if (!child && !frameQueue.isEmpty()) {
    136                 child = frameQueue.at(0);
    137                 frameQueue.remove(0);
    138                 // Figure out the parent history item used when searching for
    139                 // the history item to use.
    140                 parent = child->tree()->parent()->loader()->history()->currentItem();
    141             }
    142         }
    143     }
    144 }
    145 
    146 static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint index)
    147 {
    148     LOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!");
    149     WebCore::Frame* pFrame = (WebCore::Frame*)frame;
    150     WebCore::Page* page = pFrame->page();
    151     WebCore::HistoryItem* currentItem =
    152             static_cast<WebCore::BackForwardListImpl*>(page->backForwardList())->entries()[index].get();
    153 
    154     // load the current page with FrameLoadTypeIndexedBackForward so that it
    155     // will use cache when it is possible
    156     page->goToItem(currentItem, FrameLoadTypeIndexedBackForward);
    157 }
    158 
    159 static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray data)
    160 {
    161     LOG_ASSERT(frame, "Inflate needs a valid frame pointer!");
    162     LOG_ASSERT(data, "Inflate needs a valid data pointer!");
    163 
    164     // Get the actual bytes and the length from the java array.
    165     const jbyte* bytes = env->GetByteArrayElements(data, NULL);
    166     jsize size = env->GetArrayLength(data);
    167 
    168     // Inflate the history tree into one HistoryItem or null if the inflation
    169     // failed.
    170     RefPtr<WebCore::HistoryItem> newItem = WebCore::HistoryItem::create();
    171     WebHistoryItem* bridge = new WebHistoryItem(env, obj, newItem.get());
    172     newItem->setBridge(bridge);
    173 
    174     // Inflate the item recursively. If it fails, that is ok. We'll have an
    175     // incomplete HistoryItem but that is better than crashing due to a null
    176     // item.
    177     // We have a 2nd local variable since read_item_recursive may change the
    178     // ptr's value. We can't pass &bytes since we have to send bytes to
    179     // ReleaseByteArrayElements unchanged.
    180     const char* ptr = reinterpret_cast<const char*>(bytes);
    181     read_item_recursive(newItem.get(), &ptr, (int)size);
    182     env->ReleaseByteArrayElements(data, const_cast<jbyte*>(bytes), JNI_ABORT);
    183     bridge->setActive();
    184 
    185     // Add the new item to the back/forward list.
    186     WebCore::Frame* pFrame = (WebCore::Frame*)frame;
    187     pFrame->page()->backForwardList()->addItem(newItem);
    188 
    189     // Update the item.
    190     bridge->updateHistoryItem(newItem.get());
    191 }
    192 
    193 // 6 empty strings + no document state + children count + 2 scales = 10 unsigned values
    194 // 1 char for isTargetItem.
    195 #define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 10 + sizeof(char)))
    196 
    197 jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::HistoryItem* item)
    198 {
    199     if (!item)
    200         return NULL;
    201 
    202     // Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE.
    203     v.reserveCapacity(HISTORY_MIN_SIZE);
    204 
    205     // Write the top-level history item and then write all the children
    206     // recursively.
    207     LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
    208     write_item(v, item);
    209     write_children_recursive(v, item);
    210 
    211     // Try to create a new java byte array.
    212     jbyteArray b = env->NewByteArray(v.size());
    213     if (!b)
    214         return NULL;
    215 
    216     // Write our flattened data to the java array.
    217     env->SetByteArrayRegion(b, 0, v.size(), (const jbyte*)v.data());
    218     return b;
    219 }
    220 
    221 WebHistoryItem::WebHistoryItem(JNIEnv* env, jobject obj,
    222         WebCore::HistoryItem* item) : WebCore::AndroidWebHistoryBridge(item) {
    223     m_object = env->NewWeakGlobalRef(obj);
    224     m_parent = 0;
    225 }
    226 
    227 WebHistoryItem::~WebHistoryItem() {
    228     if (m_object) {
    229         JNIEnv* env = JSC::Bindings::getJNIEnv();
    230         if (!env)
    231             return;
    232         env->DeleteWeakGlobalRef(m_object);
    233     }
    234 }
    235 
    236 void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
    237     // Do not want to update during inflation.
    238     if (!m_active)
    239         return;
    240     WebHistoryItem* webItem = this;
    241     // Now we need to update the top-most WebHistoryItem based on the top-most
    242     // HistoryItem.
    243     if (m_parent) {
    244         webItem = m_parent.get();
    245         if (webItem->hasOneRef()) {
    246             // if the parent only has one ref, it is from this WebHistoryItem.
    247             // This means that the matching WebCore::HistoryItem has been freed.
    248             // This can happen during clear().
    249             LOGW("Can't updateHistoryItem as the top HistoryItem is gone");
    250             return;
    251         }
    252         while (webItem->parent())
    253             webItem = webItem->parent();
    254         item = webItem->historyItem();
    255         if (!item) {
    256             // If a HistoryItem only exists for page cache, it is possible that
    257             // the parent HistoryItem destroyed before the child HistoryItem. If
    258             // it happens, skip updating.
    259             LOGW("Can't updateHistoryItem as the top HistoryItem is gone");
    260             return;
    261         }
    262     }
    263     JNIEnv* env = JSC::Bindings::getJNIEnv();
    264     if (!env)
    265         return;
    266 
    267     // Don't do anything if the item has been gc'd already
    268     AutoJObject realItem = getRealObject(env, webItem->m_object);
    269     if (!realItem.get())
    270         return;
    271 
    272     const WTF::String urlString = WebFrame::convertIDNToUnicode(item->url());
    273     jstring urlStr = NULL;
    274     if (!urlString.isNull())
    275         urlStr = wtfStringToJstring(env, urlString);
    276     const WTF::String originalUrlString = WebFrame::convertIDNToUnicode(item->originalURL());
    277     jstring originalUrlStr = NULL;
    278     if (!originalUrlString.isNull())
    279         originalUrlStr = wtfStringToJstring(env, originalUrlString);
    280     const WTF::String& titleString = item->title();
    281     jstring titleStr = NULL;
    282     if (!titleString.isNull())
    283         titleStr = wtfStringToJstring(env, titleString);
    284 
    285     // Try to get the favicon from the history item. For some pages like Grand
    286     // Prix, there are history items with anchors. If the icon fails for the
    287     // item, try to get the icon using the url without the ref.
    288     jobject favicon = NULL;
    289     WTF::String url = item->urlString();
    290     if (item->url().hasFragmentIdentifier()) {
    291         int refIndex = url.reverseFind('#');
    292         url = url.substring(0, refIndex);
    293     }
    294     // FIXME: This method should not be used from outside WebCore and will be removed.
    295     // http://trac.webkit.org/changeset/81484
    296     WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(url, WebCore::IntSize(16, 16));
    297 
    298     if (icon)
    299         favicon = webcoreImageToJavaBitmap(env, icon);
    300 
    301     WTF::Vector<char> data;
    302     jbyteArray array = WebHistory::Flatten(env, data, item);
    303     env->CallVoidMethod(realItem.get(), gWebHistoryItem.mUpdate, urlStr,
    304             originalUrlStr, titleStr, favicon, array);
    305     env->DeleteLocalRef(urlStr);
    306     env->DeleteLocalRef(originalUrlStr);
    307     env->DeleteLocalRef(titleStr);
    308     if (favicon)
    309         env->DeleteLocalRef(favicon);
    310     env->DeleteLocalRef(array);
    311 }
    312 
    313 static void historyItemChanged(WebCore::HistoryItem* item) {
    314     LOG_ASSERT(item, "historyItemChanged called with a null item");
    315 
    316     if (item->bridge())
    317         item->bridge()->updateHistoryItem(item);
    318 }
    319 
    320 void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item)
    321 {
    322     LOG_ASSERT(item, "newItem must take a valid HistoryItem!");
    323     // Item already added. Should only happen when we are inflating the list.
    324     if (item->bridge() || !list.get())
    325         return;
    326 
    327     JNIEnv* env = list.env();
    328     // Allocate a blank WebHistoryItem
    329     jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
    330     jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit);
    331     env->DeleteLocalRef(clazz);
    332 
    333     // Create the bridge, make it active, and attach it to the item.
    334     WebHistoryItem* bridge = new WebHistoryItem(env, newItem, item);
    335     bridge->setActive();
    336     item->setBridge(bridge);
    337 
    338     // Update the history item which will flatten the data and call update on
    339     // the java item.
    340     bridge->updateHistoryItem(item);
    341 
    342     // Add it to the list.
    343     env->CallVoidMethod(list.get(), gWebBackForwardList.mAddHistoryItem, newItem);
    344 
    345     // Delete our local reference.
    346     env->DeleteLocalRef(newItem);
    347 }
    348 
    349 void WebHistory::RemoveItem(const AutoJObject& list, int index)
    350 {
    351     if (list.get())
    352         list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mRemoveHistoryItem, index);
    353 }
    354 
    355 void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex)
    356 {
    357     if (list.get())
    358         list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex);
    359 }
    360 
    361 static void write_string(WTF::Vector<char>& v, const WTF::String& str)
    362 {
    363     unsigned strLen = str.length();
    364     // Only do work if the string has data.
    365     if (strLen) {
    366         // Determine how much to grow the vector. Use the worst case for utf8 to
    367         // avoid reading the string twice. Add sizeof(unsigned) to hold the
    368         // string length in utf8.
    369         unsigned vectorLen = v.size() + sizeof(unsigned);
    370         unsigned length = (strLen << 2) + vectorLen;
    371         // Grow the vector. This will change the value of v.size() but we
    372         // remember the original size above.
    373         v.grow(length);
    374         // Grab the position to write to.
    375         char* data = v.begin() + vectorLen;
    376         // Write the actual string
    377         int l = SkUTF16_ToUTF8(str.characters(), strLen, data);
    378         LOGV("Writing string       %d %.*s", l, l, data);
    379         // Go back and write the utf8 length. Subtract sizeof(unsigned) from
    380         // data to get the position to write the length.
    381         memcpy(data - sizeof(unsigned), (char*)&l, sizeof(unsigned));
    382         // Shrink the internal state of the vector so we match what was
    383         // actually written.
    384         v.shrink(vectorLen + l);
    385     } else
    386         v.append((char*)&strLen, sizeof(unsigned));
    387 }
    388 
    389 static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item)
    390 {
    391     // Original url
    392     write_string(v, item->originalURLString());
    393 
    394     // Url
    395     write_string(v, item->urlString());
    396 
    397     // Title
    398     write_string(v, item->title());
    399 
    400     // Form content type
    401     write_string(v, item->formContentType());
    402 
    403     // Form data
    404     const WebCore::FormData* formData = item->formData();
    405     if (formData) {
    406         write_string(v, formData->flattenToString());
    407         // save the identifier as it is not included in the flatten data
    408         int64_t id = formData->identifier();
    409         v.append((char*)&id, sizeof(int64_t));
    410     } else
    411         write_string(v, WTF::String()); // Empty constructor does not allocate a buffer.
    412 
    413     // Target
    414     write_string(v, item->target());
    415 
    416     AndroidWebHistoryBridge* bridge = item->bridge();
    417     LOG_ASSERT(bridge, "We should have a bridge here!");
    418     // Screen scale
    419     const float scale = bridge->scale();
    420     LOGV("Writing scale %f", scale);
    421     v.append((char*)&scale, sizeof(float));
    422     const float textWrapScale = bridge->textWrapScale();
    423     LOGV("Writing text wrap scale %f", textWrapScale);
    424     v.append((char*)&textWrapScale, sizeof(float));
    425 
    426     // Scroll position.
    427     const int scrollX = item->scrollPoint().x();
    428     v.append((char*)&scrollX, sizeof(int));
    429     const int scrollY = item->scrollPoint().y();
    430     v.append((char*)&scrollY, sizeof(int));
    431 
    432     // Document state
    433     const WTF::Vector<WTF::String>& docState = item->documentState();
    434     WTF::Vector<WTF::String>::const_iterator end = docState.end();
    435     unsigned stateSize = docState.size();
    436     LOGV("Writing docState     %d", stateSize);
    437     v.append((char*)&stateSize, sizeof(unsigned));
    438     for (WTF::Vector<WTF::String>::const_iterator i = docState.begin(); i != end; ++i) {
    439         write_string(v, *i);
    440     }
    441 
    442     // Is target item
    443     LOGV("Writing isTargetItem %d", item->isTargetItem());
    444     v.append((char)item->isTargetItem());
    445 
    446     // Children count
    447     unsigned childCount = item->children().size();
    448     LOGV("Writing childCount   %d", childCount);
    449     v.append((char*)&childCount, sizeof(unsigned));
    450 }
    451 
    452 static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent)
    453 {
    454     const WebCore::HistoryItemVector& children = parent->children();
    455     WebCore::HistoryItemVector::const_iterator end = children.end();
    456     for (WebCore::HistoryItemVector::const_iterator i = children.begin(); i != end; ++i) {
    457         WebCore::HistoryItem* item = (*i).get();
    458         LOG_ASSERT(parent->bridge(),
    459                 "The parent item should have a bridge object!");
    460         if (!item->bridge()) {
    461             WebHistoryItem* bridge = new WebHistoryItem(static_cast<WebHistoryItem*>(parent->bridge()));
    462             item->setBridge(bridge);
    463             bridge->setActive();
    464         } else {
    465             // The only time this item's parent may not be the same as the
    466             // parent's bridge is during history close. In that case, the
    467             // parent must not have a parent bridge.
    468             WebHistoryItem* bridge = static_cast<WebHistoryItem*>(item->bridge());
    469             WebHistoryItem* parentBridge = static_cast<WebHistoryItem*>(parent->bridge());
    470             LOG_ASSERT(parentBridge->parent() == 0 ||
    471                     bridge->parent() == parentBridge,
    472                     "Somehow this item has an incorrect parent");
    473             bridge->setParent(parentBridge);
    474         }
    475         write_item(v, item);
    476         write_children_recursive(v, item);
    477     }
    478 }
    479 
    480 static bool read_item_recursive(WebCore::HistoryItem* newItem,
    481         const char** pData, int length)
    482 {
    483     if (!pData || length < HISTORY_MIN_SIZE)
    484         return false;
    485 
    486     const WebCore::TextEncoding& e = WebCore::UTF8Encoding();
    487     const char* data = *pData;
    488     const char* end = data + length;
    489     int sizeofUnsigned = (int)sizeof(unsigned);
    490 
    491     // Read the original url
    492     // Read the expected length of the string.
    493     int l;
    494     memcpy(&l, data, sizeofUnsigned);
    495     // Increment data pointer by the size of an unsigned int.
    496     data += sizeofUnsigned;
    497     if (l) {
    498         LOGV("Original url    %d %.*s", l, l, data);
    499         // If we have a length, check if that length exceeds the data length
    500         // and return null if there is not enough data.
    501         if (data + l < end)
    502             newItem->setOriginalURLString(e.decode(data, l));
    503         else
    504             return false;
    505         // Increment the data pointer by the length of the string.
    506         data += l;
    507     }
    508     // Check if we have enough data left to continue.
    509     if (end - data < sizeofUnsigned)
    510         return false;
    511 
    512     // Read the url
    513     memcpy(&l, data, sizeofUnsigned);
    514     data += sizeofUnsigned;
    515     if (l) {
    516         LOGV("Url             %d %.*s", l, l, data);
    517         if (data + l < end)
    518             newItem->setURLString(e.decode(data, l));
    519         else
    520             return false;
    521         data += l;
    522     }
    523     if (end - data < sizeofUnsigned)
    524         return false;
    525 
    526     // Read the title
    527     memcpy(&l, data, sizeofUnsigned);
    528     data += sizeofUnsigned;
    529     if (l) {
    530         LOGV("Title           %d %.*s", l, l, data);
    531         if (data + l < end)
    532             newItem->setTitle(e.decode(data, l));
    533         else
    534             return false;
    535         data += l;
    536     }
    537     if (end - data < sizeofUnsigned)
    538         return false;
    539 
    540     // Generate a new ResourceRequest object for populating form information.
    541     WTF::String formContentType;
    542     WTF::PassRefPtr<WebCore::FormData> formData = NULL;
    543 
    544     // Read the form content type
    545     memcpy(&l, data, sizeofUnsigned);
    546     data += sizeofUnsigned;
    547     if (l) {
    548         LOGV("Content type    %d %.*s", l, l, data);
    549         if (data + l < end)
    550             formContentType = e.decode(data, l);
    551         else
    552             return false;
    553         data += l;
    554     }
    555     if (end - data < sizeofUnsigned)
    556         return false;
    557 
    558     // Read the form data
    559     memcpy(&l, data, sizeofUnsigned);
    560     data += sizeofUnsigned;
    561     if (l) {
    562         LOGV("Form data       %d %.*s", l, l, data);
    563         if (data + l < end)
    564             formData = WebCore::FormData::create(data, l);
    565         else
    566             return false;
    567         data += l;
    568         // Read the identifier
    569         {
    570             int64_t id;
    571             int size = (int)sizeof(int64_t);
    572             memcpy(&id, data, size);
    573             data += size;
    574             if (id)
    575                 formData->setIdentifier(id);
    576         }
    577     }
    578     if (end - data < sizeofUnsigned)
    579         return false;
    580 
    581     // Set up the form info
    582     if (formData != NULL) {
    583         WebCore::ResourceRequest r;
    584         r.setHTTPMethod("POST");
    585         r.setHTTPContentType(formContentType);
    586         r.setHTTPBody(formData);
    587         newItem->setFormInfoFromRequest(r);
    588     }
    589 
    590     // Read the target
    591     memcpy(&l, data, sizeofUnsigned);
    592     data += sizeofUnsigned;
    593     if (l) {
    594         LOGV("Target          %d %.*s", l, l, data);
    595         if (data + l < end)
    596             newItem->setTarget(e.decode(data, l));
    597         else
    598             return false;
    599         data += l;
    600     }
    601     if (end - data < sizeofUnsigned)
    602         return false;
    603 
    604     AndroidWebHistoryBridge* bridge = newItem->bridge();
    605     LOG_ASSERT(bridge, "There should be a bridge object during inflate");
    606     float fValue;
    607     // Read the screen scale
    608     memcpy(&fValue, data, sizeof(float));
    609     LOGV("Screen scale    %f", fValue);
    610     bridge->setScale(fValue);
    611     data += sizeof(float);
    612     memcpy(&fValue, data, sizeofUnsigned);
    613     LOGV("Text wrap scale    %f", fValue);
    614     bridge->setTextWrapScale(fValue);
    615     data += sizeof(float);
    616 
    617     if (end - data < sizeofUnsigned)
    618         return false;
    619 
    620     // Read scroll position.
    621     int scrollX = 0;
    622     memcpy(&scrollX, data, sizeofUnsigned);
    623     data += sizeofUnsigned;
    624     int scrollY = 0;
    625     memcpy(&scrollY, data, sizeofUnsigned);
    626     data += sizeofUnsigned;
    627     newItem->setScrollPoint(IntPoint(scrollX, scrollY));
    628 
    629     if (end - data < sizeofUnsigned)
    630         return false;
    631 
    632     // Read the document state
    633     memcpy(&l, data, sizeofUnsigned);
    634     LOGV("Document state  %d", l);
    635     data += sizeofUnsigned;
    636     if (l) {
    637         // Check if we have enough data to at least parse the sizes of each
    638         // document state string.
    639         if (data + l * sizeofUnsigned >= end)
    640             return false;
    641         // Create a new vector and reserve enough space for the document state.
    642         WTF::Vector<WTF::String> docState;
    643         docState.reserveCapacity(l);
    644         while (l--) {
    645             // Check each time if we have enough to parse the length of the next
    646             // string.
    647             if (end - data < sizeofUnsigned)
    648                 return false;
    649             int strLen;
    650             memcpy(&strLen, data, sizeofUnsigned);
    651             data += sizeofUnsigned;
    652             if (data + strLen < end)
    653                 docState.append(e.decode(data, strLen));
    654             else
    655                 return false;
    656             LOGV("\t\t%d %.*s", strLen, strLen, data);
    657             data += strLen;
    658         }
    659         newItem->setDocumentState(docState);
    660     }
    661     // Check if we have enough to read the next byte
    662     if (data >= end)
    663         return false;
    664 
    665     // Read is target item
    666     // Cast the value to unsigned char in order to make a negative value larger
    667     // than 1. A value that is not 0 or 1 is a failure.
    668     unsigned char c = (unsigned char)data[0];
    669     if (c > 1)
    670         return false;
    671     LOGV("Target item     %d", c);
    672     newItem->setIsTargetItem((bool)c);
    673     data++;
    674     if (end - data < sizeofUnsigned)
    675         return false;
    676 
    677     // Read the child count
    678     memcpy(&l, data, sizeofUnsigned);
    679     LOGV("Child count     %d", l);
    680     data += sizeofUnsigned;
    681     *pData = data;
    682     if (l) {
    683         // Check if we have the minimum amount need to parse l children.
    684         if (data + l * HISTORY_MIN_SIZE >= end)
    685             return false;
    686         while (l--) {
    687             // No need to check the length each time because read_item_recursive
    688             // will return null if there isn't enough data left to parse.
    689             WTF::PassRefPtr<WebCore::HistoryItem> child = WebCore::HistoryItem::create();
    690             // Set a bridge that will not call into java.
    691             child->setBridge(new WebHistoryItem(static_cast<WebHistoryItem*>(bridge)));
    692             // Read the child item.
    693             if (!read_item_recursive(child.get(), pData, end - data)) {
    694                 child.clear();
    695                 return false;
    696             }
    697             child->bridge()->setActive();
    698             newItem->addChildItem(child);
    699         }
    700     }
    701     return true;
    702 }
    703 
    704 // On arm, this test will cause memory corruption since converting char* will
    705 // byte align the result and this test does not use memset (it probably
    706 // should).
    707 // On the simulator, using HistoryItem will invoke the IconDatabase which will
    708 // initialize the main thread. Since this is invoked by the Zygote process, the
    709 // main thread will be incorrect and an assert will fire later.
    710 // In conclusion, define UNIT_TEST only if you know what you are doing.
    711 #ifdef UNIT_TEST
    712 static void unit_test()
    713 {
    714     LOGD("Entering history unit test!");
    715     const char* test1 = new char[0];
    716     WTF::RefPtr<WebCore::HistoryItem> item = WebCore::HistoryItem::create();
    717     WebCore::HistoryItem* testItem = item.get();
    718     testItem->setBridge(new WebHistoryItem(0));
    719     LOG_ASSERT(!read_item_recursive(testItem, &test1, 0), "0 length array should fail!");
    720     delete[] test1;
    721     const char* test2 = new char[2];
    722     LOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!");
    723     delete[] test2;
    724     LOG_ASSERT(!read_item_recursive(testItem, NULL, HISTORY_MIN_SIZE), "Null data should fail!");
    725     // Original Url
    726     char* test3 = new char[HISTORY_MIN_SIZE];
    727     const char* ptr = (const char*)test3;
    728     memset(test3, 0, HISTORY_MIN_SIZE);
    729     *(int*)test3 = 4000;
    730     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length originalUrl should fail!");
    731     // Url
    732     int offset = 4;
    733     memset(test3, 0, HISTORY_MIN_SIZE);
    734     ptr = (const char*)test3;
    735     *(int*)(test3 + offset) = 4000;
    736     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length url should fail!");
    737     // Title
    738     offset += 4;
    739     memset(test3, 0, HISTORY_MIN_SIZE);
    740     ptr = (const char*)test3;
    741     *(int*)(test3 + offset) = 4000;
    742     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length title should fail!");
    743     // Form content type
    744     offset += 4;
    745     memset(test3, 0, HISTORY_MIN_SIZE);
    746     ptr = (const char*)test3;
    747     *(int*)(test3 + offset) = 4000;
    748     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!");
    749     // Form data
    750     offset += 4;
    751     memset(test3, 0, HISTORY_MIN_SIZE);
    752     ptr = (const char*)test3;
    753     *(int*)(test3 + offset) = 4000;
    754     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!");
    755     // Target
    756     offset += 4;
    757     memset(test3, 0, HISTORY_MIN_SIZE);
    758     ptr = (const char*)test3;
    759     *(int*)(test3 + offset) = 4000;
    760     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length target should fail!");
    761     offset += 4; // Scale
    762     // Document state
    763     offset += 4;
    764     memset(test3, 0, HISTORY_MIN_SIZE);
    765     ptr = (const char*)test3;
    766     *(int*)(test3 + offset) = 4000;
    767     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length document state should fail!");
    768     // Is target item
    769     offset += 1;
    770     memset(test3, 0, HISTORY_MIN_SIZE);
    771     ptr = (const char*)test3;
    772     *(char*)(test3 + offset) = '!';
    773     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "IsTargetItem should fail with ! as the value!");
    774     // Child count
    775     offset += 4;
    776     memset(test3, 0, HISTORY_MIN_SIZE);
    777     ptr = (const char*)test3;
    778     *(int*)(test3 + offset) = 4000;
    779     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 kids should fail!");
    780     offset = 36;
    781     // Test document state
    782     delete[] test3;
    783     test3 = new char[HISTORY_MIN_SIZE + sizeof(unsigned)];
    784     memset(test3, 0, HISTORY_MIN_SIZE + sizeof(unsigned));
    785     ptr = (const char*)test3;
    786     *(int*)(test3 + offset) = 1;
    787     *(int*)(test3 + offset + 4) = 20;
    788     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + sizeof(unsigned)), "1 20 length document state string should fail!");
    789     delete[] test3;
    790     test3 = new char[HISTORY_MIN_SIZE + 2 * sizeof(unsigned)];
    791     memset(test3, 0, HISTORY_MIN_SIZE + 2 * sizeof(unsigned));
    792     ptr = (const char*)test3;
    793     *(int*)(test3 + offset) = 2;
    794     *(int*)(test3 + offset + 4) = 0;
    795     *(int*)(test3 + offset + 8) = 20;
    796     LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + 2 * sizeof(unsigned) ), "2 20 length document state string should fail!");
    797     delete[] test3;
    798 }
    799 #endif
    800 
    801 //---------------------------------------------------------
    802 // JNI registration
    803 //---------------------------------------------------------
    804 static JNINativeMethod gWebBackForwardListMethods[] = {
    805     { "nativeClose", "(I)V",
    806         (void*) WebHistoryClose },
    807     { "restoreIndex", "(II)V",
    808         (void*) WebHistoryRestoreIndex }
    809 };
    810 
    811 static JNINativeMethod gWebHistoryItemMethods[] = {
    812     { "inflate", "(I[B)V",
    813         (void*) WebHistoryInflate }
    814 };
    815 
    816 int registerWebHistory(JNIEnv* env)
    817 {
    818     // Get notified of all changes to history items.
    819     WebCore::notifyHistoryItemChanged = historyItemChanged;
    820 #ifdef UNIT_TEST
    821     unit_test();
    822 #endif
    823     // Find WebHistoryItem, its constructor, and the update method.
    824     jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
    825     LOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem");
    826     gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "()V");
    827     LOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor");
    828     gWebHistoryItem.mUpdate = env->GetMethodID(clazz, "update",
    829             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;[B)V");
    830     LOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem");
    831 
    832     // Find the field ids for mTitle and mUrl.
    833     gWebHistoryItem.mTitle = env->GetFieldID(clazz, "mTitle", "Ljava/lang/String;");
    834     LOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem");
    835     gWebHistoryItem.mUrl = env->GetFieldID(clazz, "mUrl", "Ljava/lang/String;");
    836     LOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem");
    837     env->DeleteLocalRef(clazz);
    838 
    839     // Find the WebBackForwardList object and method.
    840     clazz = env->FindClass("android/webkit/WebBackForwardList");
    841     LOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList");
    842     gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem",
    843             "(Landroid/webkit/WebHistoryItem;)V");
    844     LOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem");
    845     gWebBackForwardList.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem",
    846             "(I)V");
    847     LOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem");
    848     gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V");
    849     LOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex");
    850     env->DeleteLocalRef(clazz);
    851 
    852     int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList",
    853             gWebBackForwardListMethods, NELEM(gWebBackForwardListMethods));
    854     return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItem",
    855             gWebHistoryItemMethods, NELEM(gWebHistoryItemMethods));
    856 }
    857 
    858 } /* namespace android */
    859