Plugin sample study notes

一、 ANP interface
1. ANP interface in android 
a android爲插件提供了額外的NPN函數,稱之爲ANP
b 這些函數是通過傳遞函數指針的方式傳遞給插件的
具體操作方式是通過NPN的GetValue函數
瀏覽器和插件通過頭文件約定好一些值,這些值代表APN函數結構體的指針
c 通過NPN_GetValue插件獲取到了這些結構圖的指針,然後進而得到了各個ANP裏面的函數指針,然後通過這系列函數指針就可以調用系統服務了
d 具體獲取這些指針的過程
a)NPN_GetValue(Npapi.cpp)
b)PluginView::getValueStatic(PluginViewAndroid.cpp)
c)(void)anp_getInterface(variable, value, &error)(PluginViewAndroid.cpp)
調用各個接口的初始化函數進行初始化
2. Android's extra ANPInterface
declaration in "android_npapi.h"
a.ANPLogInterfaceV0
log
b.ANPBitmapInterfaceV0
getPixelPacking
c.ANPMatrixInterfaceV0
newMaxtix\deleteMatrix\getFlags\copy\get3x3\set3x3\setIdentity\preTranslate\postTranslate\preScale\postScale\preSkew\postRotate\preRotate\preConcat\postConcat\invert\mapPoints
d.ANPPathInterfaceV0
newPath\deletePath\copy\equal\reset\isEmpty\getBounds\moveTo\lineTo\quadTo\cublicTo\close\offset\transform
e.ANPTypefaceInterfaceV0
createFromName\createFromTypeface\getRefCount\ref\unref\getStyle\getFontPath\getFontDirectoryPath
f. ANPPaintInterfaceV0
newPaint\deletePaint\getFlags\setFlags\getColor\setColor\getStyle\setStyle\getStrokeWidth\getSrokeMite\getStrokeCap\getStrokeJoin\setStrokeWidth\setStrokeMiter\setStrokeCap\setStrokeJoin\getTextEncoding\getTextAlign\getTextSize\getTextScaleX\getTextSkewX\setTextEncoding\setTextAlign\setTextSize\setTextScaleX\setTextSkewx\getTypeface\setTypeface\measureText\getTextWidths\getFontMetrics
g.ANPCanvasInterfaceV0
newCanvas\deleteCanvas\save\restore\translate\scale\rotate\skew\concat\clipRect\clipPath\getTotalMatrix\getLocalClipBounds\getDeviceClipBounds\drawColor\drawPaint\drawLine\drawRect\drawOval\drawPath\drawPosText\drawBitmap\drawBitmapRect
h.ANPWindowInterfaceV0
setVisibleRects\clearVisibleRects\showKeyboard\requestFullScreen\exitFullScreen\requestCenterFitZoom
i. ANPAudioTrackInterfaceV0
newTrack\deleteTrack\start\pause\stop\isStopped
j.ANPEventInterfaceV0
postEvent
h.ANPSystemInterfaceV0 "ANPSystemInterface.cpp"
anp_getApplicationDataDirectory
anp_loadJavaClass

二、class and function used in Plugin
1. functions 
NP_XX ,DLL functions .defined in the dll to be exported by the dll loader
NPN_XX,browser function
defined in Npapi.cpp (will finally call PluginView's function)
Npruntime.cpp
NPP_XX, Plugin's function, defined in the Plugin.
2.NPObject
class created by Browser and called in the plugin.
PluginObject *obj = browser->createobject (instance, getPluginClass());
struct NPObject {
    NPClass *_class;
    uint32_t referenceCount;
    // Additional space may be allocated here by types of NPObjects
};
struct NPClass
{
    uint32_t structVersion;
    NPAllocateFunctionPtr allocate;
    NPDeallocateFunctionPtr deallocate;
    NPInvalidateFunctionPtr invalidate;
    NPHasMethodFunctionPtr hasMethod;
    NPInvokeFunctionPtr invoke;
    NPInvokeDefaultFunctionPtr invokeDefault;
    NPHasPropertyFunctionPtr hasProperty;
    NPGetPropertyFunctionPtr getProperty;
    NPSetPropertyFunctionPtr setProperty;
    NPRemovePropertyFunctionPtr removeProperty;
    NPEnumerationFunctionPtr enumerate;
    NPConstructFunctionPtr construct;
};
defined in NPruntime.h
3. PluginObject class defined in the Plugin, using NPObject as it's subcalss
typedef struct PluginObject {
    NPObject header;
    NPP npp;
    NPWindow* window;
    PluginType pluginType;
    SubPlugin* activePlugin;
} PluginObject
4. 


三、steps for creating a plugin
a. define NP_Initialize,NP_Shutdown,NP_GetValue,NP_GetMiMEDescription
for "PluginPack"
in NP_Initialize evaluate the NPP_XX function pointer with it's own function
b. define it's NPP_XX function, metioned in a
c. define it's NP class, mainly define and implement the function in NPClass
d. in NPP_New call the browser's createObject function, passing it's NPClass to generate it's own pluginobject
all in all, we need to define 3 set of functions
NP_
NPP
and NPClass's function

四 NPP_New中createObject
NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc,
                char* argn[], char* argv[], NPSavedData* saved){
instance->pdata = browser->createobject (instance, getPluginClass());
PluginObject *obj=static_cast<PluginObject*>(instance->pdata);
}
爲什麼調用createobject返回的指針可以轉換爲一個PluginObject
a createobject 調用的是_NPN_CreateObject,傳入一個NPP和NPClass返回一個NPObject的指針
NPObject *_NPN_CreateObject(NPP npp, NPClass* aClass)
{    ASSERT(aClass);
    if (aClass) {
        NPObject* obj;
        if (aClass->allocate != NULL)
            obj = aClass->allocate(npp, aClass);
        else
            obj = (NPObject*)malloc(sizeof(NPObject));
        if (!obj)
            CRASH();
        obj->_class = aClass;
        obj->referenceCount = 1;
        return obj;
    }
    return 0;
}
NPObject的定義如下
struct NPObject {
    NPClass *_class;
    uint32_t referenceCount;
    // Additional space may be allocated here by types of NPObjects
};在Npruntime.h中
而PluginObject是插件自己定義的一個類
typedef struct PluginObject {
    NPObject header;
    NPP npp;
    NPWindow* window;
    PluginType pluginType;
    SubPlugin* activePlugin;
} PluginObject;
如何保證他們大小相同而且類型可以相互轉換?

關鍵就在於
a)createobject (instance, getPluginClass())的第二個參數,是插件裏面定義的。
所以在函數實現過程中 obj = aClass->allocate(npp, aClass);就是調用的插件的allocate
而在插件的這個函數定義中
PluginObject *newInstance = (PluginObject*) malloc(sizeof(PluginObject));
就是申請了一個PluginObject這麼大小的空間。
b)PluginObject 的定義
第一個元素就是NPObject類型,而且在返回的時候&newInstance->header;返回的是其NPObject 元素的地址。
c )由於 PluginObject  的第一個元素是NPObject,所以它的地址就是PluginObject的地址,所以我們可以直接通過指針進行類型轉換。

五、NPWindow以及其和PluginWidgetAndroid關係
1.
NPWindow定義在npapi.h
typedef struct _NPWindow
{
    void*    window;     /* Platform specific window handle */
    int32    x;            /* Position of top left corner relative */
    int32    y;            /*    to a netscape page.                    */
    uint32    width;        /* Maximum window size */
    uint32    height;
    NPRect    clipRect;    /* Clipping rectangle in port coordinates */
  NPWindowType type; 
} NPWindow;
它是插件對窗口的抽象表示,
對象定義在
a、PluginView.h NPWindow m_npWindow;
b、PluginWidgetAndroid.h NPWindow  m_pluginWindow;
c、 NPWindow* window; 插件內部
在PluginView setNPWindowIfNeeded
同時把m_npWindow設置給插件和m_window.
2. m_window有什麼用?
在PluginViewAndroid中
a 事件處理
PluginView::handleTouchEvent
PluginView::handleMouseEvent
PluginView::handleFocusEvent
PluginView::handleKeyboardEvent
都會調用m_window->sendEvent(evt)
而在 PluginWidgetAndroid::sendEvent
最終調用到了
pkg->pluginFuncs()->event
b 窗口和界面繪製和管理
a)PluginView::handleFocusEvent-》m_window->webViewCore()->contentInvalidate(rect)
b)PluginView::setParent-》m_window->init(c);
c)PluginView::setNPWindowIfNeeded()-》
d)m_window->setWindow(&m_npWindow, m_isTransparent);
e)PluginView::platformSetValue-》m_window->setDrawingModel 和m_window->updateEventFlags(flags)
f)PluginView::invalidateRect
m_window->inval(r, true);
g)PluginView::paint
m_window->setSurfaceClip
m_window->draw

六、窗口模式和非窗口模式插件
1.
windowed plug-in 是繪製在單獨的本地窗口,而不是在它的瀏覽器窗口。包含它的瀏覽器頁面在它的顯示窗口之下。這種窗口自己決定繪製流程。
windowless plug-in 不需要本地窗口,它只需要一個可繪製區域。這個區域要麼是這個瀏覽器窗口,要麼是一個屏幕位圖。可繪製區域的具體定義取決於平臺。

在NPWindow結構體中,有一個變量NPWindowType type;來定義插件屬於哪種模型在PluginViewAndroid的platformInit()對於該結構體直接賦值
m_npWindow.type = NPWindowTypeDrawable
m_isWindowed = false;//we don't support windowed yet.
見android的註釋

2.NP's drawing mode.
不管窗口模式還是非窗口模式Android都有如下幾種繪製模式
kBitmap_ANPDrawingModel
kSurface_ANPDrawingModel
kOpenGL_ANPDrawingModel

3.對於surface繪製模式插件的surface如何關聯到java的view
a.獲取surface
a)in PluginWidgetAndroid::layoutSurface
jobject pluginSurface;
pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue,
static_cast<void*>(&pluginSurface));
調用插件的函數,獲取surface賦值給jobject
具體調用過程:
call pluginFuncs()->getvalue(instance, kJavaSurface_ANPGetValue)
在插件裏面調用jobject PaintPlugin::getSurface()
*surface = plugin->getSurface();
b) 在插件PaintPlugin::getSurface()
 m_surface = env->NewGlobalRef(paintSurface);
通過JNI獲取java PaintSurface的實例
b.將surface賦值到Webview的view中
通過a步驟,插件java的view已經保持在pluginSurface中,
1) in PluginWidgetAndroid::layoutSurface
jobject tempObj = m_core->addSurface(pluginSurface,
                m_pluginWindow->x, m_pluginWindow->y,
                m_pluginWindow->width, m_pluginWindow->height);
調用webcore的方法WebViewCore::addSurface (WebviewCore.cpp)
2)in "WebViewCore::addSurface"
 jobject result = env->CallObjectMethod(m_javaGlue->object(env).get(),
                                       m_javaGlue->m_addSurface,
                                        view, x, y, width, height);
調用WebViewCore.java's addSurface
3)private ViewManager.ChildView addSurface(View pluginView, int x, int y, ....)
ViewManager.ChildView view = mWebView.mViewManager.createView();
view.mView pluginView;
view.attachView(x, y, width, height);
4) in ViewManager.attachView
mWebView.addView(mView);
所以就把插件中的java jobject實例加入到了webview中


七、other
1.m_pluginFuncs在何時被調用?
a PluginStream中會被調用
b PluginView::start() 調用newp
c PluginView::stop() 調用setwindow和destroy
d PluginView::performRequest把 函數實例傳給PluginStream,並且調用urlnotify
e PluginView::bindingInstance() 調用getvalue
f PluginView::getNPObject 調用getvalue
g PluginView::didReceiveResponse,創建stream,並且調用PluginStream的didReceiveResponse
h PluginView::setNPWindowIfNeeded() 調用setwindow
i PluginWidgetAndroid::draw() 調用event
j PluginWidgetAndroid::layoutSurface調用getvalue
k PluginWidgetAndroid::sendEvent調用event

2. PluginStream
Streams can be produced by the browser and consumed by a plug-in instance,
or produced by an instance and consumed by the browser.
Provide an interface for creating families of related or dependent objects without specifying their concrete classes

八、view of plugin
1.NPP是一個結構體,包含兩個void的指針
ndata, the pointer of the browser, usually the PluginView, was valued in PluginView::PluginView.
pdata, the pointer of the plugin, was valued by Plugin in NPP_New, maybe a type of "PluginObject" only could be seen in the plugin.
in Browser, we use NPP as a whole.
2. NPP_Window
is the structure holding a void * window, and it's location.
usually save the point in both Browser and Plugin.
3. PluginObject in Plugin
we usually use type "PluginObject" to describe the "Plugin" in Plugin's code.
It should include at least the information below.
NPP
NPP_Window.
NPObject
所以,一個plugin,必不可少的東西包括
"NPNetscapeFuncs" and "PluginObject" mentioned above.
4. m_windowRect = frameView->contentsToWindow(frameRect())
m_pageRect=m_windowRect
5.pluginView.setParent->PluginView.updatePlginWidget
->PluginViewAndroid.setNPWindowIfNeeded
->PluginWidgetAndroid.setWindow
->PluginWidgetAndroid.layoutSurface
6.PluginWidgetAndroid's m_embededView is a java object.
surfaceview繪製方式是在m_embeddedView這個jobject繪製;opengl全屏模式下也是用這個view繪製。
但是opengl繪製方式(非全屏),沒有對這個embeddedView賦值,只有一個medialayer那它是怎麼繪製的呢?
莫非open每次都能夠在最外層繪製?那是如何做的的呢?
7.對於非全屏
pluginView.setParent->PluginView.updatePlginWidget
->PluginViewAndroid.setNPWindowIfNeeded
->PluginWidgetAndroid.setWindow
會調用到sendSizeAndVisibilityEvents
這裏面會設置繪製大小,向插件發事件。
8.全屏步驟
a、opengl由於embeddedView默認爲null,因此先向插件獲取這個View
b、向插件發生一個全屏消息
c、對於非全屏原來有embeddedView,不過要將之前的從webview detach
d、向webcore發送一個消息,SHOW_FULLSCREEN顯示全屏。通過PluginFullScreenHolder獲取webview的最外層view,將embeddedView給attach上去
9、MediaPlayer
MediaPlay中,唯一重要的類就是MediaTexture
MediaPlayer中方法
a ANativeWindow* MediaLayer::acquireNativeWindowForContent()
b ANativeWindow* MediaLayer::acquireNativeWindowForVideo()
c void MediaLayer::setWindowDimensionsForVideo
d void MediaLayer::releaseNativeWindowForVideo(ANativeWindow* window)
e void MediaLayer::setFramerateCallback
bool MediaLayer::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix)
最終都是調用了MediaTexture的函數
10、
在MediaTexture中,有如下類
a、TextureWrapper* m_contentTexture;
b、Vector<TextureWrapper*> m_videoTextures;
c Vector<GLuint> m_unusedTextures;
d sp<ANativeWindow> m_newWindow;
e jobject m_weakWebViewRef;就是傳入的WebView
傳入的WebView jobject有什麼用呢?
a 在MediaTexture::initNativeWindowIfNeeded
調用WebView的sendPluginDrawMsg
最後會調入PluginWidgetAndroid的sendSizeAndVisibilityEvents
b在MediaTexture::requestNativeWindowForVideo
調用WebView的postInvalidate
c 傳給MediaListener,在其onFrameAvailable中調用
調用WebView的postInvalidate
最後會調用View的invalidate
貌似依然沒有解釋,繪在哪裏的問題。
莫非opengl的繪製,真的每次都是在最頂層,只有給它一個區域就行了?全屏時候,設置embeddedView是避免繪製和WebView繪製衝突,所以用一個view覆蓋WebView避免它繪製。然後就完全自己繪製??
11、TextureWrapper
定義裏面包含內容如下:
a GLunit
b SurfaceTexture
c ANativeWindow
d MediaListener
其中,的MediaListener最終持有了傳入的m_weakWebViewRef。
12、ANativeWindow
定義在system\core\include\system\Window.h中
它在TextureWrapper的默認構造函數中被創建
TextureWrapper* videoTexture = createTexture();
m_newWindow = videoTexture->nativeWindow;
在createTexture中
wrapper->nativeWindow = new android::SurfaceTextureClient(wrapper->surfaceTexture);
這是用一個它的子類對其進行實現和初始化。
除此以外它還有如下初始化方式
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface)
這個函數定義在frameworks\base\native\android的Native_window.cpp中


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章