mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
432 lines
11 KiB
432 lines
11 KiB
#include "project.hpp"
|
|
#pragma hdrstop
|
|
|
|
#include "contain.hpp"
|
|
#include "csite.hpp"
|
|
#include "helpers.hpp"
|
|
|
|
// {C71E9420-E82F-11ce-B6CF-00AA00A74DAF}
|
|
static const GUID CLSID_ScriptIntegrator =
|
|
{ 0xc71e9420, 0xe82f, 0x11ce, { 0xb6, 0xcf, 0x0, 0xaa, 0x0, 0xa7, 0x4d, 0xaf } };
|
|
|
|
// {0BB43480-E20B-11ce-B6CF-00AA00A74DAF}
|
|
static const GUID IID_IScriptIntegration =
|
|
{ 0xbb43480, 0xe20b, 0x11ce, { 0xb6, 0xcf, 0x0, 0xaa, 0x0, 0xa7, 0x4d, 0xaf } };
|
|
|
|
CSite::CSite(HText *text)
|
|
{
|
|
ASSERT(text != NULL);
|
|
|
|
ASSERT(IsWindow(text->tw->win));
|
|
_docWnd = text->tw->win;
|
|
|
|
_dwRef = 0L;
|
|
|
|
// Set our interfaces to NULL
|
|
_pIOleClientSite = NULL;
|
|
_pIOleControlSite = NULL;
|
|
_pIAdviseSink = NULL;
|
|
_pIOleInPlaceSite = NULL;
|
|
_pXObject = NULL;
|
|
_pIOleDispatchAmbientProps = NULL;
|
|
|
|
// Set the script integration interface pointer to NULL.
|
|
_pIntegrator = NULL;
|
|
}
|
|
|
|
CSite::~CSite()
|
|
{
|
|
ASSERT(_pIAdviseSink != NULL && _pIAdviseSink->GetRef() == 0);
|
|
ASSERT(_pIOleControlSite != NULL && _pIOleControlSite->GetRef() == 0);
|
|
ASSERT(_pIOleClientSite != NULL && _pIOleClientSite->GetRef() == 0);
|
|
ASSERT(_pIOleInPlaceSite != NULL && _pIOleInPlaceSite->GetRef() == 0);
|
|
ASSERT(_pIOleDispatchAmbientProps != NULL && _pIOleDispatchAmbientProps->GetRef() == 0);
|
|
|
|
// No need to delete _pXObject. It is a special interface that handles
|
|
// reference counting and deletes itself when the ref count goes to zero.
|
|
|
|
SAFEDELETE(_pIAdviseSink);
|
|
SAFEDELETE(_pIOleClientSite);
|
|
SAFEDELETE(_pIOleControlSite);
|
|
SAFEDELETE(_pIOleInPlaceSite);
|
|
SAFEDELETE(_pIOleDispatchAmbientProps);
|
|
}
|
|
|
|
HRESULT CSite::InitializeSite(const char *name)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
_pIAdviseSink = new (CAdviseSink(this, this));
|
|
if (_pIAdviseSink == NULL)
|
|
goto cleanup;
|
|
|
|
_pIOleClientSite = new (COleClientSite(this, this));
|
|
if (_pIOleClientSite == NULL)
|
|
goto cleanup;
|
|
|
|
_pIOleControlSite = new (COleControlSite(this, this));
|
|
if (_pIOleControlSite == NULL)
|
|
goto cleanup;
|
|
|
|
_pIOleInPlaceSite = new (COleInPlaceSite(this, this));
|
|
if (_pIOleInPlaceSite == NULL)
|
|
goto cleanup;
|
|
|
|
_pXObject = new (CXObject(this, name));
|
|
if (_pXObject == NULL)
|
|
goto cleanup;
|
|
|
|
_pIOleDispatchAmbientProps = new (CAmbientDispatch( this, this));
|
|
if (_pIOleDispatchAmbientProps == NULL)
|
|
goto cleanup;
|
|
|
|
g_Container->AddSite(this, &_SiteCookie);
|
|
AddRef(); // Stay around, jack!
|
|
return S_OK;
|
|
|
|
cleanup:
|
|
SAFERELEASE(_pIAdviseSink);
|
|
SAFERELEASE(_pIOleClientSite);
|
|
SAFERELEASE(_pIOleControlSite);
|
|
SAFERELEASE(_pIOleInPlaceSite);
|
|
SAFERELEASE(_pXObject);
|
|
SAFERELEASE(_pIOleDispatchAmbientProps);
|
|
|
|
return hr;
|
|
}
|
|
|
|
// IUnknown methods
|
|
STDMETHODIMP_(ULONG) CSite::AddRef(void)
|
|
{
|
|
return ++_dwRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CSite::Release(void)
|
|
{
|
|
if (--_dwRef == 0)
|
|
{
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return _dwRef;
|
|
}
|
|
|
|
STDMETHODIMP CSite::QueryInterface(REFIID riid, LPVOID *ppvObj)
|
|
{
|
|
// ppvObj must not be NULL
|
|
ASSERT(ppvObj != NULL);
|
|
|
|
if (ppvObj == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
*ppvObj = NULL;
|
|
|
|
if (IsEqualIID(riid, IID_IUnknown))
|
|
*ppvObj = this;
|
|
else if (IsEqualIID(riid, IID_IOleClientSite))
|
|
*ppvObj = _pIOleClientSite;
|
|
else if (IsEqualIID(riid, IID_IOleControlSite))
|
|
*ppvObj = _pIOleControlSite;
|
|
else if (IsEqualIID(riid, IID_IAdviseSink))
|
|
*ppvObj = _pIAdviseSink;
|
|
else if (IsEqualIID(riid, IID_IOleInPlaceSite))
|
|
*ppvObj = _pIOleInPlaceSite;
|
|
else if (IsEqualIID(riid, IID_IDispatch))
|
|
*ppvObj = _pIOleDispatchAmbientProps;
|
|
else
|
|
return g_Container->QueryInterface(riid, ppvObj); // Delegate to global container object
|
|
|
|
if (*ppvObj != NULL) // Should always be non-NULL at this point, but just to be safe...
|
|
((LPUNKNOWN)*ppvObj)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CSite::Destroy()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// Deactivate the control
|
|
_pXObject->Deactivate();
|
|
_pXObject->Destroy();
|
|
|
|
g_Container->DeleteSite(&_SiteCookie);
|
|
Release(); // Decrement reference count on site object.
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT CSite::CreateEmbedding(CLSID clsid)
|
|
{
|
|
// BUGBUG: Need to check to see if this is really a control before aggregating with x object...
|
|
if (SUCCEEDED(Mpolevtbl->CoCreateInstance(clsid, _pXObject, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)_pXObject->GetInnerUnknown())))
|
|
{
|
|
_pXObject->Initialize();
|
|
return _pXObject->SetClientSite(_pIOleClientSite); // Control will addref the client site interface
|
|
}
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT CSite::ConnectEvents(const char* pSinkID, const char* progid)
|
|
{
|
|
ASSERT((pSinkID != NULL) || (progid != NULL)); // Got to have one or the other...
|
|
|
|
HRESULT hr;
|
|
CLSID clsid;
|
|
if (progid != NULL) // We prefer a ProgID
|
|
hr = ConvertANSIProgIDtoCLSID(progid, &clsid);
|
|
else
|
|
hr = ConvertANSItoCLSID(pSinkID, &clsid);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
DBGOUT("Could not convert SINK id to CLSID");
|
|
return hr;
|
|
}
|
|
|
|
LPDISPATCH pEventSink = NULL;
|
|
|
|
// Instantiate the event sink
|
|
if SUCCEEDED(Mpolevtbl->CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void **)&pEventSink))
|
|
{
|
|
// Load up the glue DLL
|
|
hr = Mpolevtbl->CoCreateInstance(CLSID_ScriptIntegrator, NULL, CLSCTX_INPROC_SERVER, IID_IScriptIntegration, (void **)&_pIntegrator);
|
|
if (SUCCEEDED(hr))
|
|
hr = _pIntegrator->IntegrateUI(g_Container->_pIOleContainer, pEventSink);
|
|
}
|
|
else
|
|
DBGOUT("Could not load script DLL");
|
|
|
|
return hr;
|
|
}
|
|
|
|
void HText_addEmbed(HText *text, const char* pszClsid, const char* events, const char * height, const char *name,
|
|
const char* progid, const char* properties, const char* propertysrc, const char * sink,
|
|
const char* src, const char* width)
|
|
|
|
{
|
|
|
|
ASSERT(text != NULL);
|
|
ASSERT(pszClsid != NULL); // Need to have a CLSID to create!!
|
|
|
|
InitializeContainer();
|
|
PCSite pSite = new (CSite(text));
|
|
|
|
CLSID clsid;
|
|
ConvertANSItoCLSID(pszClsid, &clsid);
|
|
|
|
// Create a new C++ site object
|
|
|
|
if (pSite == NULL)
|
|
return; // Couldn't allocate memory for site object
|
|
else
|
|
pSite->InitializeSite(name); // Initialize the site object.
|
|
|
|
if (SUCCEEDED(pSite->CreateEmbedding(clsid)))
|
|
{
|
|
pSite->_pXObject->Activate();
|
|
|
|
// If this embedding sources out events, hook 'em up!
|
|
// if (sink || progid) pSite->ConnectEvents(sink, progid);
|
|
}
|
|
else
|
|
{
|
|
if (pSite)
|
|
delete pSite;
|
|
return; // Couldn't create embedded object
|
|
}
|
|
|
|
|
|
// If successful, add a new form element;
|
|
if (pSite)
|
|
{
|
|
HText_add_element(text, ELE_EMBED);
|
|
|
|
text->bOpen = FALSE;
|
|
text->w3doc->aElements[text->iElement].form = (struct _form_element *) GTR_MALLOC(sizeof(struct _form_element));
|
|
memset(text->w3doc->aElements[text->iElement].form, 0, sizeof(struct _form_element));
|
|
text->w3doc->aElements[text->iElement].form->iBeginForm = text->iBeginForm;
|
|
text->w3doc->aElements[text->iElement].form->pSite = pSite;
|
|
}
|
|
}
|
|
|
|
|
|
// Callback for destroying site object. After this function executes, the
|
|
// site object is **gone**.
|
|
HRESULT CloseSite(void * ptr)
|
|
{
|
|
// ptr is really a pointer to a CSite class instance
|
|
ASSERT(ptr != NULL);
|
|
|
|
PCSite pSite = (PCSite) ptr;
|
|
pSite->Destroy();
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
#ifdef FEATURE_IMG_THREADS
|
|
#define HIDDEN_X_POS 10000
|
|
#define HIDDEN_Y_POS 0
|
|
BOOL bUnformatted = TRUE;
|
|
int nLastGoodElement = -1;
|
|
int nLastLine;
|
|
#endif
|
|
|
|
// Callback for positioning control during layout.
|
|
HRESULT SetEmbeddedObjectRect(BOOL bUnformatted, struct Mwin *tw, struct _element *el)
|
|
{
|
|
|
|
PCSite pSite = (PCSite) el->form->pSite;
|
|
ASSERT(pSite != NULL);
|
|
|
|
LPOLEOBJECT pObj = pSite->_pXObject->GetObject();
|
|
LPOLEINPLACEOBJECT pOIPO = NULL;
|
|
|
|
if (pObj != NULL)
|
|
{
|
|
pObj->QueryInterface(IID_IOleInPlaceObject, (void **)&pOIPO);
|
|
if (pOIPO)
|
|
{
|
|
RECT rSize;
|
|
SetRectEmpty(&rSize);
|
|
|
|
SIZEL *size = pSite->_pXObject->GetSize();
|
|
|
|
SetRect(&rSize,
|
|
#ifdef FEATURE_IMG_THREADS
|
|
bUnformatted ? HIDDEN_X_POS:el->r.left - tw->offl,
|
|
bUnformatted ? HIDDEN_Y_POS:el->r.top - tw->offt,
|
|
#else
|
|
el->r.left - tw->offl,
|
|
el->r.top - tw->offt,
|
|
#endif
|
|
|
|
(el->r.left + size->cx),
|
|
(el->r.top + size->cy)
|
|
);
|
|
pOIPO->SetObjectRects(&rSize, NULL);
|
|
CopyRect(pSite->_pXObject->GetRect(), &rSize);
|
|
SAFERELEASE(pOIPO);
|
|
}
|
|
SAFERELEASE(pObj);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
struct _line
|
|
{
|
|
#ifdef WIN32
|
|
HDC hdc; /* working var, not really related to a line */
|
|
#endif
|
|
int nLineNum;
|
|
|
|
int iFirstElement; /* in */
|
|
int iLastElement; /* out */
|
|
RECT r; /* left, right, and top go in, bottom comes out */
|
|
int baseline; /* calculated */
|
|
int leading; /* out */
|
|
int nWSBelow; /* Minimum whitespace below the line */
|
|
|
|
int nWSAbove; /* Whitespace above current line */
|
|
int gIndentLevel;
|
|
int gRightIndentLevel;
|
|
int Flags;
|
|
int deferedFloatImgs[10]; // array of defered floating images
|
|
int numDeferedFloatImgs; // count of defered floating images
|
|
};
|
|
|
|
|
|
/* FormatEmbbedObject fills in the r structure which indicated the size of the element. This
|
|
is later used to format each line. This code is called (and essentially copied) from the
|
|
case statement in x_format_one_line in the file reformat.c
|
|
*/
|
|
HRESULT FormatEmbeddedObject(struct _element* pel, int *cThings, BOOL *bNeedsAdjust, int right_margin, struct _line * line, int *x, int *done, int prev_i)
|
|
{
|
|
ASSERT(pel != NULL && cThings != NULL && bNeedsAdjust != NULL);
|
|
ASSERT(pel->form != NULL);
|
|
ASSERT(pel->form->pSite != NULL);
|
|
|
|
PCSite pSite = (PCSite)pel->form->pSite;
|
|
|
|
if (pel->form->pSite == NULL)
|
|
return E_INVALIDARG;
|
|
|
|
/*
|
|
For printing, form controls need to be scaled too
|
|
{
|
|
float fScale;
|
|
|
|
if (pdoc->pStyles->image_res != 72)
|
|
{
|
|
fScale = (float) ((float) pdoc->pStyles->image_res / 96.0);
|
|
siz.cx = (long) (siz.cx * fScale);
|
|
siz.cy = (long) (siz.cy * fScale);
|
|
}
|
|
}
|
|
|
|
*/
|
|
SIZE *size = pSite->_pXObject->GetSize();
|
|
if ((!*cThings) || ((*x + size->cx) <= right_margin))
|
|
{
|
|
// Make sure the rectangle is initialized. Shouldn't matter, but hey!!
|
|
SetRectEmpty(&pel->r);
|
|
pel->r.left = *x;
|
|
pel->r.right = pel->r.left + size->cx;
|
|
pel->r.top = line->r.top;
|
|
pel->r.bottom = pel->r.top + size->cy;
|
|
//
|
|
// Baseline adjusts by 2 because of 3D effect on window controls.
|
|
// Note: This currently isn't used because ALIGN_MIDDLE is always set.
|
|
//
|
|
pel->baseline = pel->r.bottom - 2;
|
|
pel->alignment = ALIGN_MIDDLE;
|
|
|
|
*x += (size->cx);
|
|
if (line->r.bottom < pel->r.bottom)
|
|
{
|
|
line->r.bottom = pel->r.bottom;
|
|
}
|
|
*bNeedsAdjust = TRUE;
|
|
*cThings++;
|
|
XX_DMsg(DBG_TEXT, ("FORM CONTROL: cThings -> %d\n", *cThings));
|
|
}
|
|
else
|
|
{
|
|
line->iLastElement = prev_i;
|
|
*done = 1;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT ShowAllEmbeddings(struct _www *w3doc, struct Mwin *tw, int nCmdShow)
|
|
{
|
|
if (w3doc->elementCount)
|
|
{
|
|
for (int i = 0; i >= 0; i = w3doc->aElements[i].next)
|
|
{
|
|
if (w3doc->aElements[i].form)
|
|
{
|
|
if (w3doc->aElements[i].form->pSite)
|
|
{
|
|
// We've got an embedding here, folks.
|
|
PCSite pSite = (PCSite)w3doc->aElements[i].form->pSite;
|
|
|
|
// There is a new doc window
|
|
pSite->_docWnd = tw->win;
|
|
|
|
if (nCmdShow == SW_HIDE)
|
|
pSite->_pXObject->Hide();
|
|
else if (nCmdShow == SW_SHOW)
|
|
pSite->_pXObject->Show();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|