1 /*
   2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 #include "config.h"
   5 
   6 #include "Frame.h"
   7 #include "FrameLoader.h"
   8 #include "BackForwardList.h"
   9 #include "BackForwardController.h"
  10 #include "HistoryItem.h"
  11 #include "Image.h"
  12 #include "JavaEnv.h"
  13 #include "Page.h"
  14 #include "WebPage.h"
  15 
  16 using namespace WebCore;
  17 
  18 #ifdef __cplusplus
  19 extern "C" {
  20 #endif
  21 
  22 static Page* getPage(jlong jpage)
  23 {
  24     return WebPage::pageFromJLong(jpage);
  25 }
  26 
  27 static BackForwardList* getBfl(jlong jpage)
  28 {
  29     return static_cast<WebCore::BackForwardList*>(getPage(jpage)->backForward().client());
  30 }
  31 
  32 static HistoryItem* getItem(jlong jitem)
  33 {
  34     return static_cast<HistoryItem*>(jlong_to_ptr(jitem));
  35 }
  36 
  37 static jmethodID initMethod(JNIEnv* env, jclass cls, char* name, const char* signature)
  38 {
  39     jmethodID mid = env->GetMethodID(cls, name, signature);
  40     ASSERT(mid);
  41     return mid;
  42 }
  43 
  44 static jmethodID initCtor(JNIEnv* env, jclass cls, const char* signature)
  45 {
  46     return initMethod(env, cls, "<init>", signature);
  47 }
  48 
  49 // ENTRY-RELATED METHODS
  50 
  51 static jclass getJEntryClass()
  52 {
  53     JNIEnv* env = WebCore_GetJavaEnv();
  54 
  55     static JGClass jEntryClass(env->FindClass("com/sun/webkit/BackForwardList$Entry"));
  56     ASSERT(jEntryClass);
  57 
  58     return jEntryClass;
  59 }
  60 
  61 static jclass getJBFLClass()
  62 {
  63     JNIEnv* env = WebCore_GetJavaEnv();
  64 
  65     static JGClass jBFLClass(env->FindClass("com/sun/webkit/BackForwardList"));
  66     ASSERT(jBFLClass);
  67 
  68     return jBFLClass;
  69 }
  70 
  71 static JLObject createEntry(HistoryItem* item, jlong jpage)
  72 {
  73 
  74     JNIEnv* env = WebCore_GetJavaEnv();
  75     static jmethodID entryCtorMID = initCtor(env, getJEntryClass(), "(JJ)V");
  76 
  77     JLObject jEntry(env->NewObject(getJEntryClass(), entryCtorMID, ptr_to_jlong(item), jpage));
  78     CheckAndClearException(env);
  79 
  80     item->setHostObject(jEntry);
  81 
  82     return jEntry;
  83 }
  84 
  85 static void notifyHistoryItemChangedImpl(HistoryItem* item) {
  86     JNIEnv* env = WebCore_GetJavaEnv();
  87     static jmethodID notifyItemChangedMID = initMethod(env, getJEntryClass(), "notifyItemChanged", "()V");
  88     if (item->hostObject()) {
  89         env->CallVoidMethod(item->hostObject(), notifyItemChangedMID);
  90         CheckAndClearException(env);
  91     }
  92 }
  93 
  94 void notifyHistoryItemDestroyed(const JLObject &host)
  95 {
  96     WC_GETJAVAENV_CHKRET(env);
  97     static jmethodID notifyItemDestroyedMID =
  98             initMethod(env, getJEntryClass(), "notifyItemDestroyed", "()V");
  99     if (host) {
 100         env->CallVoidMethod(host, notifyItemDestroyedMID);
 101         CheckAndClearException(env);
 102     }
 103 }
 104 
 105 // entry.getURL()
 106 JNIEXPORT jstring JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetURL(JNIEnv* env, jclass z, jlong jitem)
 107 {
 108     HistoryItem* item = getItem(jitem);
 109     String urlString = item->urlString();
 110     return urlString.toJavaString(env).releaseLocal();
 111 }
 112 
 113 // entry.getTitle()
 114 JNIEXPORT jstring JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetTitle(JNIEnv* env, jclass z, jlong jitem)
 115 {
 116     HistoryItem* item = getItem(jitem);
 117     String title = item->title();
 118     return title.toJavaString(env).releaseLocal();
 119 }
 120 
 121 // entry.getIcon()
 122 JNIEXPORT jobject JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetIcon(JNIEnv* env, jclass z, jlong jitem)
 123 {
 124     HistoryItem* item = getItem(jitem);
 125 /*
 126     if (item != NULL) {
 127     // TODO: crashes with DRT
 128         return *WebCore::iconDatabase().synchronousIconForPageURL(item->url(), WebCore::IntSize(16, 16))->nativeImageForCurrentFrame();
 129         Image* icon = item->icon();
 130         if (icon != NULL) {
 131             return *icon->javaImage();
 132         }
 133     }
 134 */
 135     return NULL;
 136 }
 137 
 138 // entry.getLastVisited()
 139 JNIEXPORT jlong JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetLastVisitedDate(JNIEnv* env, jclass z, jlong jitem)
 140 {
 141 //    HistoryItem* item = getItem(jitem);
 142 //    double lastVisitedDate = item->lastVisitedTime();
 143 //    return (jlong) (lastVisitedDate * 1000);
 144     return 0; // todo tav where is lastVisitedDate field?
 145 }
 146 
 147 // entry.isTargetItem()
 148 JNIEXPORT jboolean JNICALL Java_com_sun_webkit_BackForwardList_bflItemIsTargetItem(JNIEnv* env, jclass z, jlong jitem)
 149 {
 150     HistoryItem* item = getItem(jitem);
 151     return (jboolean)item->isTargetItem();
 152 }
 153 
 154 // entry.getTarget()
 155 JNIEXPORT jstring JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetTarget(JNIEnv* env, jclass z, jlong jitem)
 156 {
 157     HistoryItem* item = getItem(jitem);
 158     String target = item->target();
 159     if (!target.isEmpty()) {
 160         return target.toJavaString(env).releaseLocal();
 161     } else {
 162         return NULL;
 163     }
 164 }
 165 
 166 // entry.getChildren()
 167 JNIEXPORT jobjectArray JNICALL Java_com_sun_webkit_BackForwardList_bflItemGetChildren(JNIEnv* env, jclass z, jlong jitem, jlong jpage)
 168 {
 169     HistoryItem* item = getItem(jitem);
 170     if (!item->hasChildren()) {
 171         return NULL;
 172     }
 173     jobjectArray children = env->NewObjectArray(item->children().size(), getJEntryClass(), NULL);
 174     int i = 0;
 175     for (HistoryItemVector::const_iterator it = item->children().begin();
 176      it != item->children().end();
 177      ++it)
 178     {
 179         env->SetObjectArrayElement(children, i++, (jobject)createEntry(&**it, jpage));
 180     }
 181     return children;
 182 }
 183 
 184 // BACKFORWARDLIST METHODS
 185 
 186 static int getSize(BackForwardList* bfl)
 187 {
 188     int size = 0;
 189     if (bfl->currentItem())
 190         size = bfl->forwardListCount() + bfl->backListCount() + 1;
 191     return size;
 192 }
 193 
 194 // BackForwardList.size()
 195 JNIEXPORT jint JNICALL Java_com_sun_webkit_BackForwardList_bflSize(JNIEnv* env, jclass z, jlong jpage)
 196 {
 197     return getSize(getBfl(jpage));
 198 }
 199 
 200 // BackForwardList.getMaximumSize()
 201 JNIEXPORT jint JNICALL Java_com_sun_webkit_BackForwardList_bflGetMaximumSize(JNIEnv* env, jclass z, jlong jpage)
 202 {
 203     BackForwardList* bfl = static_cast<BackForwardList *>(getBfl(jpage));
 204     return bfl->capacity();
 205 }
 206 
 207 // BackForwardList.setMaximumSize()
 208 JNIEXPORT void JNICALL Java_com_sun_webkit_BackForwardList_bflSetMaximumSize(JNIEnv* env, jclass z, jlong jpage, jint size)
 209 {
 210     BackForwardList* bfl = static_cast<BackForwardList *>(getBfl(jpage));
 211     bfl->setCapacity(size);
 212 }
 213 
 214 // BackForwardList.getCurrentIndex()
 215 JNIEXPORT jint JNICALL Java_com_sun_webkit_BackForwardList_bflGetCurrentIndex(JNIEnv* env, jclass z, jlong jpage)
 216 {
 217     BackForwardList* bfl = getBfl(jpage);
 218     return bfl->currentItem() ? bfl->backListCount() : -1;
 219 }
 220 
 221 // BackForwardList.setEnabled()
 222 JNIEXPORT void JNICALL Java_com_sun_webkit_BackForwardList_bflSetEnabled(JNIEnv* env, jclass z, jlong jpage, jboolean flag)
 223 {
 224     BackForwardList* bfl = static_cast<BackForwardList *>(getBfl(jpage));
 225     bfl->setEnabled(flag);
 226 }
 227 
 228 // BackForwardList.isEnabled()
 229 JNIEXPORT jboolean JNICALL Java_com_sun_webkit_BackForwardList_bflIsEnabled(JNIEnv* env, jclass z, jlong jpage)
 230 {
 231     BackForwardList* bfl = static_cast<BackForwardList *>(getBfl(jpage));
 232     return bfl->enabled();
 233 }
 234 
 235 static HistoryItem* itemAtIndex(BackForwardList* bfl, int index)
 236 {
 237     // Note: WebKit counts from the *current* position
 238     return bfl->itemAtIndex(index - bfl->backListCount());
 239 }
 240 
 241 // BackForwardList.get()
 242 JNIEXPORT jobject JNICALL Java_com_sun_webkit_BackForwardList_bflGet(JNIEnv* env, jclass z, jlong jpage, jint index)
 243 {
 244     BackForwardList* bfl = getBfl(jpage);
 245     HistoryItem* item = itemAtIndex(bfl, index);
 246     if (!item)
 247         return 0;
 248     JLObject host(item->hostObject());
 249     if (!host) {
 250         host = createEntry(item, jpage);
 251     }
 252     return host.releaseLocal();
 253 }
 254 
 255 // BackForwardList.setCurrentIndex()
 256 JNIEXPORT jint JNICALL Java_com_sun_webkit_BackForwardList_bflSetCurrentIndex(JNIEnv* env, jclass z, jlong jpage, jint index)
 257 {
 258     Page* page = getPage(jpage);
 259     BackForwardList* bfl = static_cast<BackForwardList*>(page->backForward().client());
 260     if (index < 0 || index >= getSize(bfl))
 261         return -1;
 262     int distance = index - bfl->backListCount();
 263     page->backForward().goBackOrForward(distance);
 264     return index;
 265 }
 266 
 267 // BackForwardList.get[Last]IndexOf()
 268 JNIEXPORT jint JNICALL Java_com_sun_webkit_BackForwardList_bflIndexOf(JNIEnv* env, jclass z, jlong jpage, jlong jitem, jboolean reverse)
 269 {
 270     if (!jitem)
 271         return -1;
 272     BackForwardList* bfl = getBfl(jpage);
 273     int size = getSize(bfl);
 274     int start = reverse ? size - 1 : 0;
 275     int end = reverse ? -1 : size;
 276     int inc = reverse ? -1 : 1;
 277     HistoryItem* item = static_cast<HistoryItem*>(jlong_to_ptr(jitem));
 278     for (int i = start; i != end; i += inc)
 279         if (item == itemAtIndex(bfl, i))
 280             return i;
 281     return -1;
 282 }
 283 
 284 JNIEXPORT void JNICALL Java_com_sun_webkit_BackForwardList_bflSetHostObject(JNIEnv* env, jclass z, jlong jpage, jobject host)
 285 {
 286     BackForwardList* bfl = getBfl(jpage);
 287     bfl->setHostObject(JLObject(host, true));
 288 
 289     notifyHistoryItemChanged = notifyHistoryItemChangedImpl;
 290 }
 291 
 292 #ifdef __cplusplus
 293 }
 294 #endif
 295 
 296 namespace WebCore {
 297 
 298 // ChangeListener support
 299 void notifyBackForwardListChanged(const JLObject &host)
 300 {
 301     JNIEnv* env = WebCore_GetJavaEnv();
 302 
 303     if (!host) {
 304         return;
 305     }
 306 
 307     static jmethodID notifyChangedMID = initMethod(
 308         env,
 309     getJBFLClass(),
 310         "notifyChanged",
 311         "()V");
 312     ASSERT(notifyChangedMID);
 313 
 314     env->CallVoidMethod(host, notifyChangedMID);
 315     CheckAndClearException(env);
 316 }
 317 
 318 } // namespace WebCore