/* * htmlutil.c - HTML utility functions. */ /* Headers **********/ #include "all.h" #pragma hdrstop #include "htmlutil.h" #include "wc_html.h" /* Module Constants *******************/ #pragma data_seg(DATA_SEG_READ_ONLY) PRIVATE_DATA CCHAR s_cszFileProtocol[] = "file:"; // (- 1) for null terminator. #define FILE_PROTOCOL_LEN (sizeof(s_cszFileProtocol) - 1) #pragma data_seg() /***************************** Private Functions *****************************/ PRIVATE_CODE BOOL IsFileURL(PCSTR pcszURL) { ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR)); return(! _strnicmp(pcszURL, s_cszFileProtocol, FILE_PROTOCOL_LEN)); } /****************************** Public Functions *****************************/ #ifdef DEBUG PUBLIC_CODE BOOL IsValidElementType(UCHAR uchType) { /* Allow any type value. */ return(TRUE); } PUBLIC_CODE BOOL IsValidPCELEMENT(PCELEMENT pcelem) { /* Allow any structure fields. */ return(IS_VALID_READ_PTR(pcelem, CELEMENT)); } PUBLIC_CODE BOOL IsValidPCImageInfo(PCImageInfo pcimginfo) { /* Allow any structure fields. */ return(IS_VALID_READ_PTR(pcimginfo, CImageInfo)); } PUBLIC_CODE BOOL IsValidPCMWIN(PCMWIN pcmwin) { /* Allow any structure fields. */ return(IS_VALID_READ_PTR(pcmwin, CMWIN)); } PUBLIC_CODE BOOL IsValidElementIndex(PCMWIN pcmwin, int iElem) { return(EVAL(iElem >= 0) && EVAL(iElem < pcmwin->w3doc->elementCount)); } PUBLIC_CODE BOOL IsValidHTAtom(HTAtom atom) { return(EVAL(atom != -1) && EVAL(HTAtom_name(atom) != NULL)); } PUBLIC_CODE BOOL IsValidPCPOSITION(PCPOSITION pcpos) { /* Allow any structure fields. */ return(IS_VALID_READ_PTR(pcpos, CPOSITION)); } PUBLIC_CODE BOOL IsValidScreenX(int xScreen) { return(EVAL(xScreen < GetSystemMetrics(SM_CXSCREEN))); } PUBLIC_CODE BOOL IsValidScreenY(int yScreen) { return(EVAL(yScreen < GetSystemMetrics(SM_CYSCREEN))); } #endif /* DEBUG */ PUBLIC_CODE BOOL PositionFromPoint(PCMWIN pcmwin, POINT ptDoc, PPOSITION ppos) { BOOL bResult = FALSE; #ifdef FEATURE_INTL BOOL bDBCS; #endif ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN)); ASSERT(IS_VALID_STRUCT_PTR(&ptDoc, CPOINT)); ASSERT(IS_VALID_WRITE_PTR(ppos, POSITION)); ppos->elementIndex = -1; ppos->offset = -1; if (pcmwin && pcmwin->w3doc && pcmwin->w3doc->elementCount > 0) { int i; PCELEMENT pcelem; RECT elRect; /* * BUGBUG: (Performance) (JCordell 4/1//95) We could iterate through the * line list more quickly than the element list here, and then start the * element search with the first element on the intersected line. */ for (i = 0; i >= 0; i = pcelem->next) { pcelem = &(pcmwin->w3doc->aElements[i]); if ( pcelem->type == ELE_FRAME ) continue; FrameToDoc( pcmwin->w3doc, i, &elRect ); if (PtInRect(&elRect, ptDoc)) { if (pcelem->type == ELE_TEXT) { int ncOffset; PGTRFont pfont; HDC hdc; ncOffset = ptDoc.x - elRect.left; if (IS_FLAG_SET(pcelem->lFlags, ELEFLAG_ANCHOR)) #ifdef FEATURE_INTL pfont = STY_GetCPFont(GETMIMECP(pcmwin->w3doc), pcmwin->w3doc->pStyles, pcelem->iStyle, (pcelem->fontBits | gPrefs.cAnchorFontBits), pcelem->fontSize, pcelem->fontFace, TRUE); #else pfont = STY_GetFont( pcmwin->w3doc->pStyles, pcelem->iStyle, (pcelem->fontBits | gPrefs.cAnchorFontBits), pcelem->fontSize, pcelem->fontFace, TRUE); #endif else #ifdef FEATURE_INTL pfont = STY_GetCPFont(GETMIMECP(pcmwin->w3doc), pcmwin->w3doc->pStyles, pcelem->iStyle, pcelem->fontBits, pcelem->fontSize, pcelem->fontFace, TRUE); #else pfont = STY_GetFont(pcmwin->w3doc->pStyles, pcelem->iStyle, pcelem->fontBits, pcelem->fontSize, pcelem->fontFace, TRUE); #endif hdc = GetDC(pcmwin->win); if (hdc) { HFONT hfontPrev; int ncPos; if (pfont && pfont->hFont) hfontPrev = SelectObject(hdc, pfont->hFont); else hfontPrev = NULL; for (ncPos = 1; ncPos <= pcelem->textLen; ncPos++) { SIZE size; #ifdef FEATURE_INTL // We should handle DBCS 1st byte and 2nd byte as one character. if (IsFECodePage(GETMIMECP(pcmwin->w3doc)) && (bDBCS = IsDBCSLeadByteEx(GETMIMECP(pcmwin->w3doc), *(pcmwin->w3doc->pool+pcelem->textOffset+ncPos-1)))) ++ncPos; if (EVAL(myGetTextExtentPointWithMIME(pcmwin->w3doc->iMimeCharSet, hdc, pcmwin->w3doc->pool + pcelem->textOffset, ncPos, &size)) && size.cx > ncOffset) { ncPos -= (bDBCS) ? 1 : 0; break; } #else if (EVAL(myGetTextExtentPoint(hdc, pcmwin->w3doc->pool + pcelem->textOffset, ncPos, &size)) && size.cx > ncOffset) break; #endif } if (hfontPrev) EVAL(SelectObject(hdc, hfontPrev) != NULL); ReleaseDC(pcmwin->win, hdc); ppos->offset = ncPos - 1; } } else ASSERT(ppos->offset == -1); ppos->elementIndex = i; bResult = TRUE; break; } } } ASSERT((bResult || (EVAL(ppos->elementIndex == -1) && EVAL(ppos->offset == -1))) && IS_VALID_STRUCT_PTR(ppos, CPOSITION)); return(bResult); } PUBLIC_CODE BOOL MWinHasSelection(PCMWIN pcmwin) { BOOL bHasSelection; ASSERT(IS_VALID_STRUCT_PTR(pcmwin, CMWIN)); bHasSelection = (pcmwin && pcmwin->w3doc && pcmwin->w3doc->selStart.elementIndex != -1 && pcmwin->w3doc->selEnd.elementIndex != -1); ASSERT(! bHasSelection || pcmwin->w3doc->elementCount > 0); return(bHasSelection); } PUBLIC_CODE BOOL IsPositionInSelection(PCMWIN pcmwin, PCPOSITION pcpos) { BOOL bInSelection = FALSE; if (MWinHasSelection(pcmwin)) { int i; ASSERT(pcmwin->w3doc->elementCount > 0); i = pcmwin->w3doc->selStart.elementIndex; do { /* Entering selection? */ if (i == pcmwin->w3doc->selStart.elementIndex) { /* Yes. */ if (i == pcpos->elementIndex) bInSelection = (pcmwin->w3doc->selStart.offset == -1 || pcpos->offset == -1 || pcmwin->w3doc->selStart.offset <= pcpos->offset); else bInSelection = TRUE; } /* Leaving selection? */ if (i == pcmwin->w3doc->selEnd.elementIndex) { /* Yes. */ if (i == pcpos->elementIndex) bInSelection = (bInSelection && (pcmwin->w3doc->selStart.offset == -1 || pcpos->offset == -1 || pcmwin->w3doc->selEnd.offset > pcpos->offset)); else bInSelection = FALSE; break; } /* Found wholly selected element? */ if (i == pcpos->elementIndex) /* Yes. */ break; else i = pcmwin->w3doc->aElements[i].next; } while (i != -1); } return(bInSelection); } PUBLIC_CODE BOOL FullyQualifyURL(PCSTR pcszURL, PCSTR pcszBaseURL, PSTR *ppszFullURL) { ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR)); ASSERT(IS_VALID_STRING_PTR(pcszBaseURL, CSTR)); ASSERT(IS_VALID_WRITE_PTR(ppszFullURL, PSTR)); *ppszFullURL = HTParse(pcszURL, pcszBaseURL, (PARSE_PUNCTUATION | PARSE_ACCESS | PARSE_HOST | PARSE_PATH | PARSE_ANCHOR)); ASSERT((*ppszFullURL && IS_VALID_STRING_PTR(*ppszFullURL, STR)) || EVAL(! *ppszFullURL)); return(*ppszFullURL != NULL); } PUBLIC_CODE HRESULT GetURLFileSystemPath(PCSTR pcszURL, PCSTR pcszBaseURL, PSTR szFullPath, UINT ucFullPathBufLen) { HRESULT hr; ASSERT(IS_VALID_STRING_PTR(pcszURL, CSTR)); ASSERT(IS_VALID_STRING_PTR(pcszBaseURL, CSTR)); ASSERT(IS_VALID_WRITE_BUFFER_PTR(szFullPath, STR, ucFullPathBufLen)); if (ucFullPathBufLen > 0) { // Get fully qualified file: URL. if (IsFileURL(pcszURL)) { PSTR pszFullURL; if (FullyQualifyURL(pcszURL, pcszBaseURL, &pszFullURL)) { ASSERT(IsFileURL(pszFullURL)); hr = FullyQualifyPath(pszFullURL + FILE_PROTOCOL_LEN, szFullPath, ucFullPathBufLen); if (hr == S_OK) TRACE_OUT(("GetURLFileSystemPath(): File system path for URL %s is %s.", pszFullURL, szFullPath)); GTR_FREE(pszFullURL); pszFullURL = NULL; } else hr = E_OUTOFMEMORY; } else { PSTR pszCachePath; // Get full path to cached copy of referent. if (pszCachePath = PszGetDCachePath(pcszURL, NULL, NULL)) { ASSERT(IS_VALID_STRING_PTR(pszCachePath, STR)); if (lstrlen(pszCachePath) < ucFullPathBufLen) { lstrcpy(szFullPath, pszCachePath); hr = S_OK; TRACE_OUT(("GetURLFileSystemPath(): Cache path for URL %s is %s.", pcszURL, szFullPath)); } else hr = S_FALSE; GTR_FREE(pszCachePath); pszCachePath = NULL; } else { hr = E_OUTOFMEMORY; } } } else hr = S_FALSE; if (hr != S_OK && ucFullPathBufLen > 0) *szFullPath = '\0'; ASSERT((hr == S_OK && IS_VALID_STRING_PTR(szFullPath, STR) && EVAL(lstrlen(szFullPath) < ucFullPathBufLen)) || (hr != S_OK && EVAL(! ucFullPathBufLen || ! *szFullPath))); return(hr); } PUBLIC_CODE HRESULT GetURLFromHREF(PCMWIN pcmwin, int iElem, PSTR *ppszURL) { HRESULT hr; PCELEMENT pcelem; *ppszURL = NULL; pcelem = &(pcmwin->w3doc->aElements[iElem]); if (EVAL(IS_FLAG_SET(pcelem->lFlags, ELEFLAG_ANCHOR)) && EVAL(pcelem->hrefLen > 0)) { PSTR pszHREF; // (+ 1) for null terminator. if (AllocateMemory(pcelem->hrefLen + 1, &pszHREF)) { // (+ 1) for null terminator. MyLStrCpyN(pszHREF, &(pcmwin->w3doc->pool[pcelem->hrefOffset]), pcelem->hrefLen + 1); ASSERT(IS_VALID_STRING_PTR(pcmwin->w3doc->szActualURL, CSTR)); hr = FullyQualifyURL(pszHREF, pcmwin->w3doc->szActualURL, ppszURL) ? S_OK : E_OUTOFMEMORY; if (hr == S_OK) TRACE_OUT(("GetURLFromHREF(): Element %d's URL is %s.", iElem, *ppszURL)); GTR_FREE(pszHREF); pszHREF = NULL; } else hr = E_OUTOFMEMORY; } else { WARNING_OUT(("GetURLFromHREF(): Unable to retrieve URL for element %d. No HREF.", iElem)); hr = S_FALSE; } ASSERT((hr == S_OK && IS_VALID_STRING_PTR(*ppszURL, STR)) || (hr != S_OK && ! *ppszURL)); return(hr); } PUBLIC_CODE HRESULT GetElementText(PCMWIN pcmwin, int iElem, PSTR *ppszName) { HRESULT hr; PCELEMENT pcelem; *ppszName = NULL; pcelem = &(pcmwin->w3doc->aElements[iElem]); if (pcelem->textLen > 0) { // (+ 1) for null terminator. if (AllocateMemory(pcelem->textLen + 1, ppszName)) { // (+ 1) for null terminator. MyLStrCpyN(*ppszName, &(pcmwin->w3doc->pool[pcelem->textOffset]), pcelem->textLen + 1); hr = S_OK; TRACE_OUT(("GetElementText(): Element %d's text is \"%s\".", iElem, *ppszName)); } else hr = E_OUTOFMEMORY; } else { WARNING_OUT(("GetElementText(): No text for element %d.", iElem)); hr = S_FALSE; } ASSERT((hr == S_OK && IS_VALID_STRING_PTR(*ppszName, STR)) || (hr != S_OK && ! *ppszName)); return(hr); } PUBLIC_CODE int OpenLink(PMWIN pmwin, int iElem, DWORD dwFlags) { int nResult; PSTR pszURL; ASSERT(IS_VALID_STRUCT_PTR(pmwin, CMWIN)); ASSERT(IsValidElementIndex(pmwin, iElem)); ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_OPENLINK_FLAGS)); if (GetURLFromHREF(pmwin, iElem, &pszURL) == S_OK) { if (IS_FLAG_SET(dwFlags, OPENLINK_FL_NEW_WINDOW)) nResult = GTR_NewWindow(pszURL, pmwin->request->referer, 0, 0, 0, NULL, NULL); else nResult = TW_LoadDocument(pmwin, pszURL, TW_LD_FL_RECORD, NULL, pmwin->request->referer); GTR_FREE(pszURL); pszURL = NULL; } return(nResult); } PUBLIC_CODE BOOL ElementIsImagePlaceHolder(PCELEMENT pcelem) { ASSERT(IS_VALID_STRUCT_PTR(pcelem, CELEMENT)); return((pcelem->type == ELE_IMAGE || pcelem->type == ELE_FORMIMAGE) && EVAL(pcelem->myImage != NULL) && IS_FLAG_SET(pcelem->myImage->flags, (IMG_ERROR | IMG_MISSING | IMG_NOTLOADED)) && EVAL(IS_FLAG_CLEAR(pcelem->myImage->flags, IMG_LOADING))); } PUBLIC_CODE BOOL ElementIsValidImage(PCELEMENT pcelem) { BOOL bResult; ASSERT(IS_VALID_STRUCT_PTR(pcelem, CELEMENT)); bResult = ((pcelem->type == ELE_IMAGE || pcelem->type == ELE_FORMIMAGE) && EVAL(pcelem->myImage != NULL) && IS_FLAG_CLEAR(pcelem->myImage->flags, (IMG_ERROR | IMG_MISSING | IMG_NOTLOADED | IMG_LOADING))); TRACE_OUT(("ElementIsValidImage(): Element %s a valid image.", bResult ? "is" : "is not")); return(bResult); } PUBLIC_CODE BOOL LoadImageFromPlaceholder(PMWIN pmwin, int iElem) { BOOL bResult = FALSE; PCELEMENT pcelem; ASSERT(IS_VALID_STRUCT_PTR(pmwin, CMWIN)); ASSERT(IS_VALID_STRUCT_PTR(pmwin, CMWIN)); ASSERT(IsValidElementIndex(pmwin, iElem)); pcelem = &(pmwin->w3doc->aElements[iElem]); if (EVAL(ElementIsImagePlaceHolder(pcelem))) { struct Params_Image_LoadAll *pila; if (AllocateMemory(sizeof(*pila), &pila)) { #ifdef FEATURE_IMG_THREADS pila->tw = pmwin; pila->bLocalOnly = FALSE; pila->bNoImageCache = FALSE; pila->decoderObject = NULL; pila->parentThread = NULL; pila->bJustOne = TRUE; pila->nEl = iElem; /* Image_LoadAll_Async() tolerates pila->tw not being GIMGMASTER. */ bResult = (Async_StartThread(Image_LoadAll_Async, pila, pmwin) != NULL); #else pila->tw = pmwin; pil->bLocalOnly = FALSE; pil->nEl = iElem; bResult = (Async_StartThread(Image_LoadOneImage_Async, pila, pmwin) != NULL); #endif /* FEATURE_IMG_THREADS */ BHBar_SetStatusField(pmwin, NULL); TBar_UpdateTBar(pmwin); } } #ifdef FEATURE_VRML if (!pmwin->w3doc->aElements[iElem].pVrml) { SetFocus(pmwin->hWndFrame); } #else SetFocus(pmwin->hWndFrame); #endif return(bResult); }