From 7f81fc8ed2173924cbd0efbb828033bfad36882a Mon Sep 17 00:00:00 2001 From: John Daggett Date: Wed, 7 Dec 2011 12:02:53 +0900 Subject: [PATCH 1/6] Bug 693143. Fix top crasher related to small font sizes and bitmap fonts. r=roc --- gfx/thebes/gfxFont.cpp | 2 +- gfx/thebes/gfxGDIFont.cpp | 203 +++++++++++++++++++------------------- 2 files changed, 105 insertions(+), 100 deletions(-) diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index 338f9d1b8b1..0d9e9351fa9 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -1832,7 +1832,7 @@ gfxFont::SanitizeMetrics(gfxFont::Metrics *aMetrics, bool aIsBadUnderlineFont) { // Even if this font size is zero, this font is created with non-zero size. // However, for layout and others, we should return the metrics of zero size font. - if (mStyle.size == 0) { + if (mStyle.size == 0.0) { memset(aMetrics, 0, sizeof(gfxFont::Metrics)); return; } diff --git a/gfx/thebes/gfxGDIFont.cpp b/gfx/thebes/gfxGDIFont.cpp index 0be9f432137..d76ceff7161 100644 --- a/gfx/thebes/gfxGDIFont.cpp +++ b/gfx/thebes/gfxGDIFont.cpp @@ -327,6 +327,7 @@ gfxGDIFont::Initialize() } } + // this may end up being zero mAdjustedSize = ROUND(mAdjustedSize); FillLogFont(logFont, mAdjustedSize); mFont = ::CreateFontIndirectW(&logFont); @@ -338,102 +339,105 @@ gfxGDIFont::Initialize() SetGraphicsMode(dc.GetDC(), GM_ADVANCED); AutoSelectFont selectFont(dc.GetDC(), mFont); - // Get font metrics - OUTLINETEXTMETRIC oMetrics; - TEXTMETRIC& metrics = oMetrics.otmTextMetrics; + // Get font metrics if size > 0 + if (mAdjustedSize > 0.0) { - if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { - mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; - // Some fonts have wrong sign on their subscript offset, bug 410917. - mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); - mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; - mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; - mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; - mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; + OUTLINETEXTMETRIC oMetrics; + TEXTMETRIC& metrics = oMetrics.otmTextMetrics; - const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; - GLYPHMETRICS gm; - DWORD len = GetGlyphOutlineW(dc.GetDC(), PRUnichar('x'), GGO_METRICS, &gm, 0, nsnull, &kIdentityMatrix); - if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { - // 56% of ascent, best guess for true type - mMetrics->xHeight = - ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); + if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { + mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; + // Some fonts have wrong sign on their subscript offset, bug 410917. + mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); + mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; + mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; + mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; + mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; + + const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; + GLYPHMETRICS gm; + DWORD len = GetGlyphOutlineW(dc.GetDC(), PRUnichar('x'), GGO_METRICS, &gm, 0, nsnull, &kIdentityMatrix); + if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { + // 56% of ascent, best guess for true type + mMetrics->xHeight = + ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); + } else { + mMetrics->xHeight = gm.gmptGlyphOrigin.y; + } + mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; + gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; + mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); + mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; + if (oMetrics.otmEMSquare > 0) { + mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); + } } else { - mMetrics->xHeight = gm.gmptGlyphOrigin.y; - } - mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; - gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; - mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); - mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; - if (oMetrics.otmEMSquare > 0) { - mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); - } - } else { - // Make a best-effort guess at extended metrics - // this is based on general typographic guidelines - - // GetTextMetrics can fail if the font file has been removed - // or corrupted recently. - BOOL result = GetTextMetrics(dc.GetDC(), &metrics); - if (!result) { - NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); - mIsValid = false; - memset(mMetrics, 0, sizeof(*mMetrics)); - return; + // Make a best-effort guess at extended metrics + // this is based on general typographic guidelines + + // GetTextMetrics can fail if the font file has been removed + // or corrupted recently. + BOOL result = GetTextMetrics(dc.GetDC(), &metrics); + if (!result) { + NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); + mIsValid = false; + memset(mMetrics, 0, sizeof(*mMetrics)); + return; + } + + mMetrics->xHeight = + ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); + mMetrics->superscriptOffset = mMetrics->xHeight; + mMetrics->subscriptOffset = mMetrics->xHeight; + mMetrics->strikeoutSize = 1; + mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight + mMetrics->underlineSize = 1; + mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent + mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; + mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; + mMetrics->emDescent = metrics.tmDescent; } - mMetrics->xHeight = - ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); - mMetrics->superscriptOffset = mMetrics->xHeight; - mMetrics->subscriptOffset = mMetrics->xHeight; - mMetrics->strikeoutSize = 1; - mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight - mMetrics->underlineSize = 1; - mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent - mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; - mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; - mMetrics->emDescent = metrics.tmDescent; - } - - mMetrics->internalLeading = metrics.tmInternalLeading; - mMetrics->externalLeading = metrics.tmExternalLeading; - mMetrics->maxHeight = metrics.tmHeight; - mMetrics->maxAscent = metrics.tmAscent; - mMetrics->maxDescent = metrics.tmDescent; - mMetrics->maxAdvance = metrics.tmMaxCharWidth; - mMetrics->aveCharWidth = NS_MAX(1, metrics.tmAveCharWidth); - // The font is monospace when TMPF_FIXED_PITCH is *not* set! - // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx - if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { - mMetrics->maxAdvance = mMetrics->aveCharWidth; - } - - // Cache the width of a single space. - SIZE size; - GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); - mMetrics->spaceWidth = ROUND(size.cx); - - // Cache the width of digit zero. - // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) - // does not say what the failure modes for GetTextExtentPoint32 are - - // is it safe to assume it will fail iff the font has no '0'? - if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { - mMetrics->zeroOrAveCharWidth = ROUND(size.cx); - } else { - mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; - } - - mSpaceGlyph = 0; - if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) { - WORD glyph; - DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, - GGI_MARK_NONEXISTING_GLYPHS); - if (ret != GDI_ERROR && glyph != 0xFFFF) { - mSpaceGlyph = glyph; + mMetrics->internalLeading = metrics.tmInternalLeading; + mMetrics->externalLeading = metrics.tmExternalLeading; + mMetrics->maxHeight = metrics.tmHeight; + mMetrics->maxAscent = metrics.tmAscent; + mMetrics->maxDescent = metrics.tmDescent; + mMetrics->maxAdvance = metrics.tmMaxCharWidth; + mMetrics->aveCharWidth = NS_MAX(1, metrics.tmAveCharWidth); + // The font is monospace when TMPF_FIXED_PITCH is *not* set! + // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx + if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { + mMetrics->maxAdvance = mMetrics->aveCharWidth; } - } - SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); + // Cache the width of a single space. + SIZE size; + GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); + mMetrics->spaceWidth = ROUND(size.cx); + + // Cache the width of digit zero. + // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) + // does not say what the failure modes for GetTextExtentPoint32 are - + // is it safe to assume it will fail iff the font has no '0'? + if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { + mMetrics->zeroOrAveCharWidth = ROUND(size.cx); + } else { + mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; + } + + mSpaceGlyph = 0; + if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) { + WORD glyph; + DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, + GGI_MARK_NONEXISTING_GLYPHS); + if (ret != GDI_ERROR && glyph != 0xFFFF) { + mSpaceGlyph = glyph; + } + } + + SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); + } mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, mFont); @@ -460,20 +464,21 @@ gfxGDIFont::Initialize() mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); NS_WARNING(warnBuf); #endif + mIsValid = false; + } else { + mIsValid = true; } - mIsValid = true; - #if 0 - printf("Font: %p (%s) size: %f\n", this, - NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); - printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); - printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance); - printf(" internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading); - printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); + printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, + NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); + printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); + printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); + printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); + printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", - mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, - mMetrics.superscriptOffset, mMetrics.subscriptOffset); + mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, + mMetrics->superscriptOffset, mMetrics->subscriptOffset); #endif } From d177eac65fd740840340cd38b3ee886a7d82ecb8 Mon Sep 17 00:00:00 2001 From: John Daggett Date: Wed, 7 Dec 2011 12:03:42 +0900 Subject: [PATCH 2/6] Bug 693143. Crashtest for the small bitmap case. r=roc --- gfx/tests/crashtests/693143-1.html | 44 ++++++++++++++++++++++++++++ gfx/tests/crashtests/crashtests.list | 2 ++ 2 files changed, 46 insertions(+) create mode 100644 gfx/tests/crashtests/693143-1.html diff --git a/gfx/tests/crashtests/693143-1.html b/gfx/tests/crashtests/693143-1.html new file mode 100644 index 00000000000..80b1e891ac1 --- /dev/null +++ b/gfx/tests/crashtests/693143-1.html @@ -0,0 +1,44 @@ + + + +Tiny ugly fonts + + + + + + + +

No text should show below this line

+
+

ugly font

+

ugly font

+

ugly font

+

ugly font

+
+ + + \ No newline at end of file diff --git a/gfx/tests/crashtests/crashtests.list b/gfx/tests/crashtests/crashtests.list index c7854ee8561..71ea8bdd0a9 100644 --- a/gfx/tests/crashtests/crashtests.list +++ b/gfx/tests/crashtests/crashtests.list @@ -85,3 +85,5 @@ load 595727-1.html load 633453-1.html load 633322-1.html load 686190-1.html +load 693143-1.html + From f7b12259d17e24c53feafe7a4a002570bae143e3 Mon Sep 17 00:00:00 2001 From: Oleg Romashin Date: Tue, 6 Dec 2011 19:29:58 -0500 Subject: [PATCH 3/6] Bug 706935 - file upload on Meego Harmattan don't working. r=dougt --- widget/src/qt/faststartupqt/nsFastStartupQt.cpp | 6 +++--- widget/src/qt/faststartupqt/nsFastStartupQt.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/widget/src/qt/faststartupqt/nsFastStartupQt.cpp b/widget/src/qt/faststartupqt/nsFastStartupQt.cpp index 588df73c966..01104f3e000 100644 --- a/widget/src/qt/faststartupqt/nsFastStartupQt.cpp +++ b/widget/src/qt/faststartupqt/nsFastStartupQt.cpp @@ -63,7 +63,7 @@ nsFastStartup::symbolsLoadingFinished(bool preloaded) { mSymbolsLoaded = preloaded; if (mWidgetPainted && mSymbolsLoaded) { - qApp->quit(); + mLoop.quit(); } } @@ -71,7 +71,7 @@ void nsFastStartup::painted() { mWidgetPainted = true; if (mWidgetPainted && mSymbolsLoaded) { - qApp->quit(); + mLoop.quit(); } } @@ -159,7 +159,7 @@ nsFastStartup::CreateFastStartup(int& argc, char ** argv, // Start native loop in order to get view opened and painted once // Will block CreateFastStartup function and // exit when symbols are loaded and Static UI shown - qApp->exec(); + mLoop.exec(); return true; } diff --git a/widget/src/qt/faststartupqt/nsFastStartupQt.h b/widget/src/qt/faststartupqt/nsFastStartupQt.h index da2e5f61f47..3614dd4410e 100644 --- a/widget/src/qt/faststartupqt/nsFastStartupQt.h +++ b/widget/src/qt/faststartupqt/nsFastStartupQt.h @@ -42,6 +42,7 @@ #include #include "nscore.h" #include +#include #include class QGraphicsView; @@ -106,6 +107,7 @@ private: bool mSymbolsLoaded; bool mWidgetPainted; GeckoThread* mThread; + QEventLoop mLoop; }; #endif From 9453ec7dd6165e418f4f7468e7516fde8aec3697 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Tue, 6 Dec 2011 20:24:33 -0800 Subject: [PATCH 4/6] bug 708171 - XUL fennec hangs on start up r=mbrubeck --- embedding/android/GeckoAppShell.java | 28 ++++++++++++++++++++---- mobile/xul/chrome/content/browser.js | 21 +++++++++++++++++- mobile/xul/installer/package-manifest.in | 3 +++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java index 11f39051fa9..cf20000dc72 100644 --- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -73,6 +73,9 @@ import android.net.NetworkInfo; import android.graphics.drawable.*; import android.graphics.Bitmap; +import org.json.JSONArray; +import org.json.JSONObject; + public class GeckoAppShell { private static final String LOG_FILE_NAME = "GeckoAppShell"; @@ -1629,10 +1632,6 @@ public class GeckoAppShell } } - // unused - public static String handleGeckoMessage(String message) { - return ""; - } // unused static void checkUriVisited(String uri) {} // unused @@ -1645,6 +1644,27 @@ public class GeckoAppShell GeckoBatteryManager.enableNotifications(); } + public static String handleGeckoMessage(String message) { + // + // {"gecko": { + // "type": "value", + // "event_specific": "value", + // .... + try { + JSONObject json = new JSONObject(message); + final JSONObject geckoObject = json.getJSONObject("gecko"); + String type = geckoObject.getString("type"); + + if (type.equals("Gecko:Ready")) { + onAppShellReady(); + } + } catch (Exception e) { + Log.i(LOG_FILE_NAME, "handleGeckoMessage throws " + e); + } + + return ""; + } + public static void disableBatteryNotifications() { GeckoBatteryManager.disableNotifications(); } diff --git a/mobile/xul/chrome/content/browser.js b/mobile/xul/chrome/content/browser.js index c77c90de4b4..155ddb60a77 100644 --- a/mobile/xul/chrome/content/browser.js +++ b/mobile/xul/chrome/content/browser.js @@ -53,6 +53,16 @@ let Ci = Components.interfaces; let Cu = Components.utils; let Cr = Components.results; + +function getBridge() { + return Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge); +} + +function sendMessageToJava(aMessage) { + return getBridge().handleGeckoMessage(JSON.stringify(aMessage)); +} + + function getBrowser() { return Browser.selectedBrowser; } @@ -166,7 +176,16 @@ var Browser = { startup: function startup() { var self = this; - + + try { + sendMessageToJava({ + gecko: { + type: "Gecko:Ready" + } + }); + } catch(e) { + Cu.reportError("error sending message: " + e); + } try { messageManager.loadFrameScript("chrome://browser/content/Util.js", true); messageManager.loadFrameScript("chrome://browser/content/forms.js", true); diff --git a/mobile/xul/installer/package-manifest.in b/mobile/xul/installer/package-manifest.in index 87c4a52554d..1e6551f4d25 100644 --- a/mobile/xul/installer/package-manifest.in +++ b/mobile/xul/installer/package-manifest.in @@ -267,6 +267,9 @@ #ifdef XP_MACOSX @BINPATH@/components/widget_cocoa.xpt #endif +#ifdef ANDROID +@BINPATH@/components/widget_android.xpt +#endif @BINPATH@/components/windowds.xpt @BINPATH@/components/windowwatcher.xpt @BINPATH@/components/xpcom_base.xpt From d1bff952ffb3b73ddea57e181dd26f7ebdea1fd9 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Tue, 6 Dec 2011 20:52:51 -0800 Subject: [PATCH 5/6] bug 708171 - XUL fennec hangs on start up, follow up to fix missed review comment r=mbrubeck --- mobile/xul/chrome/content/browser.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mobile/xul/chrome/content/browser.js b/mobile/xul/chrome/content/browser.js index 155ddb60a77..fb848153ec3 100644 --- a/mobile/xul/chrome/content/browser.js +++ b/mobile/xul/chrome/content/browser.js @@ -177,15 +177,12 @@ var Browser = { startup: function startup() { var self = this; - try { sendMessageToJava({ gecko: { type: "Gecko:Ready" } }); - } catch(e) { - Cu.reportError("error sending message: " + e); - } + try { messageManager.loadFrameScript("chrome://browser/content/Util.js", true); messageManager.loadFrameScript("chrome://browser/content/forms.js", true); From b7e4ab81f92458ae87c768c526de984a126f8641 Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Mon, 5 Dec 2011 16:57:33 -0500 Subject: [PATCH 6/6] bug 705572 - Kindle Fire: YouTube videos do not open in unavailable YouTube App r=dougt,mfinkle --- embedding/android/AndroidManifest.xml.in | 16 ++- embedding/android/GeckoAppShell.java | 12 ++ embedding/android/Makefile.in | 2 + embedding/android/VideoPlayer.java | 113 ++++++++++++++++++ .../android/resources/layout/videoplayer.xml | 12 ++ 5 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 embedding/android/VideoPlayer.java create mode 100644 embedding/android/resources/layout/videoplayer.xml diff --git a/embedding/android/AndroidManifest.xml.in b/embedding/android/AndroidManifest.xml.in index 8c9b8272d02..cedaebe5e29 100644 --- a/embedding/android/AndroidManifest.xml.in +++ b/embedding/android/AndroidManifest.xml.in @@ -34,11 +34,11 @@ + android:debuggable="false"> #else - android:debuggable="true"> + android:debuggable="true"> #endif - + #endif + + + + + + diff --git a/embedding/android/GeckoAppShell.java b/embedding/android/GeckoAppShell.java index cf20000dc72..2a147813ab2 100644 --- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -811,6 +811,18 @@ public class GeckoAppShell intent.setDataAndType(Uri.parse(aUriSpec), aMimeType); } else { Uri uri = Uri.parse(aUriSpec); + if ("vnd.youtube".equals(uri.getScheme())) { + // Special case youtube to fallback to our own player + String[] handlers = getHandlersForURL(aUriSpec, aAction); + if (handlers.length == 0) { + intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName(GeckoApp.mAppContext.getPackageName(), + "org.mozilla.gecko.VideoPlayer"); + intent.setData(uri); + GeckoApp.mAppContext.startActivity(intent); + return true; + } + } if ("sms".equals(uri.getScheme())) { // Have a apecial handling for the SMS, as the message body // is not extracted from the URI automatically diff --git a/embedding/android/Makefile.in b/embedding/android/Makefile.in index 540adaab05c..71920c4bdbf 100644 --- a/embedding/android/Makefile.in +++ b/embedding/android/Makefile.in @@ -56,6 +56,7 @@ JAVAFILES = \ SurfaceInfo.java \ GeckoBatteryManager.java \ GeckoSmsManager.java \ + VideoPlayer.java \ $(NULL) PROCESSEDJAVAFILES = \ @@ -127,6 +128,7 @@ RES_LAYOUT = \ res/layout/notification_icon_text.xml \ res/layout/launch_app_list.xml \ res/layout/launch_app_listitem.xml \ + res/layout/videoplayer.xml \ $(NULL) RES_VALUES = res/values/colors.xml res/values/themes.xml diff --git a/embedding/android/VideoPlayer.java b/embedding/android/VideoPlayer.java new file mode 100644 index 00000000000..ca643de242e --- /dev/null +++ b/embedding/android/VideoPlayer.java @@ -0,0 +1,113 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brad Lassey + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +package org.mozilla.gecko; + +import android.app.Activity; +import android.os.Bundle; +import java.net.*; +import java.io.*; +import java.util.*; +import android.util.*; +import android.widget.*; +import android.net.*; +import android.content.Intent; + +public class VideoPlayer extends Activity +{ + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.videoplayer); + mVideoView = (VideoView) findViewById(R.id.VideoView); + MediaController mediaController = new MediaController(this); + mediaController.setAnchorView(mVideoView); + Intent intent = getIntent(); + Uri data = intent.getData(); + String spec = null; + if ("vnd.youtube".equals(data.getScheme())) { + String ssp = data.getSchemeSpecificPart(); + String id = ssp.substring(0, ssp.indexOf('?')); + spec = getSpecFromYouTubeVideoID(id); + } + if (spec == null) + return; + Uri video = Uri.parse(spec); + mVideoView.setMediaController(mediaController); + mVideoView.setVideoURI(video); + mVideoView.start(); + } + + VideoView mVideoView; + + String getSpecFromYouTubeVideoID(String id) { + String spec = null; + try { + String info_uri = "http://www.youtube.com/get_video_info?&video_id=" + id; + URL info_url = new URL(info_uri); + URLConnection urlConnection = info_url.openConnection(); + BufferedReader br = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); + try { + StringBuilder sb = new StringBuilder(); + String line; + while ((line = br.readLine()) != null) + sb.append(line); + android.net.Uri fakeUri = android.net.Uri.parse("fake:/fake?" + sb); + String stream_map = fakeUri.getQueryParameter("url_encoded_fmt_stream_map"); + if (stream_map == null) + return null; + String[] streams = stream_map.split(","); + for (int i = 0; i < streams.length; i++) { + fakeUri = android.net.Uri.parse("fake:/fake?" + streams[i]); + String url = fakeUri.getQueryParameter("url"); + String type = fakeUri.getQueryParameter("type"); + if (type != null && url != null && + (type.startsWith("video/mp4") || type.startsWith("video/webm"))) { + spec = url; + } + } + } finally { + br.close(); + } + } catch (Exception e) { + Log.e("VideoPlayer", "exception", e); + } + return spec; + } +} diff --git a/embedding/android/resources/layout/videoplayer.xml b/embedding/android/resources/layout/videoplayer.xml new file mode 100644 index 00000000000..25953a5b111 --- /dev/null +++ b/embedding/android/resources/layout/videoplayer.xml @@ -0,0 +1,12 @@ + + + +