Bug 419588 - Add support for a resolution media fragment. r=seth
authorWes Johnston <wjohnston@mozilla.com>
Fri, 22 Mar 2013 16:12:40 -0700
changeset 136374 26eb06639c711ffdb8294e2929a3dea4e960665a
parent 136373 e1d71b13e35f92eac9f46573e4cca2ba64956b7b
child 136375 7bdeb824afcf8a9ebdfdca1a312026f0f655a459
push id2452
push userlsblakk@mozilla.com
push dateMon, 13 May 2013 16:59:38 +0000
treeherdermozilla-beta@d4b152d29d8d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersseth
bugs419588
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 419588 - Add support for a resolution media fragment. r=seth
image/decoders/nsICODecoder.cpp
image/src/ImageFactory.cpp
image/src/RasterImage.h
image/test/reftest/ico/ico-mixed/mixed-bmp-png32.png
image/test/reftest/ico/ico-mixed/mixed-bmp-png48.png
image/test/reftest/ico/ico-mixed/reftest.list
netwerk/base/src/nsMediaFragmentURIParser.cpp
netwerk/base/src/nsMediaFragmentURIParser.h
--- a/image/decoders/nsICODecoder.cpp
+++ b/image/decoders/nsICODecoder.cpp
@@ -242,16 +242,22 @@ nsICODecoder::WriteInternal(const char* 
     mPos += 2;
     aCount -= 2;
   }
 
   if (mNumIcons == 0)
     return; // Nothing to do.
 
   uint16_t colorDepth = 0;
+  nsIntSize prefSize = mImage.GetRequestedResolution();
+  if (prefSize.width == 0 && prefSize.height == 0) {
+    prefSize.SizeTo(PREFICONSIZE,PREFICONSIZE);
+  }
+
+  int32_t diff = INT_MAX;
   // Loop through each entry's dir entry
   while (mCurrIcon < mNumIcons) { 
     if (mPos >= DIRENTRYOFFSET + (mCurrIcon * sizeof(mDirEntryArray)) && 
         mPos < DIRENTRYOFFSET + ((mCurrIcon + 1) * sizeof(mDirEntryArray))) {
       uint32_t toCopy = sizeof(mDirEntryArray) - 
                         (mPos - DIRENTRYOFFSET - mCurrIcon * sizeof(mDirEntryArray));
       if (toCopy > aCount) {
         toCopy = aCount;
@@ -266,20 +272,21 @@ nsICODecoder::WriteInternal(const char* 
 
     IconDirEntry e;
     if (mPos == (DIRENTRYOFFSET + ICODIRENTRYSIZE) + 
                 (mCurrIcon * sizeof(mDirEntryArray))) {
       mCurrIcon++;
       ProcessDirEntry(e);
       // We can't use GetRealWidth and GetRealHeight here because those operate
       // on mDirEntry, here we are going through each item in the directory
-      if (((e.mWidth == 0 ? 256 : e.mWidth) == PREFICONSIZE && 
-           (e.mHeight == 0 ? 256 : e.mHeight) == PREFICONSIZE && 
-           (e.mBitCount >= colorDepth)) ||
+      int32_t delta = abs( (e.mWidth == 0 ? 256 : e.mWidth) - prefSize.width +
+                           (e.mHeight == 0 ? 256 : e.mHeight) - prefSize.height );
+      if ((e.mBitCount >= colorDepth && delta <= diff) ||
           (mCurrIcon == mNumIcons && mImageOffset == 0)) {
+        diff = delta;
         mImageOffset = e.mImageOffset;
 
         // ensure mImageOffset is >= size of the direntry headers (bug #245631)
         uint32_t minImageOffset = DIRENTRYOFFSET + 
                                   mNumIcons * sizeof(mDirEntryArray);
         if (mImageOffset < minImageOffset) {
           PostDataError();
           return;
--- a/image/src/ImageFactory.cpp
+++ b/image/src/ImageFactory.cpp
@@ -18,16 +18,17 @@
 #include "nsIRequest.h"
 
 #include "imgIContainer.h"
 #include "imgStatusTracker.h"
 #include "RasterImage.h"
 #include "VectorImage.h"
 #include "FrozenImage.h"
 #include "Image.h"
+#include "nsMediaFragmentURIParser.h"
 
 #include "ImageFactory.h"
 
 namespace mozilla {
 namespace image {
 
 // Global preferences related to image containers.
 static bool gInitializedPrefCaches = false;
@@ -211,16 +212,21 @@ ImageFactory::CreateRasterImage(nsIReque
       nsresult rv2 = newImage->SetSourceSizeHint(sizeHint);
       // If we've still failed at this point, things are going downhill.
       if (NS_FAILED(rv) || NS_FAILED(rv2)) {
         NS_WARNING("About to hit OOM in imagelib!");
       }
     }
   }
 
+  mozilla::net::nsMediaFragmentURIParser parser(aURI);
+  if (parser.HasResolution()) {
+    newImage->SetRequestedResolution(parser.GetResolution());
+  }
+
   return newImage.forget();
 }
 
 /* static */ already_AddRefed<Image>
 ImageFactory::CreateVectorImage(nsIRequest* aRequest,
                                 imgStatusTracker* aStatusTracker,
                                 const nsCString& aMimeType,
                                 nsIURI* aURI,
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -261,16 +261,25 @@ public:
    * We take this approach rather than having the source data management code do
    * something more complicated (like chunklisting) because HTTP is by far the
    * dominant source of images, and the Content-Length header is quite reliable.
    * Thus, pre-allocation simplifies code and reduces the total number of
    * allocations.
    */
   nsresult SetSourceSizeHint(uint32_t sizeHint);
 
+  /* Provide a hint for the requested resolution of the resulting image. */
+  void SetRequestedResolution(const nsIntSize requestedResolution) {
+    mRequestedResolution = requestedResolution;
+  }
+
+  nsIntSize GetRequestedResolution() {
+    return mRequestedResolution;
+  }
+
   // "Blend" method indicates how the current image is combined with the
   // previous image.
   enum FrameBlendMethod {
     // All color components of the frame, including alpha, overwrite the current
     // contents of the frame's output buffer region
     kBlendSource =  0,
 
     // The frame should be composited onto the output buffer based on its alpha,
@@ -707,17 +716,16 @@ private:
   bool IsInUpdateImageContainer() { return mInUpdateImageContainer; }
   enum RequestDecodeType {
       ASYNCHRONOUS,
       SOMEWHAT_SYNCHRONOUS
   };
   NS_IMETHOD RequestDecodeCore(RequestDecodeType aDecodeType);
 
 private: // data
-
   nsIntSize                  mSize;
 
   // Whether mFrames below were decoded using any special flags.
   // Some flags (e.g. unpremultiplied data) may not be compatible
   // with the browser's needs for displaying the image to the user.
   // As such, we may need to redecode if we're being asked for
   // a frame with different flags.  0 indicates default flags.
   //
@@ -755,16 +763,19 @@ private: // data
   nsRefPtr<Decoder>              mDecoder;
   nsRefPtr<DecodeRequest>        mDecodeRequest;
   uint32_t                       mBytesDecoded;
 
   // How many times we've decoded this image.
   // This is currently only used for statistics
   int32_t                        mDecodeCount;
 
+  // If the image contains multiple resolutions, a hint as to which one should be used
+  nsIntSize                  mRequestedResolution;
+
   // Cached value for GetImageContainer.
   nsRefPtr<mozilla::layers::ImageContainer> mImageContainer;
 
 #ifdef DEBUG
   uint32_t                       mFramesNotified;
 #endif
 
   // Boolean flags (clustered together to conserve space):
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a0589912728b065a5e2ad148a3d63fa1368e1d34
GIT binary patch
literal 940
zc$@*O15^BoP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*e|
z02mC(zN}sV00S&ZL_t(o!>w1bj?+L8efFiteUQ8tmlU`8f^!rBB}qqjag&1PNJ*9C
z3zBQoB>4i|P*I%I(%}05n>CUvBxFH}lu+FGZdrD1CoobZ%iip~nR#z^$3jCB?G6Vp
z0B{MwH!O<)>;Qx;Pva*0S`8eJ09*s$IL=}KbC##!NdQE<!vL%+qHSssfPm$xXbeEK
zI|Fj=G_4RteD~2hTs%KmHvky@T*{s{8<rvE>xPkS-<=(tPu8L2g`<Gl0$3)QC`7x%
zb-b`Nk-x8Tya6!pxAq*sl-}{0><p7kXh~^nYHqR+z<Iy5pY&V%1vw9rOmqp9$tw4?
zrDs#k3jjTqr^9}0?*RBr>w0BWNhSgSK?Mlzxol(vKy~*Gbv|c#8hI|`0B!+9NhW$p
zCJK3Bl8H?Xi0i5h=ss>(p7vOt7K(GDlNu0Op4imkxW;(^0G`VnBBrQ`PzJHoee+z#
zbQu_^WGkIZ++akwqDfOoGBKgPpd;j804^2D1QOx_0i2s;RACcCdw#TW?Ar?Y0+y$8
zlnYY9^4R{HWFjIG%kR_-PHm;`kre%iQWiE%y~ei2=<m&!0n81u+5N*o6e^OI(?5`9
z7|N#=v6V}_ILVaEZFK?KhL5r`oKpdigaJVOLE>@jm)x_p=>aaJ=T{XDm`UGCAZmFR
zvJ4}I`Kn$=x<2l?%$L@U4ACzD#MGS1=x0)SBU^(`XKT-8vofXBn%5*z0JtJRa{nj~
ztw2frRN8lE8B%-O;3^g+nds5_nX>UiGfFbCB<JOMB6F&18#b@geGFhIv3*97%KzKc
zIFGU7u?fJg;&wBqyMXRE?h>Il52xn6-fuN(x-ni#iPc|}*TW<eVPg%BV~5J}R(sD_
z@m}S%yrQnCDBC2-#D>VW)}4N|u8S2HwS$T0vb9cPhL$@?UWSZ7R}pxK6%WmG!8m3B
ze609JlGL?kQvo3S@$|*++p{+ez*U3kDJb`?o{a8^vmip<l_%MguOIl?ub<9$?{z@~
zhu?5yE692MV4`H=zl~;P&5s^VDI3!hhtnH1<;Mef1aj1Pjumfoh5HSq!%noOh)vJ{
O0000<MNUMnLSTYmyr;zg
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..61bea5c804b88b6e74ac6dc7c5d300dbbd42695d
GIT binary patch
literal 1332
zc$@(=1<U%0P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00001b5ch_0Itp)
z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2i*e|
z02dasL`mxa00gv2L_t(&-o08qlHxcReNcS>Z%lv&4lwEy05!pei%&2(A>HN#4JQCn
zC%8}0?h~~81mih?J#ygOCz#!U&pm1*$&wANDgp`>e((F!`#yPqD=aaZ%mK^+%m6U@
zD7Vt*4M4)mJn8%FK~K=%0W1M{9si~R5Cb@}GEYB+00Dm_i(hjk0Cuik88`rE0QO|@
zTdo*Dz{<S38UZnyECHN)gi4pt3Rs!Py$OiXWDnq>Z=M540sN#;slMI)_5g^i5JGwu
zrvfme5Pe}~zU@pvj3y@ltB#;k08aqoZ+E{z|1;C%PD;d%3PKetbKy*&Blrry5kSPs
zTujGoMU~1W;dfafw!M<LL)ZwaAQ1pe$E>bY9)K4B|2pPRlocYd**MfB?1O{FH>}LR
zuriOPW9CiAY!Bd-NG-^k3;J%mR?{)tI(vXh<qu11eJFR+G2>LJIDk!7h=aU&I%Xab
z;|@f=$T?x-fxQLz3V_eb+?T*F2^<69H^BoyR)~r`5jhZewDtg<u&)-C#h0rBCF+TY
zEwVziN`mQ_xfF=Mh<vLD+So>{%<ubxCvOA}p5Uz^B&kUg_@H6M`gDd1_y!3Z-7~kz
zf$xssxdc9N1ure%u{vo9EFHjmk}is}LPT93PO<H`Y?~PgQ23}SPtpW0<q9XuZThM<
z^4_kG2j-fS)mK!Hxpc^FOx3}09SotQ53zO1hZ+~@^mrZjNmhvXO5p2I(s`jUofAVv
z|9Vh$MN~5Dy-(L}04SF#&B3X%J_Ep;1WcBw&xxu};<lYNn!{69URhI0>{OvcHJ?cu
z=vM2cY5lAaiK#lt1S(eM2hC>rocMVw^a`+vCVafQ^bcFySJ(Zeg-bufBaqH5uSwu&
z*etKlZ0zGUm0A-JhQ4#=BCh%@^7gwymFLVlm8&6!bWoTQvsq^UaRt)=W?D<h`jIB~
zWz{Td0)>Mb<W!Yhni1P!*rQ~9q4}LP3A}Yk%o8b6SSCIr8Pe9|FtYwZVg0$HSAQFt
zG`Rt!2jJBJYTwW>6@a}elxPqjcWA*y?4M8FXO-Z*V`ZL*(Zn+VMGJ|P%3Xp#BldYi
zsm4U=$8^k&<Z+MouB7Kg7aHpv_s<F}6+)g2ERylRj-$kT*^*NGY3jEZAFO`{ubX5<
z2zfBPQT_ItVL<xHHwZT00sOn5v>}i<fKSNssYWWq0PY+ASq}t+1Na0XPizU;RH&Fh
zEZPQ9Ss_GLhy{Q^3Y%1JQfRnlIxu(2$($w!7=T}zp928#)jG3v`asEUHde@eYXU8U
zsII+i@<Dl?%j5~|Q|t=BJwh&A33%j%YY4eRR)~!Rehd5QwU3a;%F&_)2~LUCl|+K`
z>_3r2*(3B<vX_m2$S<ZKPPdfgiD$T7Sfr$FBC0McvN&`2j|d@G-WLp7l4=V;Amou^
zykfc|uCI)qvO=U-r%O_?t4@8g2E3gI*6E%e9KTD3kXH?_)Fn@3f5#Plp9A=ce%G?f
zuyGHevjv;itciv6?sJ+4&4lev;7_Uhtc&iATq>_a;G-_T*{cS%M6g|*U-lp(*LvCG
q$rX5i0+(d!UVy>!b(^lB<@G-!upc#}auv`30000<MNUMnLSTZ9n_ce!
--- a/image/test/reftest/ico/ico-mixed/reftest.list
+++ b/image/test/reftest/ico/ico-mixed/reftest.list
@@ -1,4 +1,14 @@
 # ICO BMP and PNG mixed tests
 
 == mixed-bmp-png.ico mixed-bmp-png.png
 
+# Using media fragments to select different resolutions
+
+== mixed-bmp-png.ico#-moz-resolution=8,8 mixed-bmp-png.png
+== mixed-bmp-png.ico#test=true&-moz-resolution=8,8&other mixed-bmp-png.png
+== mixed-bmp-png.ico#-moz-resolution=32,32 mixed-bmp-png32.png
+== mixed-bmp-png.ico#-moz-resolution=39,39 mixed-bmp-png32.png
+== mixed-bmp-png.ico#-moz-resolution=40,40 mixed-bmp-png32.png
+== mixed-bmp-png.ico#-moz-resolution=48,48 mixed-bmp-png48.png
+== mixed-bmp-png.ico#-moz-resolution=64,64 mixed-bmp-png48.png
+== mixed-bmp-png.ico#-moz-resolution=64 mixed-bmp-png.png # Bad syntax will fall back to lowest resolution
--- a/netwerk/base/src/nsMediaFragmentURIParser.cpp
+++ b/netwerk/base/src/nsMediaFragmentURIParser.cpp
@@ -323,16 +323,32 @@ bool nsMediaFragmentURIParser::ParseXYWH
     mClip.construct(x, y, w, h);
     mClipUnit = clipUnit;
     return true;
   }
 
   return false;
 }
 
+bool nsMediaFragmentURIParser::ParseMozResolution(nsDependentSubstring aString)
+{
+  int32_t w, h;
+
+  // Read and validate coordinates.
+  if (ParseInteger(aString, w) && w >= 0 &&
+      ParseCommaSeparator(aString)       &&
+      ParseInteger(aString, h) && h >= 0 &&
+      aString.Length() == 0) {
+    mResolution.construct(w,h);
+    return true;
+  }
+
+  return false;
+}
+
 void nsMediaFragmentURIParser::Parse(nsACString& aRef)
 {
   // Create an array of possibly-invalid media fragments.
   nsTArray< std::pair<nsCString, nsCString> > fragments;
   nsCCharSeparatedTokenizer tokenizer(aRef, '&');
 
   while (tokenizer.hasMoreTokens()) {
     const nsCSubstring& nv = tokenizer.nextToken();
@@ -343,24 +359,27 @@ void nsMediaFragmentURIParser::Parse(nsA
       NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name);
       NS_UnescapeURL(Substring(nv, index + 1, nv.Length()),
                      esc_Ref | esc_AlwaysCopy, value);
       fragments.AppendElement(make_pair(name, value));
     }
   }
 
   // Parse the media fragment values.
-  bool gotTemporal = false, gotSpatial = false;
+  bool gotTemporal = false, gotSpatial = false, gotResolution = false;
   for (int i = fragments.Length() - 1 ; i >= 0 ; --i) {
     if (gotTemporal && gotSpatial) {
       // We've got one of each possible type. No need to look at the rest.
       break;
     } else if (!gotTemporal && fragments[i].first.EqualsLiteral("t")) {
       nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
       gotTemporal = ParseNPT(nsDependentSubstring(value, 0));
     } else if (!gotSpatial && fragments[i].first.EqualsLiteral("xywh")) {
       nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
       gotSpatial = ParseXYWH(nsDependentSubstring(value, 0));
+    } else if (!gotResolution && fragments[i].first.EqualsLiteral("-moz-resolution")) {
+      nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second);
+      gotResolution = ParseMozResolution(nsDependentSubstring(value, 0));
     }
   }
 }
 
 }} // namespace mozilla::net
--- a/netwerk/base/src/nsMediaFragmentURIParser.h
+++ b/netwerk/base/src/nsMediaFragmentURIParser.h
@@ -45,16 +45,22 @@ public:
 
   // If a valid temporal media fragment indicated an end time, returns
   // it in units of seconds. If not, defaults to -1.
   double GetEndTime() const { return mEnd.ref(); }
 
   // True if a valid spatial media fragment indicated a clipping region.
   bool HasClip() const { return !mClip.empty(); }
 
+  // True if a valid spatial media fragment indicated a resolution.
+  bool HasResolution() const { return !mResolution.empty(); }
+
+  // True if a valid spatial media fragment indicated a resolution.
+  nsIntSize GetResolution() const { return mResolution.ref(); }
+
   // If a valid spatial media fragment indicated a clipping region,
   // returns the region. If not, returns an empty region. The unit
   // used depends on the value returned by GetClipUnit().
   nsIntRect GetClip() const { return mClip.ref(); }
 
   // If a valid spatial media fragment indicated a clipping region,
   // returns the unit used.
   ClipUnit GetClipUnit() const { return mClipUnit; }
@@ -75,19 +81,21 @@ private:
   bool ParseNPTSec(nsDependentSubstring& aString, double& aSec);
   bool ParseNPTFraction(nsDependentSubstring& aString, double& aFraction);
   bool ParseNPTMMSS(nsDependentSubstring& aString, double& aTime);
   bool ParseNPTHHMMSS(nsDependentSubstring& aString, double& aTime);
   bool ParseNPTHH(nsDependentSubstring& aString, uint32_t& aHour);
   bool ParseNPTMM(nsDependentSubstring& aString, uint32_t& aMinute);
   bool ParseNPTSS(nsDependentSubstring& aString, uint32_t& aSecond);
   bool ParseXYWH(nsDependentSubstring aString);
+  bool ParseMozResolution(nsDependentSubstring aString);
 
   // Media fragment information.
   Maybe<double>    mStart;
   Maybe<double>    mEnd;
   Maybe<nsIntRect> mClip;
   ClipUnit         mClipUnit;
+  Maybe<nsIntSize> mResolution;
 };
 
 }} // namespace mozilla::net
 
 #endif