diff -r 000000000000 -r dd21522fd290 webengine/osswebengine/WebKit/s60/misc/WebUtil.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/webengine/osswebengine/WebKit/s60/misc/WebUtil.cpp Mon Mar 30 12:54:55 2009 +0300 @@ -0,0 +1,776 @@ +/* +* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Frame in webkit side +* +*/ + +#include "config.h" + +#include "BrCtl.h" +#include "Frame.h" +#include "Cache.h" +#include "DocLoader.h" +#include "IntPoint.h" +#include "String.h" +#include "HTMLNames.h" +#include "EventNames.h" +#include "HTMLInputElement.h" +#include "Document.h" +#include "WebFrame.h" +#include "WebFrameView.h" +#include "WebCursor.h" +#include "WebView.h" +#include "FrameView.h" +#include "RenderImage.h" +#include "IntRect.h" +#include "FloatRect.h" +#include "Image.h" +#include "HTMLImageElement.h" +#include "StaticObjectsContainer.h" +#include "SelectionController.h" +#include "WebUtil.h" +#include "errordefs.h" +#include "RenderListBox.h" +#include "RenderTextControl.h" +#include "RenderView.h" +#include "PlatformScrollbar.h" +#include "HTMLSelectElement.h" +#include "webkitlogger.h" +#include +#include +#include +#include +#include + +using namespace WebCore; +using namespace EventNames; +using namespace HTMLNames; + +static const char* KTel = "tel:"; +static const char* KMailto = "mailto:"; +static const char* KWtai = "wtai:"; +static const char* KWtaiMC = "wtai://wp/mc;"; +static const char* KWtaiAP = "wtai://wp/ap;"; +static const char* KWtaiSD = "wtai://wp/sd;"; + +_LIT(KPathBegin,""); +_LIT(KMimeWBMP, "image/vnd.wap.wbmp"); +_LIT(KMimeOTA, "image/vnd.nokia.ota-bitmap"); + +TBrCtlDefs::TBrCtlElementType nodeTypeB(Node* node, Frame* frame) +{ + if( !node || !node->isElementNode() ) + return TBrCtlDefs::EElementNone; + + TBrCtlDefs::TBrCtlElementType elType(TBrCtlDefs::EElementNone); + HTMLElement *e = static_cast(node); + + // get the right element type + if ( e->hasLocalName(linkTag) ) { + elType = TBrCtlDefs::EElementAnchor; + } + else if ( e->hasLocalName(aTag) ) { + elType = TBrCtlDefs::EElementAnchor; + + String href = e->getAttribute( hrefAttr ); + if (!href.isNull()) { + + if( href.startsWith( KTel ) ) { + elType = TBrCtlDefs::EElementTelAnchor; + } + else if( href.startsWith( KWtai ) ) { + + if( href.startsWith( KWtaiMC ) || href.startsWith(KWtaiAP) || href.startsWith(KWtaiSD) ) { + elType = TBrCtlDefs::EElementTelAnchor; + } + + } + else if( href.startsWith( KMailto ) ) { + elType = TBrCtlDefs::EElementMailtoAnchor; + } + + + } + else if (!e->getAttribute( ctiAttr ).isNull()) { + elType = TBrCtlDefs::EElementTelAnchor; + } + else if( e->hasLocalName(areaTag) ) { + + elType = TBrCtlDefs::EElementInputBox; + } + } + else if (e->isControl()) { + HTMLGenericFormElement* ie = static_cast( e ); + // default for form element + elType = TBrCtlDefs::EElementInputBox; + if (ie->type() == "radio") + elType = ((HTMLInputElement*)ie)->checked() ? TBrCtlDefs::EElementRadioButtonSelected : TBrCtlDefs::EElementRadioButtonUnSelected; + else if (ie->type() == "checkbox") + elType = ((HTMLInputElement*)ie)->checked() ? TBrCtlDefs::EElementCheckBoxChecked : TBrCtlDefs::EElementCheckBoxUnChecked; + else if (ie->type() == "button" || ie->type() == "reset" || ie->type() == "submit") + elType = TBrCtlDefs::EElementButton; + else if (ie->type() == "file") { + if (((HTMLInputElement*)ie)->value() == String()) + elType = TBrCtlDefs::EElementFileSelectionBoxNoContent; + else + elType = TBrCtlDefs::EElementFileSelectionBoxWithContent; + } + else if (ie->type() == "select-multiple") + elType = TBrCtlDefs::EElementSelectMultiBox; + else if ( ie->type() == "select-one") { + if(!e->getAttribute(sizeAttr).isNull() && !(e->getAttribute(sizeAttr) == "1")) { + elType = TBrCtlDefs::EElementSelectMultiBox; + } + else { + elType = TBrCtlDefs::EElementSelectBox; + } + } + else if (ie->type() == "textarea") + elType = TBrCtlDefs::EElementTextAreaBox; + } + else if( e->hasLocalName(objectTag) || e->hasLocalName(embedTag) ) { + if( e->renderer() && e->renderer()->isWidget() ) + if(node->active()) + elType = TBrCtlDefs::EElementActivatedObjectBox; + else + elType = TBrCtlDefs::EElementObjectBox; + else + elType = TBrCtlDefs::EElementNone; + } + + // change to activated input box + WebView* v = control(frame)->webView(); + if ((elType == TBrCtlDefs::EElementInputBox || elType == TBrCtlDefs::EElementTextAreaBox) && v && v->isEditable()) + elType = TBrCtlDefs::EElementActivatedInputBox; + + return elType; +} + + +WebFrame* frameAndPointUnderCursor(IntPoint& p_, WebView& v_) +{ + WebFrameView* mfv = v_.mainFrame()->frameView(); + p_ = StaticObjectsContainer::instance()->webCursor()->position(); + WebFrame* frame = v_.mainFrame()->frameAtPoint(p_); + if (!frame) + frame = v_.mainFrame(); + IntPoint rc = frame->frameView()->rectInGlobalCoords().iTl; + p_ = frame->frameView()->viewCoordsInFrameCoords(p_); + return frame; +} + +String getNodeUrlAtPointInFrame(WebFrame& f_, IntPoint& p_) +{ + Document* doc = core(&f_)->document(); + if (doc) { + Node* node = doc->elementFromPoint(p_.x(), p_.y()); + + if (node) { + if (node->hasTagName(areaTag)) { + HTMLElement* e = static_cast(node); + if(!e->getAttribute(hrefAttr).isNull()) { + return e->getAttribute(hrefAttr); + } + } + // get the navigable node at this point + Node* n = node; + for (; n; n = n->parentNode()) + if (n->isFocusable() && n->isElementNode()) + break; + + if (n && n->isFocusable() && n->isElementNode()) { + HTMLElement* e = static_cast(n); + if (!e->getAttribute(hrefAttr).isNull()) { + return e->getAttribute(hrefAttr); + } + } + } + } + return String(); +} + + +int imageCountInFrame(WebFrame& wf_, bool visibleOnly_) +{ + int count = 0; + Frame* f = core(&wf_); + + if (!f || !f->document() || !f->document()->renderer()) + return count; + + Document* doc = f->document(); + RefPtr collection = doc->images(); + + FrameView* v = doc->view(); + IntRect r1 = wf_.frameView()->topView()->mainFrame()->frameView()->rect(); + + for (Node *n = collection->firstItem(); n; n = collection->nextItem()) { + + RenderImage* render = static_cast(n->renderer()); + if (render) { + + Image* img = render->image(); + if (!img->isNull() && img->data()) { + //if visible only is true, check for intersection + bool processing = true; + if (visibleOnly_) { + IntRect imageRect; + IntPoint tl = wf_.frameView()->frameCoordsInViewCoords(n->getRect().topLeft()); + IntPoint br = wf_.frameView()->frameCoordsInViewCoords(n->getRect().bottomRight()); + imageRect.setLocation(tl); + imageRect.setSize(br-tl); + + processing = r1.intersects(imageRect); + } + if (processing) { + String alttext = static_cast(render->element())->altText(); + // Check if alttext is "Nokia" or "No_save". + // Then do not count + if (!(equalIgnoringCase(alttext, "nokia") || equalIgnoringCase(alttext, "no_save"))) + ++count; + } + } + } + + } + return count; +} + +CArrayFixFlat* imagesInFrame(WebFrame& wf_, bool visibleOnly_) +{ + CArrayFixFlat* imglist = new CArrayFixFlat(10); + Frame* f = core(&wf_); + + if (!f || !f->document() || !f->document()->renderer()) + return imglist; + + CleanupStack::PushL(imglist); + + Document* doc = f->document(); + FrameView* v = doc->view(); + IntRect r1 = wf_.frameView()->topView()->mainFrame()->frameView()->rect(); + + + RefPtr collection = doc->images(); + for (Node* n = collection->firstItem(); n; n = collection->nextItem()) { + + RenderImage* render = static_cast(n->renderer()); + if (render) { + Image* img = render->image(); + if (!img->isNull() && img->data()) { + //if visible only is true, check for intersection + TBool processing = ETrue; + if (visibleOnly_) { + IntRect imageRect; + IntPoint tl = wf_.frameView()->frameCoordsInViewCoords(n->getRect().topLeft()); + IntPoint br = wf_.frameView()->frameCoordsInViewCoords(n->getRect().bottomRight()); + imageRect.setLocation(tl); + imageRect.setSize(br-tl); + + processing = r1.intersects(imageRect); + } + if (processing) { + String alttext = static_cast(render->element())->altText(); + TBrCtlImageType type = EImageTypeAny; + if (img->getMimeType().find("image/vnd.wap.wbmp") == 0) + type = EImageTypeWbmp; + else if (img->getMimeType().find("image/vnd.nokia.ota-bitmap") == 0) + type = EImageTypeOta; + // + TBrCtlImageCarrier tImg(TPtrC8((const TUint8*)img->data()->data(),img->data()->size()), + static_cast(render->element())->getAttribute(srcAttr), + alttext, type, img->getMimeType()); + + // Check if alttext is "Nokia" or "No_save". + // Then do not add the image to the list + if (!(equalIgnoringCase(alttext, "nokia") || equalIgnoringCase(alttext, "no_save"))) { + // Check if this image has been retrieved before. + // Image pointer should be the same for similar images + TBool imgexists = false; + for (int i=0; iCount();i++) { + TBrCtlImageCarrier wcImage = imglist->At(i); + if (tImg.RawData() == wcImage.RawData()) { + imgexists = true; + break; + } + + } + if (!imgexists) + imglist->AppendL(tImg); + } + } + } + } + } + CleanupStack::Pop(imglist); + return imglist; +} + +CArrayFixFlat* findSubscribeToInFrame(WebFrame& wf_) +{ + CArrayFixFlat* linkList = new CArrayFixFlat(10); + Frame* f = core(&wf_); + + if (!f || !f->document()) + return linkList; + + CleanupStack::PushL(linkList); + for (Node *n = f->document(); n; n = n->traverseNextNode()) { + if (n->isElementNode() && n->hasTagName(linkTag)) { + + HTMLElement* e = static_cast(n); + String type = e->getAttribute(typeAttr); + + if (type == "application/rss+xml" || type == "application/atom+xml" || + type == "text/xml" || type == "application/xml") { + String href = e->getAttribute(hrefAttr); + String title = e->getAttribute(titleAttr); + + TBrCtlSubscribeTo item(title.des(), href.des(), 0); + linkList->AppendL(item); + } + } + } + CleanupStack::Pop(linkList); + return linkList; +} + +int focusedImage(WebView* webView, TBrCtlImageCarrier*& imageCarrier) +{ + int ret = KErrNone; + TBrCtlImageCarrier* t = NULL; + RenderImage *r = renderImageUnderCursor(webView); + if (r) { + Image* img = r->image(); + CachedImage* ci = r->cachedImage(); + if( ci && !img->isNull()) { + SharedBuffer* imgData = img->data(); + if (imgData) { + TPtrC8 rawData((const unsigned char*)(imgData->data()), (imgData->size())); + // Check if there is data in the image buffer. + // Broken links do not have data in them + if (rawData.Length() > 0) { + // Get the alt text + String alttext = static_cast(r->element())->altText(); + // Check if alttext is "Nokia" or "No_save". + // Then do not add the image to the list + if (!(equalIgnoringCase(alttext, "nokia") || equalIgnoringCase(alttext, "no_save"))) { + TBrCtlImageType brCtlTtype = EImageTypeAny; + if( img->getMimeType().des().Find(KMimeWBMP) != KErrNotFound ) { + brCtlTtype = EImageTypeWbmp; + } + else if ( img->getMimeType().des().Find(KMimeOTA) != KErrNotFound ) { + brCtlTtype = EImageTypeOta; + } + t = new TBrCtlImageCarrier(TPtrC8((const TUint8*)img->data()->data(),img->data()->size()), + static_cast(r->element())->getAttribute(srcAttr), + alttext, brCtlTtype, img->getMimeType()); + if (!t) { + ret = KErrNoMemory; + } + else { + ret = KErrNone; + } + } + else { + ret = KErrAccessDenied; + } + } // if (rawData.Length() > 0) + else { + ret = KErrNotFound; + } + } + else { + ret = KErrNotFound; + } + } // if (ci) + else { + ret = KErrNotFound; + } + } // if (r) + else { + ret = KErrNoMemory; + } + imageCarrier = t; + return ret; +} + +void loadFocusedImage(WebView* webView) +{ + RenderImage *r = renderImageUnderCursor(webView); + if (r) { + CachedImage* ci = r->cachedImage(); + if (ci && ci->status() == CachedResource::Unknown) { + IntPoint p; + WebFrame* frame = frameAndPointUnderCursor(p, *webView); + cache()->loader()->load(core(frame)->document()->docLoader(), ci, true); + } + } +} + +RenderImage* renderImageUnderCursor(WebView* webView) +{ + IntPoint p; + WebFrame* frame = frameAndPointUnderCursor(p, *webView); + Frame* f = core(frame); + RenderImage* render = NULL; + if (!f || !f->document() || !f->document()->renderer()) + return NULL; + Document* doc = f->document(); + FrameView* v = doc->view(); + RefPtr collection = doc->images(); + for (Node* n = collection->firstItem(); n; n = collection->nextItem()) { + render = static_cast(n->renderer()); + if (render) { + Image* img = render->image(); + if (!img->isNull()) { + //if visible only is true, check for intersection + if (n->getRect().contains(p)) { + return render; + } + } + } + } + return NULL; +} + +HBufC* generateFrameName() +{ + HBufC* name = NULL; + name = HBufC::New(60); + if (name) { + TPtr path = name->Des(); + path.Copy(KPathBegin); + TBuf<20>timeBuf; + TTime ttime; + ttime.HomeTime(); + timeBuf.Num(ttime.Int64()); + path.Append(timeBuf); + path.Append(KPathEnd); + } + return name; +} + + +void addOneMenuItemAfter(CEikMenuPane& menuPane, unsigned int after, int command, int resourceId, unsigned int commandBase) +{ + CEikMenuPaneItem::SData item; + HBufC* buf = StringLoader::LoadLC(resourceId); + item.iText.Copy(*buf); + CleanupStack::PopAndDestroy(); // buf + buf = NULL; + item.iCommandId = command + commandBase; + item.iFlags = 0; + item.iCascadeId = 0; + menuPane.AddMenuItemL(item, after); +} + +void insertOneMenuItem(CEikMenuPane& menuPane, int command, int resourceId, unsigned int commandBase) +{ + CEikMenuPaneItem::SData item; + HBufC* buf = StringLoader::LoadLC(resourceId); + item.iText.Copy(*buf); + CleanupStack::PopAndDestroy(); // buf + buf = NULL; + item.iCommandId = command + commandBase; + item.iFlags = 0; + item.iCascadeId = 0; + menuPane.InsertMenuItemL(item, 0); +} + +int textMultiplier(int fontLevel, int originalSize) +{ + int sizeMultiplier = originalSize; + switch(fontLevel) + { + case TBrCtlDefs::EFontSizeLevelAllSmall: + // show text 40% smaller than the declared size + sizeMultiplier *= 0.6; + break; + case TBrCtlDefs::EFontSizeLevelSmaller: + // show text 20% smaller than the declared size + sizeMultiplier *= 0.8; + break; + default: + case TBrCtlDefs::EFontSizeLevelNormal: + break; + case TBrCtlDefs::EFontSizeLevelLarger: + // show text 25% larger than the declared size + sizeMultiplier *= 1.25; + break; + case TBrCtlDefs::EFontSizeLevelAllLarge: + // show text 50% larger than the declared size + sizeMultiplier *= 1.50; + break; + } + return sizeMultiplier; +} + +static void handleSpecialSchemeL(String url, CBrCtl* brctl) +{ + // only the url is supported currently + RArray typeArray; + CDesCArrayFlat* strArray = new CDesCArrayFlat( 1 ); + if (strArray) { + // add url id + typeArray.Append( EParamRequestUrl ); + // add url string + TRAPD(err, strArray->AppendL( url.des() )); + if (err == KErrNone) { + TRAP_IGNORE(brctl->brCtlSpecialLoadObserver()->HandleRequestL( &typeArray, strArray )); + } + delete strArray; + } +} + +void addFocusedUrlToContacts(WebView* webView) +{ + if (webView->brCtl()->brCtlSpecialLoadObserver()) { + IntPoint point; + WebFrame* frame = frameAndPointUnderCursor(point, *webView); + if (frame) { + Document* doc = core(frame)->document(); + if (doc) { + Node* node = doc->elementFromPoint(point.x(), point.y()); + if (node) { + // get the navigable node at this point + Node* n = node; + for (; n; n = n->parentNode()) + if (n->isFocusable() && n->isElementNode()) + break; + + if (n && n->isFocusable() && n->isElementNode()) { + HTMLElement* e = static_cast(n); + String tel; + String email; + String telbook; + // href + String attr = e->getAttribute(hrefAttr); + if (!attr.isNull() && !attr.isEmpty()) { + if ( attr.startsWith( KTel ) ) + tel = attr.substring(4); + else if( attr.startsWith(KWtaiMC) ) + tel = attr.substring(13); + else if( attr.startsWith(KWtaiAP) ) + tel = attr.substring(13); + else if( attr.startsWith(KWtaiSD) ) + tel = attr.substring(13); + else if ( attr.startsWith( KMailto ) ) { + email = attr.substring(7); + // Find just the email address + int i = email.find('?'); + if (i > 0 ) { + email = email.left(i).stripWhiteSpace(); + } + } + } + // cti + attr = e->getAttribute(ctiAttr); + if (!attr.isNull() && !attr.isEmpty() ) + tel = attr; + // email + attr = e->getAttribute(emailAttr); + if (!attr.isNull() && !attr.isEmpty() ) + email = attr; + // telbook + attr = e->getAttribute(telbookAttr); + if (!attr.isNull() && !attr.isEmpty() ) + telbook = attr; + // Save to phone book + String url; + String makeCallUrlPrefix("wtai://wp/ap;"); + char numberNameSeparator = ';'; + int len = makeCallUrlPrefix.length() + 3; // NULL terminator and ';' separators + len += tel.length() + telbook.length() + email.length(); + //url.reserve(len); + url = makeCallUrlPrefix; + url.append(tel); + url.append(numberNameSeparator); + url.append(telbook); + url.append(numberNameSeparator); + url.append(email); + handleSpecialSchemeL(url, webView->brCtl()); + } + } + } + } + } +} + +// ----------------------------------------------------------------------------- +// Map the Symbian errors to rainbow errors. +// ----------------------------------------------------------------------------- +// +int mapHttpErrors(int err ) +{ + if (err == KErrSSLAlertUserCanceled){ + return KBrowserCancelled; + } + // All SSL errors are mapped into this one, which gets displayed to the user + if (err <= SSL_ERROR_BASE && err > SSL_ERROR_BASE - 200 || + err == KErrHttpCannotEstablishTunnel) { + return KErrSSLAlertHandshakeFailure; + } + + // Deal with DNS lookup errors + if ((err <= KErrInet6NoDestination) && (err > (KErrInet6NoDestination - 200))) { + return KBrowserHTTP502; + } + + // Deal with HTTP errors + if (err <= KHttpErrorBase && err > KHttpErrorBase - 200) { + // Encode errors + if (err <= KErrHttpEncodeDefault && err >= KErrHttpEncodeCookie2) { + return KBrowserFailure; + } + // Auth errors + if (err == KErrHttpDecodeWWWAuthenticate || + err == KErrHttpDecodeUnknownAuthScheme || + err == KErrHttpDecodeBasicAuth || + err == KErrHttpDecodeDigestAuth) { + return KBrowserMissingAuthHeader; + } + + // Decode errors + if (err <= KErrHttpDecodeMalformedDate && err >= KErrHttpDecodeCookie) { + return KBrowserBadContent; + } + switch (err) + { + case KErrHttpRedirectExceededLimit: + { + return KBrowserTooManyRedirects; + } + case KErrHttpRedirectNoLocationField: + case KErrHttpRedirectUseProxy: + { + return KBrowserBadRedirect; + } + case KErrHttpInvalidUri: + { + return KBrowserMalformedUrl; + } + default: + { + return KBrowserFailure; + } + } + } + if (err <= KBrowserHTTP100 && err > KBrowserFailure) + return err; + switch (err) + { + case KErrHostUnreach: + { + return KBrowserTcpHostUnreachable; + } + case KErrAbort: //User has interrupted the loading process. We treat it as cancellation so that no error message shown. + case KErrCancel: + { + return KBrowserCancelled; + } + case KErrBadName: + case KErrPathNotFound: + { + return KBrowserFileNotFound; + } + case KErrCommsLineFail: + case KErrNotReady: + { + return KBrowserConnFailed; + } + case KErrDiskFull: + { + return KBrowserFileDiskFullError; + } + case KErrTimedOut: + { + return KBrowserWaitTimeout; + } + case KErrCouldNotConnect: + { + return KBrowserMalformedUrl; + } + case KErrDisconnected: + { + return KBrowserHTTP504; + } + case KErrNoMemory: + { + return KBrowserOutOfMemory; + } + default: + { + return KBrowserFailure; + } + } // end of switch +} + + +bool handleSelectElementScrolling(WebView* webView, int tb) +{ + bool ret = false; + if (webView->focusedElementType() == TBrCtlDefs::EElementSelectMultiBox && tb != 0) { + IntPoint point; + WebFrame* frame = frameAndPointUnderCursor(point, *webView); + Element* e = core(frame)->document()->elementFromPoint(point.x(), point.y()); + if (e && e->isControl()) { + HTMLGenericFormElement* ie = static_cast( e ); + if (ie->type() == "select-multiple") { + RenderListBox* render = static_cast(e->renderer()); + if (render->isScrollable()) { + HTMLSelectElement* selectElement = static_cast( e ); + IntRect r = e->getRect(); + int curIndex = render->listIndexAtOffset(point.x() - r.x(), point.y() - r.y()); + int topIndex = render->indexOffset(); + int bottomIndex = topIndex + selectElement->size() - 1; + TPoint curPointInSelectBox(point.x() - r.x(), point.y() - r.y()); + IntRect itemRect = render->itemRect(0, 0, curIndex); + int centerOfRect = itemRect.y() + (itemRect.height() * 1) / 4; + if (tb == -1) { + if (curIndex == topIndex) { + if (render->scroll(ScrollUp, ScrollByLine)) { + ret = true; + } + } + else { + int step = ((itemRect.height() + (curPointInSelectBox.iY - centerOfRect)) * webView->scalingFactor()) / 100; + if (step <= 0) step = (itemRect.height() * webView->scalingFactor()) / 100; + TPoint tp(StaticObjectsContainer::instance()->webCursor()->position().iX, StaticObjectsContainer::instance()->webCursor()->position().iY - step); + StaticObjectsContainer::instance()->webCursor()->updatePositionAndElemType(tp); + ret = true; + } + } + else { + if (curIndex == bottomIndex) { + if (render->scroll(ScrollDown, ScrollByLine)) { + ret = true; + } + } + else { + int step = ((itemRect.height() + (centerOfRect - curPointInSelectBox.iY)) * webView->scalingFactor()) / 100; + if (step <= 0) step = (itemRect.height() * webView->scalingFactor()) / 100; + TPoint tp(StaticObjectsContainer::instance()->webCursor()->position().iX, StaticObjectsContainer::instance()->webCursor()->position().iY + step); + StaticObjectsContainer::instance()->webCursor()->updatePositionAndElemType(tp); + ret = true; + } + } + } + } + } + } + return ret; +} +