html2canvas.js 145 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512
  1. /*
  2. html2canvas 0.5.0-beta3 <http://html2canvas.hertzen.com>
  3. Copyright (c) 2016 Niklas von Hertzen
  4. Released under License
  5. */
  6. !(function (e) { if ('object'===typeof exports && 'undefined' != typeof module)module.exports = e(); else if ('function'===typeof define && define.amd)define([], e); else { var f; 'undefined' != typeof window ? f = window:'undefined' != typeof global ? f = global:'undefined' != typeof self && (f = self), f.html2canvas = e() } }(function () {
  7. var define, module, exports; return (function e (t, n, r) { function s (o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == 'function' && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = 'MODULE_NOT_FOUND', f } var l = n[o] = {exports: {}}; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n || e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require == 'function' && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({1: [function (_dereq_, module, exports) {
  8. (function (global) {
  9. /*! http://mths.be/punycode v1.2.4 by @mathias */
  10. ;(function (root) {
  11. /** Detect free variables */
  12. var freeExports = typeof exports === 'object' && exports;
  13. var freeModule = typeof module === 'object' && module &&
  14. module.exports == freeExports && module;
  15. var freeGlobal = typeof global === 'object' && global;
  16. if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
  17. root = freeGlobal;
  18. }
  19. /**
  20. * The `punycode` object.
  21. * @name punycode
  22. * @type Object
  23. */
  24. var punycode,
  25. /** Highest positive signed 32-bit float value */
  26. maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
  27. /** Bootstring parameters */
  28. base = 36,
  29. tMin = 1,
  30. tMax = 26,
  31. skew = 38,
  32. damp = 700,
  33. initialBias = 72,
  34. initialN = 128, // 0x80
  35. delimiter = '-', // '\x2D'
  36. /** Regular expressions */
  37. regexPunycode = /^xn--/,
  38. regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
  39. regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators
  40. /** Error messages */
  41. errors = {
  42. 'overflow': 'Overflow: input needs wider integers to process',
  43. 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
  44. 'invalid-input': 'Invalid input'
  45. },
  46. /** Convenience shortcuts */
  47. baseMinusTMin = base - tMin,
  48. floor = Math.floor,
  49. stringFromCharCode = String.fromCharCode,
  50. /** Temporary variable */
  51. key;
  52. /* --------------------------------------------------------------------------*/
  53. /**
  54. * A generic error utility function.
  55. * @private
  56. * @param {String} type The error type.
  57. * @returns {Error} Throws a `RangeError` with the applicable error message.
  58. */
  59. function error (type) {
  60. throw RangeError(errors[type]);
  61. }
  62. /**
  63. * A generic `Array#map` utility function.
  64. * @private
  65. * @param {Array} array The array to iterate over.
  66. * @param {Function} callback The function that gets called for every array
  67. * item.
  68. * @returns {Array} A new array of values returned by the callback function.
  69. */
  70. function map (array, fn) {
  71. var length = array.length;
  72. while (length--) {
  73. array[length] = fn(array[length]);
  74. }
  75. return array;
  76. }
  77. /**
  78. * A simple `Array#map`-like wrapper to work with domain name strings.
  79. * @private
  80. * @param {String} domain The domain name.
  81. * @param {Function} callback The function that gets called for every
  82. * character.
  83. * @returns {Array} A new string of characters returned by the callback
  84. * function.
  85. */
  86. function mapDomain (string, fn) {
  87. return map(string.split(regexSeparators), fn).join('.');
  88. }
  89. /**
  90. * Creates an array containing the numeric code points of each Unicode
  91. * character in the string. While JavaScript uses UCS-2 internally,
  92. * this function will convert a pair of surrogate halves (each of which
  93. * UCS-2 exposes as separate characters) into a single code point,
  94. * matching UTF-16.
  95. * @see `punycode.ucs2.encode`
  96. * @see <http://mathiasbynens.be/notes/javascript-encoding>
  97. * @memberOf punycode.ucs2
  98. * @name decode
  99. * @param {String} string The Unicode input string (UCS-2).
  100. * @returns {Array} The new array of code points.
  101. */
  102. function ucs2decode (string) {
  103. var output = [],
  104. counter = 0,
  105. length = string.length,
  106. value,
  107. extra;
  108. while (counter < length) {
  109. value = string.charCodeAt(counter++);
  110. if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
  111. // high surrogate, and there is a next character
  112. extra = string.charCodeAt(counter++);
  113. if ((extra & 0xFC00) == 0xDC00) { // low surrogate
  114. output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
  115. } else {
  116. // unmatched surrogate; only append this code unit, in case the next
  117. // code unit is the high surrogate of a surrogate pair
  118. output.push(value);
  119. counter--;
  120. }
  121. } else {
  122. output.push(value);
  123. }
  124. }
  125. return output;
  126. }
  127. /**
  128. * Creates a string based on an array of numeric code points.
  129. * @see `punycode.ucs2.decode`
  130. * @memberOf punycode.ucs2
  131. * @name encode
  132. * @param {Array} codePoints The array of numeric code points.
  133. * @returns {String} The new Unicode string (UCS-2).
  134. */
  135. function ucs2encode (array) {
  136. return map(array, function (value) {
  137. var output = '';
  138. if (value > 0xFFFF) {
  139. value -= 0x10000;
  140. output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
  141. value = 0xDC00 | value & 0x3FF;
  142. }
  143. output += stringFromCharCode(value);
  144. return output;
  145. }).join('');
  146. }
  147. /**
  148. * Converts a basic code point into a digit/integer.
  149. * @see `digitToBasic()`
  150. * @private
  151. * @param {Number} codePoint The basic numeric code point value.
  152. * @returns {Number} The numeric value of a basic code point (for use in
  153. * representing integers) in the range `0` to `base - 1`, or `base` if
  154. * the code point does not represent a value.
  155. */
  156. function basicToDigit (codePoint) {
  157. if (codePoint - 48 < 10) {
  158. return codePoint - 22;
  159. }
  160. if (codePoint - 65 < 26) {
  161. return codePoint - 65;
  162. }
  163. if (codePoint - 97 < 26) {
  164. return codePoint - 97;
  165. }
  166. return base;
  167. }
  168. /**
  169. * Converts a digit/integer into a basic code point.
  170. * @see `basicToDigit()`
  171. * @private
  172. * @param {Number} digit The numeric value of a basic code point.
  173. * @returns {Number} The basic code point whose value (when used for
  174. * representing integers) is `digit`, which needs to be in the range
  175. * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
  176. * used; else, the lowercase form is used. The behavior is undefined
  177. * if `flag` is non-zero and `digit` has no uppercase form.
  178. */
  179. function digitToBasic (digit, flag) {
  180. // 0..25 map to ASCII a..z or A..Z
  181. // 26..35 map to ASCII 0..9
  182. return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
  183. }
  184. /**
  185. * Bias adaptation function as per section 3.4 of RFC 3492.
  186. * http://tools.ietf.org/html/rfc3492#section-3.4
  187. * @private
  188. */
  189. function adapt (delta, numPoints, firstTime) {
  190. var k = 0;
  191. delta = firstTime ? floor(delta / damp) : delta >> 1;
  192. delta += floor(delta / numPoints);
  193. for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
  194. delta = floor(delta / baseMinusTMin);
  195. }
  196. return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
  197. }
  198. /**
  199. * Converts a Punycode string of ASCII-only symbols to a string of Unicode
  200. * symbols.
  201. * @memberOf punycode
  202. * @param {String} input The Punycode string of ASCII-only symbols.
  203. * @returns {String} The resulting string of Unicode symbols.
  204. */
  205. function decode (input) {
  206. // Don't use UCS-2
  207. var output = [],
  208. inputLength = input.length,
  209. out,
  210. i = 0,
  211. n = initialN,
  212. bias = initialBias,
  213. basic,
  214. j,
  215. index,
  216. oldi,
  217. w,
  218. k,
  219. digit,
  220. t,
  221. /** Cached calculation results */
  222. baseMinusT;
  223. // Handle the basic code points: let `basic` be the number of input code
  224. // points before the last delimiter, or `0` if there is none, then copy
  225. // the first basic code points to the output.
  226. basic = input.lastIndexOf(delimiter);
  227. if (basic < 0) {
  228. basic = 0;
  229. }
  230. for (j = 0; j < basic; ++j) {
  231. // if it's not a basic code point
  232. if (input.charCodeAt(j) >= 0x80) {
  233. error('not-basic');
  234. }
  235. output.push(input.charCodeAt(j));
  236. }
  237. // Main decoding loop: start just after the last delimiter if any basic code
  238. // points were copied; start at the beginning otherwise.
  239. for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
  240. // `index` is the index of the next character to be consumed.
  241. // Decode a generalized variable-length integer into `delta`,
  242. // which gets added to `i`. The overflow checking is easier
  243. // if we increase `i` as we go, then subtract off its starting
  244. // value at the end to obtain `delta`.
  245. for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
  246. if (index >= inputLength) {
  247. error('invalid-input');
  248. }
  249. digit = basicToDigit(input.charCodeAt(index++));
  250. if (digit >= base || digit > floor((maxInt - i) / w)) {
  251. error('overflow');
  252. }
  253. i += digit * w;
  254. t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
  255. if (digit < t) {
  256. break;
  257. }
  258. baseMinusT = base - t;
  259. if (w > floor(maxInt / baseMinusT)) {
  260. error('overflow');
  261. }
  262. w *= baseMinusT;
  263. }
  264. out = output.length + 1;
  265. bias = adapt(i - oldi, out, oldi == 0);
  266. // `i` was supposed to wrap around from `out` to `0`,
  267. // incrementing `n` each time, so we'll fix that now:
  268. if (floor(i / out) > maxInt - n) {
  269. error('overflow');
  270. }
  271. n += floor(i / out);
  272. i %= out;
  273. // Insert `n` at position `i` of the output
  274. output.splice(i++, 0, n);
  275. }
  276. return ucs2encode(output);
  277. }
  278. /**
  279. * Converts a string of Unicode symbols to a Punycode string of ASCII-only
  280. * symbols.
  281. * @memberOf punycode
  282. * @param {String} input The string of Unicode symbols.
  283. * @returns {String} The resulting Punycode string of ASCII-only symbols.
  284. */
  285. function encode (input) {
  286. var n,
  287. delta,
  288. handledCPCount,
  289. basicLength,
  290. bias,
  291. j,
  292. m,
  293. q,
  294. k,
  295. t,
  296. currentValue,
  297. output = [],
  298. /** `inputLength` will hold the number of code points in `input`. */
  299. inputLength,
  300. /** Cached calculation results */
  301. handledCPCountPlusOne,
  302. baseMinusT,
  303. qMinusT;
  304. // Convert the input in UCS-2 to Unicode
  305. input = ucs2decode(input);
  306. // Cache the length
  307. inputLength = input.length;
  308. // Initialize the state
  309. n = initialN;
  310. delta = 0;
  311. bias = initialBias;
  312. // Handle the basic code points
  313. for (j = 0; j < inputLength; ++j) {
  314. currentValue = input[j];
  315. if (currentValue < 0x80) {
  316. output.push(stringFromCharCode(currentValue));
  317. }
  318. }
  319. handledCPCount = basicLength = output.length;
  320. // `handledCPCount` is the number of code points that have been handled;
  321. // `basicLength` is the number of basic code points.
  322. // Finish the basic string - if it is not empty - with a delimiter
  323. if (basicLength) {
  324. output.push(delimiter);
  325. }
  326. // Main encoding loop:
  327. while (handledCPCount < inputLength) {
  328. // All non-basic code points < n have been handled already. Find the next
  329. // larger one:
  330. for (m = maxInt, j = 0; j < inputLength; ++j) {
  331. currentValue = input[j];
  332. if (currentValue >= n && currentValue < m) {
  333. m = currentValue;
  334. }
  335. }
  336. // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
  337. // but guard against overflow
  338. handledCPCountPlusOne = handledCPCount + 1;
  339. if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
  340. error('overflow');
  341. }
  342. delta += (m - n) * handledCPCountPlusOne;
  343. n = m;
  344. for (j = 0; j < inputLength; ++j) {
  345. currentValue = input[j];
  346. if (currentValue < n && ++delta > maxInt) {
  347. error('overflow');
  348. }
  349. if (currentValue == n) {
  350. // Represent delta as a generalized variable-length integer
  351. for (q = delta, k = base; /* no condition */; k += base) {
  352. t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
  353. if (q < t) {
  354. break;
  355. }
  356. qMinusT = q - t;
  357. baseMinusT = base - t;
  358. output.push(
  359. stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
  360. );
  361. q = floor(qMinusT / baseMinusT);
  362. }
  363. output.push(stringFromCharCode(digitToBasic(q, 0)));
  364. bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
  365. delta = 0;
  366. ++handledCPCount;
  367. }
  368. }
  369. ++delta;
  370. ++n;
  371. }
  372. return output.join('');
  373. }
  374. /**
  375. * Converts a Punycode string representing a domain name to Unicode. Only the
  376. * Punycoded parts of the domain name will be converted, i.e. it doesn't
  377. * matter if you call it on a string that has already been converted to
  378. * Unicode.
  379. * @memberOf punycode
  380. * @param {String} domain The Punycode domain name to convert to Unicode.
  381. * @returns {String} The Unicode representation of the given Punycode
  382. * string.
  383. */
  384. function toUnicode (domain) {
  385. return mapDomain(domain, function (string) {
  386. return regexPunycode.test(string)
  387. ? decode(string.slice(4).toLowerCase())
  388. : string;
  389. });
  390. }
  391. /**
  392. * Converts a Unicode string representing a domain name to Punycode. Only the
  393. * non-ASCII parts of the domain name will be converted, i.e. it doesn't
  394. * matter if you call it with a domain that's already in ASCII.
  395. * @memberOf punycode
  396. * @param {String} domain The domain name to convert, as a Unicode string.
  397. * @returns {String} The Punycode representation of the given domain name.
  398. */
  399. function toASCII (domain) {
  400. return mapDomain(domain, function (string) {
  401. return regexNonASCII.test(string)
  402. ? 'xn--' + encode(string)
  403. : string;
  404. });
  405. }
  406. /* --------------------------------------------------------------------------*/
  407. /** Define the public API */
  408. punycode = {
  409. /**
  410. * A string representing the current Punycode.js version number.
  411. * @memberOf punycode
  412. * @type String
  413. */
  414. 'version': '1.2.4',
  415. /**
  416. * An object of methods to convert from JavaScript's internal character
  417. * representation (UCS-2) to Unicode code points, and back.
  418. * @see <http://mathiasbynens.be/notes/javascript-encoding>
  419. * @memberOf punycode
  420. * @type Object
  421. */
  422. 'ucs2': {
  423. 'decode': ucs2decode,
  424. 'encode': ucs2encode
  425. },
  426. 'decode': decode,
  427. 'encode': encode,
  428. 'toASCII': toASCII,
  429. 'toUnicode': toUnicode
  430. };
  431. /** Expose `punycode` */
  432. // Some AMD build optimizers, like r.js, check for specific condition patterns
  433. // like the following:
  434. if (
  435. typeof define === 'function' &&
  436. typeof define.amd === 'object' &&
  437. define.amd
  438. ) {
  439. define('punycode', function () {
  440. return punycode;
  441. });
  442. } else if (freeExports && !freeExports.nodeType) {
  443. if (freeModule) { // in Node.js or RingoJS v0.8.0+
  444. freeModule.exports = punycode;
  445. } else { // in Narwhal or RingoJS v0.7.0-
  446. for (key in punycode) {
  447. punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
  448. }
  449. }
  450. } else { // in Rhino or a web browser
  451. root.punycode = punycode;
  452. }
  453. }(this));
  454. }).call(this, typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : {})
  455. }, {}],
  456. 2: [function (_dereq_, module, exports) {
  457. var log = _dereq_('./log');
  458. function restoreOwnerScroll (ownerDocument, x, y) {
  459. if (ownerDocument.defaultView && (x !== ownerDocument.defaultView.pageXOffset || y !== ownerDocument.defaultView.pageYOffset)) {
  460. ownerDocument.defaultView.scrollTo(x, y);
  461. }
  462. }
  463. function cloneCanvasContents (canvas, clonedCanvas) {
  464. try {
  465. if (clonedCanvas) {
  466. clonedCanvas.width = canvas.width;
  467. clonedCanvas.height = canvas.height;
  468. clonedCanvas.getContext('2d').putImageData(canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height), 0, 0);
  469. }
  470. } catch (e) {
  471. log('Unable to copy canvas content from', canvas, e);
  472. }
  473. }
  474. function cloneNode (node, javascriptEnabled) {
  475. var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
  476. var child = node.firstChild;
  477. while (child) {
  478. if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
  479. clone.appendChild(cloneNode(child, javascriptEnabled));
  480. }
  481. child = child.nextSibling;
  482. }
  483. if (node.nodeType === 1) {
  484. clone._scrollTop = node.scrollTop;
  485. clone._scrollLeft = node.scrollLeft;
  486. if (node.nodeName === 'CANVAS') {
  487. cloneCanvasContents(node, clone);
  488. } else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') {
  489. clone.value = node.value;
  490. }
  491. }
  492. return clone;
  493. }
  494. function initNode (node) {
  495. if (node.nodeType === 1) {
  496. node.scrollTop = node._scrollTop;
  497. node.scrollLeft = node._scrollLeft;
  498. var child = node.firstChild;
  499. while (child) {
  500. initNode(child);
  501. child = child.nextSibling;
  502. }
  503. }
  504. }
  505. module.exports = function (ownerDocument, containerDocument, width, height, options, x,y) {
  506. var documentElement = cloneNode(ownerDocument.documentElement, options.javascriptEnabled);
  507. var container = containerDocument.createElement('iframe');
  508. container.className = 'html2canvas-container';
  509. container.style.visibility = 'hidden';
  510. container.style.position = 'fixed';
  511. container.style.left = '-10000px';
  512. container.style.top = '0px';
  513. container.style.border = '0';
  514. container.width = width;
  515. container.height = height;
  516. container.scrolling = 'no'; // ios won't scroll without it
  517. containerDocument.body.appendChild(container);
  518. return new Promise(function (resolve) {
  519. var documentClone = container.contentWindow.document;
  520. /* Chrome doesn't detect relative background-images assigned in inline <style> sheets when fetched through getComputedStyle
  521. if window url is about:blank, we can assign the url to current by writing onto the document
  522. */
  523. container.contentWindow.onload = container.onload = function () {
  524. var interval = setInterval(function () {
  525. if (documentClone.body.childNodes.length > 0) {
  526. initNode(documentClone.documentElement);
  527. clearInterval(interval);
  528. if (options.type === 'view') {
  529. container.contentWindow.scrollTo(x, y);
  530. if ((/(iPad|iPhone|iPod)/g).test(navigator.userAgent) && (container.contentWindow.scrollY !== y || container.contentWindow.scrollX !== x)) {
  531. documentClone.documentElement.style.top = (-y) + 'px';
  532. documentClone.documentElement.style.left = (-x) + 'px';
  533. documentClone.documentElement.style.position = 'absolute';
  534. }
  535. }
  536. resolve(container);
  537. }
  538. }, 50);
  539. };
  540. documentClone.open();
  541. documentClone.write('<!DOCTYPE html><html></html>');
  542. // Chrome scrolls the parent document for some reason after the write to the cloned window???
  543. restoreOwnerScroll(ownerDocument, x, y);
  544. documentClone.replaceChild(documentClone.adoptNode(documentElement), documentClone.documentElement);
  545. documentClone.close();
  546. });
  547. };
  548. }, {'./log': 13}],
  549. 3: [function (_dereq_, module, exports) {
  550. // http://dev.w3.org/csswg/css-color/
  551. function Color (value) {
  552. this.r = 0;
  553. this.g = 0;
  554. this.b = 0;
  555. this.a = null;
  556. var result = this.fromArray(value) ||
  557. this.namedColor(value) ||
  558. this.rgb(value) ||
  559. this.rgba(value) ||
  560. this.hex6(value) ||
  561. this.hex3(value);
  562. }
  563. Color.prototype.darken = function (amount) {
  564. var a = 1 - amount;
  565. return new Color([
  566. Math.round(this.r * a),
  567. Math.round(this.g * a),
  568. Math.round(this.b * a),
  569. this.a
  570. ]);
  571. };
  572. Color.prototype.isTransparent = function () {
  573. return this.a === 0;
  574. };
  575. Color.prototype.isBlack = function () {
  576. return this.r === 0 && this.g === 0 && this.b === 0;
  577. };
  578. Color.prototype.fromArray = function (array) {
  579. if (Array.isArray(array)) {
  580. this.r = Math.min(array[0], 255);
  581. this.g = Math.min(array[1], 255);
  582. this.b = Math.min(array[2], 255);
  583. if (array.length > 3) {
  584. this.a = array[3];
  585. }
  586. }
  587. return (Array.isArray(array));
  588. };
  589. var _hex3 = /^#([a-f0-9]{3})$/i;
  590. Color.prototype.hex3 = function (value) {
  591. var match = null;
  592. if ((match = value.match(_hex3)) !== null) {
  593. this.r = parseInt(match[1][0] + match[1][0], 16);
  594. this.g = parseInt(match[1][1] + match[1][1], 16);
  595. this.b = parseInt(match[1][2] + match[1][2], 16);
  596. }
  597. return match !== null;
  598. };
  599. var _hex6 = /^#([a-f0-9]{6})$/i;
  600. Color.prototype.hex6 = function (value) {
  601. var match = null;
  602. if ((match = value.match(_hex6)) !== null) {
  603. this.r = parseInt(match[1].substring(0, 2), 16);
  604. this.g = parseInt(match[1].substring(2, 4), 16);
  605. this.b = parseInt(match[1].substring(4, 6), 16);
  606. }
  607. return match !== null;
  608. };
  609. var _rgb = /^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/;
  610. Color.prototype.rgb = function (value) {
  611. var match = null;
  612. if ((match = value.match(_rgb)) !== null) {
  613. this.r = Number(match[1]);
  614. this.g = Number(match[2]);
  615. this.b = Number(match[3]);
  616. }
  617. return match !== null;
  618. };
  619. var _rgba = /^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d?\.?\d+)\s*\)$/;
  620. Color.prototype.rgba = function (value) {
  621. var match = null;
  622. if ((match = value.match(_rgba)) !== null) {
  623. this.r = Number(match[1]);
  624. this.g = Number(match[2]);
  625. this.b = Number(match[3]);
  626. this.a = Number(match[4]);
  627. }
  628. return match !== null;
  629. };
  630. Color.prototype.toString = function () {
  631. return this.a !== null && this.a !== 1
  632. ? 'rgba(' + [this.r, this.g, this.b, this.a].join(',') + ')'
  633. : 'rgb(' + [this.r, this.g, this.b].join(',') + ')';
  634. };
  635. Color.prototype.namedColor = function (value) {
  636. value = value.toLowerCase();
  637. var color = colors[value];
  638. if (color) {
  639. this.r = color[0];
  640. this.g = color[1];
  641. this.b = color[2];
  642. } else if (value === 'transparent') {
  643. this.r = this.g = this.b = this.a = 0;
  644. return true;
  645. }
  646. return !!color;
  647. };
  648. Color.prototype.isColor = true;
  649. // JSON.stringify([].slice.call($$('.named-color-table tr'), 1).map(function(row) { return [row.childNodes[3].textContent, row.childNodes[5].textContent.trim().split(",").map(Number)] }).reduce(function(data, row) {data[row[0]] = row[1]; return data}, {}))
  650. var colors = {
  651. 'aliceblue': [240, 248, 255],
  652. 'antiquewhite': [250, 235, 215],
  653. 'aqua': [0, 255, 255],
  654. 'aquamarine': [127, 255, 212],
  655. 'azure': [240, 255, 255],
  656. 'beige': [245, 245, 220],
  657. 'bisque': [255, 228, 196],
  658. 'black': [0, 0, 0],
  659. 'blanchedalmond': [255, 235, 205],
  660. 'blue': [0, 0, 255],
  661. 'blueviolet': [138, 43, 226],
  662. 'brown': [165, 42, 42],
  663. 'burlywood': [222, 184, 135],
  664. 'cadetblue': [95, 158, 160],
  665. 'chartreuse': [127, 255, 0],
  666. 'chocolate': [210, 105, 30],
  667. 'coral': [255, 127, 80],
  668. 'cornflowerblue': [100, 149, 237],
  669. 'cornsilk': [255, 248, 220],
  670. 'crimson': [220, 20, 60],
  671. 'cyan': [0, 255, 255],
  672. 'darkblue': [0, 0, 139],
  673. 'darkcyan': [0, 139, 139],
  674. 'darkgoldenrod': [184, 134, 11],
  675. 'darkgray': [169, 169, 169],
  676. 'darkgreen': [0, 100, 0],
  677. 'darkgrey': [169, 169, 169],
  678. 'darkkhaki': [189, 183, 107],
  679. 'darkmagenta': [139, 0, 139],
  680. 'darkolivegreen': [85, 107, 47],
  681. 'darkorange': [255, 140, 0],
  682. 'darkorchid': [153, 50, 204],
  683. 'darkred': [139, 0, 0],
  684. 'darksalmon': [233, 150, 122],
  685. 'darkseagreen': [143, 188, 143],
  686. 'darkslateblue': [72, 61, 139],
  687. 'darkslategray': [47, 79, 79],
  688. 'darkslategrey': [47, 79, 79],
  689. 'darkturquoise': [0, 206, 209],
  690. 'darkviolet': [148, 0, 211],
  691. 'deeppink': [255, 20, 147],
  692. 'deepskyblue': [0, 191, 255],
  693. 'dimgray': [105, 105, 105],
  694. 'dimgrey': [105, 105, 105],
  695. 'dodgerblue': [30, 144, 255],
  696. 'firebrick': [178, 34, 34],
  697. 'floralwhite': [255, 250, 240],
  698. 'forestgreen': [34, 139, 34],
  699. 'fuchsia': [255, 0, 255],
  700. 'gainsboro': [220, 220, 220],
  701. 'ghostwhite': [248, 248, 255],
  702. 'gold': [255, 215, 0],
  703. 'goldenrod': [218, 165, 32],
  704. 'gray': [128, 128, 128],
  705. 'green': [0, 128, 0],
  706. 'greenyellow': [173, 255, 47],
  707. 'grey': [128, 128, 128],
  708. 'honeydew': [240, 255, 240],
  709. 'hotpink': [255, 105, 180],
  710. 'indianred': [205, 92, 92],
  711. 'indigo': [75, 0, 130],
  712. 'ivory': [255, 255, 240],
  713. 'khaki': [240, 230, 140],
  714. 'lavender': [230, 230, 250],
  715. 'lavenderblush': [255, 240, 245],
  716. 'lawngreen': [124, 252, 0],
  717. 'lemonchiffon': [255, 250, 205],
  718. 'lightblue': [173, 216, 230],
  719. 'lightcoral': [240, 128, 128],
  720. 'lightcyan': [224, 255, 255],
  721. 'lightgoldenrodyellow': [250, 250, 210],
  722. 'lightgray': [211, 211, 211],
  723. 'lightgreen': [144, 238, 144],
  724. 'lightgrey': [211, 211, 211],
  725. 'lightpink': [255, 182, 193],
  726. 'lightsalmon': [255, 160, 122],
  727. 'lightseagreen': [32, 178, 170],
  728. 'lightskyblue': [135, 206, 250],
  729. 'lightslategray': [119, 136, 153],
  730. 'lightslategrey': [119, 136, 153],
  731. 'lightsteelblue': [176, 196, 222],
  732. 'lightyellow': [255, 255, 224],
  733. 'lime': [0, 255, 0],
  734. 'limegreen': [50, 205, 50],
  735. 'linen': [250, 240, 230],
  736. 'magenta': [255, 0, 255],
  737. 'maroon': [128, 0, 0],
  738. 'mediumaquamarine': [102, 205, 170],
  739. 'mediumblue': [0, 0, 205],
  740. 'mediumorchid': [186, 85, 211],
  741. 'mediumpurple': [147, 112, 219],
  742. 'mediumseagreen': [60, 179, 113],
  743. 'mediumslateblue': [123, 104, 238],
  744. 'mediumspringgreen': [0, 250, 154],
  745. 'mediumturquoise': [72, 209, 204],
  746. 'mediumvioletred': [199, 21, 133],
  747. 'midnightblue': [25, 25, 112],
  748. 'mintcream': [245, 255, 250],
  749. 'mistyrose': [255, 228, 225],
  750. 'moccasin': [255, 228, 181],
  751. 'navajowhite': [255, 222, 173],
  752. 'navy': [0, 0, 128],
  753. 'oldlace': [253, 245, 230],
  754. 'olive': [128, 128, 0],
  755. 'olivedrab': [107, 142, 35],
  756. 'orange': [255, 165, 0],
  757. 'orangered': [255, 69, 0],
  758. 'orchid': [218, 112, 214],
  759. 'palegoldenrod': [238, 232, 170],
  760. 'palegreen': [152, 251, 152],
  761. 'paleturquoise': [175, 238, 238],
  762. 'palevioletred': [219, 112, 147],
  763. 'papayawhip': [255, 239, 213],
  764. 'peachpuff': [255, 218, 185],
  765. 'peru': [205, 133, 63],
  766. 'pink': [255, 192, 203],
  767. 'plum': [221, 160, 221],
  768. 'powderblue': [176, 224, 230],
  769. 'purple': [128, 0, 128],
  770. 'rebeccapurple': [102, 51, 153],
  771. 'red': [255, 0, 0],
  772. 'rosybrown': [188, 143, 143],
  773. 'royalblue': [65, 105, 225],
  774. 'saddlebrown': [139, 69, 19],
  775. 'salmon': [250, 128, 114],
  776. 'sandybrown': [244, 164, 96],
  777. 'seagreen': [46, 139, 87],
  778. 'seashell': [255, 245, 238],
  779. 'sienna': [160, 82, 45],
  780. 'silver': [192, 192, 192],
  781. 'skyblue': [135, 206, 235],
  782. 'slateblue': [106, 90, 205],
  783. 'slategray': [112, 128, 144],
  784. 'slategrey': [112, 128, 144],
  785. 'snow': [255, 250, 250],
  786. 'springgreen': [0, 255, 127],
  787. 'steelblue': [70, 130, 180],
  788. 'tan': [210, 180, 140],
  789. 'teal': [0, 128, 128],
  790. 'thistle': [216, 191, 216],
  791. 'tomato': [255, 99, 71],
  792. 'turquoise': [64, 224, 208],
  793. 'violet': [238, 130, 238],
  794. 'wheat': [245, 222, 179],
  795. 'white': [255, 255, 255],
  796. 'whitesmoke': [245, 245, 245],
  797. 'yellow': [255, 255, 0],
  798. 'yellowgreen': [154, 205, 50]
  799. };
  800. module.exports = Color;
  801. }, {}],
  802. 4: [function (_dereq_, module, exports) {
  803. var Support = _dereq_('./support');
  804. var CanvasRenderer = _dereq_('./renderers/canvas');
  805. var ImageLoader = _dereq_('./imageloader');
  806. var NodeParser = _dereq_('./nodeparser');
  807. var NodeContainer = _dereq_('./nodecontainer');
  808. var log = _dereq_('./log');
  809. var utils = _dereq_('./utils');
  810. var createWindowClone = _dereq_('./clone');
  811. var loadUrlDocument = _dereq_('./proxy').loadUrlDocument;
  812. var getBounds = utils.getBounds;
  813. var html2canvasNodeAttribute = 'data-html2canvas-node';
  814. var html2canvasCloneIndex = 0;
  815. function html2canvas (nodeList, options) {
  816. var index = html2canvasCloneIndex++;
  817. options = options || {};
  818. if (options.logging) {
  819. log.options.logging = true;
  820. log.options.start = Date.now();
  821. }
  822. options.async = typeof (options.async) === 'undefined' ? true : options.async;
  823. options.allowTaint = typeof (options.allowTaint) === 'undefined' ? false : options.allowTaint;
  824. options.removeContainer = typeof (options.removeContainer) === 'undefined' ? true : options.removeContainer;
  825. options.javascriptEnabled = typeof (options.javascriptEnabled) === 'undefined' ? false : options.javascriptEnabled;
  826. options.imageTimeout = typeof (options.imageTimeout) === 'undefined' ? 10000 : options.imageTimeout;
  827. options.renderer = typeof (options.renderer) === 'function' ? options.renderer : CanvasRenderer;
  828. options.strict = !!options.strict;
  829. if (typeof (nodeList) === 'string') {
  830. if (typeof (options.proxy) !== 'string') {
  831. return Promise.reject('Proxy must be used when rendering url');
  832. }
  833. var width = options.width != null ? options.width : window.innerWidth;
  834. var height = options.height != null ? options.height : window.innerHeight;
  835. return loadUrlDocument(absoluteUrl(nodeList), options.proxy, document, width, height, options).then(function (container) {
  836. return renderWindow(container.contentWindow.document.documentElement, container, options, width, height);
  837. });
  838. }
  839. var node = ((nodeList === undefined) ? [document.documentElement] : ((nodeList.length) ? nodeList : [nodeList]))[0];
  840. node.setAttribute(html2canvasNodeAttribute + index, index);
  841. // return renderDocument(node.ownerDocument, options, node.ownerDocument.defaultView.innerWidth, node.ownerDocument.defaultView.innerHeight, index).then(function(canvas) {
  842. var width = options.width != null ? options.width : node.ownerDocument.defaultView.innerWidth;
  843. var height = options.height != null ? options.height : node.ownerDocument.defaultView.innerHeight;
  844. return renderDocument(node.ownerDocument, options, width, height, index).then(function (canvas) {
  845. if (typeof (options.onrendered) === 'function') {
  846. log('options.onrendered is deprecated, html2canvas returns a Promise containing the canvas');
  847. options.onrendered(canvas);
  848. }
  849. return canvas;
  850. });
  851. }
  852. html2canvas.CanvasRenderer = CanvasRenderer;
  853. html2canvas.NodeContainer = NodeContainer;
  854. html2canvas.log = log;
  855. html2canvas.utils = utils;
  856. var html2canvasExport = (typeof (document) === 'undefined' || typeof (Object.create) !== 'function' || typeof (document.createElement('canvas').getContext) !== 'function') ? function () {
  857. return Promise.reject('No canvas support');
  858. } : html2canvas;
  859. module.exports = html2canvasExport;
  860. if (typeof (define) === 'function' && define.amd) {
  861. define('html2canvas', [], function () {
  862. return html2canvasExport;
  863. });
  864. }
  865. function renderDocument (document, options, windowWidth, windowHeight, html2canvasIndex) {
  866. return createWindowClone(document, document, windowWidth, windowHeight, options, document.defaultView.pageXOffset, document.defaultView.pageYOffset).then(function (container) {
  867. log('Document cloned');
  868. var attributeName = html2canvasNodeAttribute + html2canvasIndex;
  869. var selector = '[' + attributeName + "='" + html2canvasIndex + "']";
  870. document.querySelector(selector).removeAttribute(attributeName);
  871. var clonedWindow = container.contentWindow;
  872. var node = clonedWindow.document.querySelector(selector);
  873. var oncloneHandler = (typeof (options.onclone) === 'function') ? Promise.resolve(options.onclone(clonedWindow.document)) : Promise.resolve(true);
  874. return oncloneHandler.then(function () {
  875. return renderWindow(node, container, options, windowWidth, windowHeight);
  876. });
  877. });
  878. }
  879. function renderWindow (node, container, options, windowWidth, windowHeight) {
  880. var clonedWindow = container.contentWindow;
  881. var support = new Support(clonedWindow.document);
  882. var imageLoader = new ImageLoader(options, support);
  883. var bounds = getBounds(node);
  884. var width = options.type === 'view' ? windowWidth : documentWidth(clonedWindow.document);
  885. var height = options.type === 'view' ? windowHeight : documentHeight(clonedWindow.document);
  886. var renderer = new options.renderer(width, height, imageLoader, options, document);
  887. var parser = new NodeParser(node, renderer, support, imageLoader, options);
  888. return parser.ready.then(function () {
  889. log('Finished rendering');
  890. var canvas;
  891. if (options.type === 'view') {
  892. canvas = crop(renderer.canvas, {width: renderer.canvas.width, height: renderer.canvas.height, top: 0, left: 0, x: 0, y: 0});
  893. } else if (node === clonedWindow.document.body || node === clonedWindow.document.documentElement || options.canvas != null) {
  894. canvas = renderer.canvas;
  895. } else {
  896. canvas = crop(renderer.canvas, {width: options.width != null ? options.width : bounds.width, height: options.height != null ? options.height : bounds.height, top: bounds.top, left: bounds.left, x: 0, y: 0});
  897. }
  898. cleanupContainer(container, options);
  899. return canvas;
  900. });
  901. }
  902. function cleanupContainer (container, options) {
  903. if (options.removeContainer) {
  904. container.parentNode.removeChild(container);
  905. log('Cleaned up container');
  906. }
  907. }
  908. function crop (canvas, bounds) {
  909. var croppedCanvas = document.createElement('canvas');
  910. var x1 = Math.min(canvas.width - 1, Math.max(0, bounds.left));
  911. var x2 = Math.min(canvas.width, Math.max(1, bounds.left + bounds.width));
  912. var y1 = Math.min(canvas.height - 1, Math.max(0, bounds.top));
  913. var y2 = Math.min(canvas.height, Math.max(1, bounds.top + bounds.height));
  914. croppedCanvas.width = bounds.width;
  915. croppedCanvas.height = bounds.height;
  916. var width = x2 - x1;
  917. var height = y2 - y1;
  918. log('Cropping canvas at:', 'left:', bounds.left, 'top:', bounds.top, 'width:', width, 'height:', height);
  919. log('Resulting crop with width', bounds.width, 'and height', bounds.height, 'with x', x1, 'and y', y1);
  920. croppedCanvas.getContext('2d').drawImage(canvas, x1, y1, width, height, bounds.x, bounds.y, width, height);
  921. return croppedCanvas;
  922. }
  923. function documentWidth (doc) {
  924. return Math.max(
  925. Math.max(doc.body.scrollWidth, doc.documentElement.scrollWidth),
  926. Math.max(doc.body.offsetWidth, doc.documentElement.offsetWidth),
  927. Math.max(doc.body.clientWidth, doc.documentElement.clientWidth)
  928. );
  929. }
  930. function documentHeight (doc) {
  931. return Math.max(
  932. Math.max(doc.body.scrollHeight, doc.documentElement.scrollHeight),
  933. Math.max(doc.body.offsetHeight, doc.documentElement.offsetHeight),
  934. Math.max(doc.body.clientHeight, doc.documentElement.clientHeight)
  935. );
  936. }
  937. function absoluteUrl (url) {
  938. var link = document.createElement('a');
  939. link.href = url;
  940. link.href = link.href;
  941. return link;
  942. }
  943. }, {'./clone': 2, './imageloader': 11, './log': 13, './nodecontainer': 14, './nodeparser': 15, './proxy': 16, './renderers/canvas': 20, './support': 22, './utils': 26}],
  944. 5: [function (_dereq_, module, exports) {
  945. var log = _dereq_('./log');
  946. var smallImage = _dereq_('./utils').smallImage;
  947. function DummyImageContainer (src) {
  948. this.src = src;
  949. log('DummyImageContainer for', src);
  950. if (!this.promise || !this.image) {
  951. log('Initiating DummyImageContainer');
  952. DummyImageContainer.prototype.image = new Image();
  953. var image = this.image;
  954. DummyImageContainer.prototype.promise = new Promise(function (resolve, reject) {
  955. image.onload = resolve;
  956. image.onerror = reject;
  957. image.src = smallImage();
  958. if (image.complete === true) {
  959. resolve(image);
  960. }
  961. });
  962. }
  963. }
  964. module.exports = DummyImageContainer;
  965. }, {'./log': 13, './utils': 26}],
  966. 6: [function (_dereq_, module, exports) {
  967. var smallImage = _dereq_('./utils').smallImage;
  968. function Font (family, size) {
  969. var container = document.createElement('div'),
  970. img = document.createElement('img'),
  971. span = document.createElement('span'),
  972. sampleText = 'Hidden Text',
  973. baseline,
  974. middle;
  975. container.style.visibility = 'hidden';
  976. container.style.fontFamily = family;
  977. container.style.fontSize = size;
  978. container.style.margin = 0;
  979. container.style.padding = 0;
  980. document.body.appendChild(container);
  981. img.src = smallImage();
  982. img.width = 1;
  983. img.height = 1;
  984. img.style.margin = 0;
  985. img.style.padding = 0;
  986. img.style.verticalAlign = 'baseline';
  987. span.style.fontFamily = family;
  988. span.style.fontSize = size;
  989. span.style.margin = 0;
  990. span.style.padding = 0;
  991. span.appendChild(document.createTextNode(sampleText));
  992. container.appendChild(span);
  993. container.appendChild(img);
  994. baseline = (img.offsetTop - span.offsetTop) + 1;
  995. container.removeChild(span);
  996. container.appendChild(document.createTextNode(sampleText));
  997. container.style.lineHeight = 'normal';
  998. img.style.verticalAlign = 'super';
  999. middle = (img.offsetTop - container.offsetTop) + 1;
  1000. document.body.removeChild(container);
  1001. this.baseline = baseline;
  1002. this.lineWidth = 1;
  1003. this.middle = middle;
  1004. }
  1005. module.exports = Font;
  1006. }, {'./utils': 26}],
  1007. 7: [function (_dereq_, module, exports) {
  1008. var Font = _dereq_('./font');
  1009. function FontMetrics () {
  1010. this.data = {};
  1011. }
  1012. FontMetrics.prototype.getMetrics = function (family, size) {
  1013. if (this.data[family + '-' + size] === undefined) {
  1014. this.data[family + '-' + size] = new Font(family, size);
  1015. }
  1016. return this.data[family + '-' + size];
  1017. };
  1018. module.exports = FontMetrics;
  1019. }, {'./font': 6}],
  1020. 8: [function (_dereq_, module, exports) {
  1021. var utils = _dereq_('./utils');
  1022. var getBounds = utils.getBounds;
  1023. var loadUrlDocument = _dereq_('./proxy').loadUrlDocument;
  1024. function FrameContainer (container, sameOrigin, options) {
  1025. this.image = null;
  1026. this.src = container;
  1027. var self = this;
  1028. var bounds = getBounds(container);
  1029. this.promise = (!sameOrigin ? this.proxyLoad(options.proxy, bounds, options) : new Promise(function (resolve) {
  1030. if (container.contentWindow.document.URL === 'about:blank' || container.contentWindow.document.documentElement == null) {
  1031. container.contentWindow.onload = container.onload = function () {
  1032. resolve(container);
  1033. };
  1034. } else {
  1035. resolve(container);
  1036. }
  1037. })).then(function (container) {
  1038. var html2canvas = _dereq_('./core');
  1039. return html2canvas(container.contentWindow.document.documentElement, {type: 'view', width: container.width, height: container.height, proxy: options.proxy, javascriptEnabled: options.javascriptEnabled, removeContainer: options.removeContainer, allowTaint: options.allowTaint, imageTimeout: options.imageTimeout / 2});
  1040. }).then(function (canvas) {
  1041. return self.image = canvas;
  1042. });
  1043. }
  1044. FrameContainer.prototype.proxyLoad = function (proxy, bounds, options) {
  1045. var container = this.src;
  1046. return loadUrlDocument(container.src, proxy, container.ownerDocument, bounds.width, bounds.height, options);
  1047. };
  1048. module.exports = FrameContainer;
  1049. }, {'./core': 4, './proxy': 16, './utils': 26}],
  1050. 9: [function (_dereq_, module, exports) {
  1051. function GradientContainer (imageData) {
  1052. this.src = imageData.value;
  1053. this.colorStops = [];
  1054. this.type = null;
  1055. this.x0 = 0.5;
  1056. this.y0 = 0.5;
  1057. this.x1 = 0.5;
  1058. this.y1 = 0.5;
  1059. this.promise = Promise.resolve(true);
  1060. }
  1061. GradientContainer.TYPES = {
  1062. LINEAR: 1,
  1063. RADIAL: 2
  1064. };
  1065. // TODO: support hsl[a], negative %/length values
  1066. // TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle )
  1067. GradientContainer.REGEXP_COLORSTOP = /^\s*(rgba?\(\s*\d{1,3},\s*\d{1,3},\s*\d{1,3}(?:,\s*[0-9\.]+)?\s*\)|[a-z]{3,20}|#[a-f0-9]{3,6})(?:\s+(\d{1,3}(?:\.\d+)?)(%|px)?)?(?:\s|$)/i;
  1068. module.exports = GradientContainer;
  1069. }, {}],
  1070. 10: [function (_dereq_, module, exports) {
  1071. function ImageContainer (src, cors) {
  1072. this.src = src;
  1073. this.image = new Image();
  1074. var self = this;
  1075. this.tainted = null;
  1076. this.promise = new Promise(function (resolve, reject) {
  1077. self.image.onload = resolve;
  1078. self.image.onerror = reject;
  1079. if (cors) {
  1080. self.image.crossOrigin = 'anonymous';
  1081. }
  1082. self.image.src = src;
  1083. if (self.image.complete === true) {
  1084. resolve(self.image);
  1085. }
  1086. });
  1087. }
  1088. module.exports = ImageContainer;
  1089. }, {}],
  1090. 11: [function (_dereq_, module, exports) {
  1091. var log = _dereq_('./log');
  1092. var ImageContainer = _dereq_('./imagecontainer');
  1093. var DummyImageContainer = _dereq_('./dummyimagecontainer');
  1094. var ProxyImageContainer = _dereq_('./proxyimagecontainer');
  1095. var FrameContainer = _dereq_('./framecontainer');
  1096. var SVGContainer = _dereq_('./svgcontainer');
  1097. var SVGNodeContainer = _dereq_('./svgnodecontainer');
  1098. var LinearGradientContainer = _dereq_('./lineargradientcontainer');
  1099. var WebkitGradientContainer = _dereq_('./webkitgradientcontainer');
  1100. var bind = _dereq_('./utils').bind;
  1101. function ImageLoader (options, support) {
  1102. this.link = null;
  1103. this.options = options;
  1104. this.support = support;
  1105. this.origin = this.getOrigin(window.location.href);
  1106. }
  1107. ImageLoader.prototype.findImages = function (nodes) {
  1108. var images = [];
  1109. nodes.reduce(function (imageNodes, container) {
  1110. switch (container.node.nodeName) {
  1111. case 'IMG':
  1112. return imageNodes.concat([{
  1113. args: [container.node.src],
  1114. method: 'url'
  1115. }]);
  1116. case 'svg':
  1117. case 'IFRAME':
  1118. return imageNodes.concat([{
  1119. args: [container.node],
  1120. method: container.node.nodeName
  1121. }]);
  1122. }
  1123. return imageNodes;
  1124. }, []).forEach(this.addImage(images, this.loadImage), this);
  1125. return images;
  1126. };
  1127. ImageLoader.prototype.findBackgroundImage = function (images, container) {
  1128. container.parseBackgroundImages().filter(this.hasImageBackground).forEach(this.addImage(images, this.loadImage), this);
  1129. return images;
  1130. };
  1131. ImageLoader.prototype.addImage = function (images, callback) {
  1132. return function (newImage) {
  1133. newImage.args.forEach(function (image) {
  1134. if (!this.imageExists(images, image)) {
  1135. images.splice(0, 0, callback.call(this, newImage));
  1136. log('Added image #' + (images.length), typeof (image) === 'string' ? image.substring(0, 100) : image);
  1137. }
  1138. }, this);
  1139. };
  1140. };
  1141. ImageLoader.prototype.hasImageBackground = function (imageData) {
  1142. return imageData.method !== 'none';
  1143. };
  1144. ImageLoader.prototype.loadImage = function (imageData) {
  1145. if (imageData.method === 'url') {
  1146. var src = imageData.args[0];
  1147. if (this.isSVG(src) && !this.support.svg && !this.options.allowTaint) {
  1148. return new SVGContainer(src);
  1149. } else if (src.match(/data:image\/.*;base64,/i)) {
  1150. return new ImageContainer(src.replace(/url\(['"]{0,}|['"]{0,}\)$/ig, ''), false);
  1151. } else if (this.isSameOrigin(src) || this.options.allowTaint === true || this.isSVG(src)) {
  1152. return new ImageContainer(src, false);
  1153. } else if (this.support.cors && !this.options.allowTaint && this.options.useCORS) {
  1154. return new ImageContainer(src, true);
  1155. } else if (this.options.proxy) {
  1156. return new ProxyImageContainer(src, this.options.proxy);
  1157. } else {
  1158. return new DummyImageContainer(src);
  1159. }
  1160. } else if (imageData.method === 'linear-gradient') {
  1161. return new LinearGradientContainer(imageData);
  1162. } else if (imageData.method === 'gradient') {
  1163. return new WebkitGradientContainer(imageData);
  1164. } else if (imageData.method === 'svg') {
  1165. return new SVGNodeContainer(imageData.args[0], this.support.svg);
  1166. } else if (imageData.method === 'IFRAME') {
  1167. return new FrameContainer(imageData.args[0], this.isSameOrigin(imageData.args[0].src), this.options);
  1168. } else {
  1169. return new DummyImageContainer(imageData);
  1170. }
  1171. };
  1172. ImageLoader.prototype.isSVG = function (src) {
  1173. return src.substring(src.length - 3).toLowerCase() === 'svg' || SVGContainer.prototype.isInline(src);
  1174. };
  1175. ImageLoader.prototype.imageExists = function (images, src) {
  1176. return images.some(function (image) {
  1177. return image.src === src;
  1178. });
  1179. };
  1180. ImageLoader.prototype.isSameOrigin = function (url) {
  1181. return (this.getOrigin(url) === this.origin);
  1182. };
  1183. ImageLoader.prototype.getOrigin = function (url) {
  1184. var link = this.link || (this.link = document.createElement('a'));
  1185. link.href = url;
  1186. link.href = link.href; // IE9, LOL! - http://jsfiddle.net/niklasvh/2e48b/
  1187. return link.protocol + link.hostname + link.port;
  1188. };
  1189. ImageLoader.prototype.getPromise = function (container) {
  1190. return this.timeout(container, this.options.imageTimeout)['catch'](function () {
  1191. var dummy = new DummyImageContainer(container.src);
  1192. return dummy.promise.then(function (image) {
  1193. container.image = image;
  1194. });
  1195. });
  1196. };
  1197. ImageLoader.prototype.get = function (src) {
  1198. var found = null;
  1199. return this.images.some(function (img) {
  1200. return (found = img).src === src;
  1201. }) ? found : null;
  1202. };
  1203. ImageLoader.prototype.fetch = function (nodes) {
  1204. this.images = nodes.reduce(bind(this.findBackgroundImage, this), this.findImages(nodes));
  1205. this.images.forEach(function (image, index) {
  1206. image.promise.then(function () {
  1207. log('Succesfully loaded image #' + (index + 1), image);
  1208. }, function (e) {
  1209. log('Failed loading image #' + (index + 1), image, e);
  1210. });
  1211. });
  1212. this.ready = Promise.all(this.images.map(this.getPromise, this));
  1213. log('Finished searching images');
  1214. return this;
  1215. };
  1216. ImageLoader.prototype.timeout = function (container, timeout) {
  1217. var timer;
  1218. var promise = Promise.race([container.promise, new Promise(function (resolve, reject) {
  1219. timer = setTimeout(function () {
  1220. log('Timed out loading image', container);
  1221. reject(container);
  1222. }, timeout);
  1223. })]).then(function (container) {
  1224. clearTimeout(timer);
  1225. return container;
  1226. });
  1227. promise['catch'](function () {
  1228. clearTimeout(timer);
  1229. });
  1230. return promise;
  1231. };
  1232. module.exports = ImageLoader;
  1233. }, {'./dummyimagecontainer': 5, './framecontainer': 8, './imagecontainer': 10, './lineargradientcontainer': 12, './log': 13, './proxyimagecontainer': 17, './svgcontainer': 23, './svgnodecontainer': 24, './utils': 26, './webkitgradientcontainer': 27}],
  1234. 12: [function (_dereq_, module, exports) {
  1235. var GradientContainer = _dereq_('./gradientcontainer');
  1236. var Color = _dereq_('./color');
  1237. function LinearGradientContainer (imageData) {
  1238. GradientContainer.apply(this, arguments);
  1239. this.type = GradientContainer.TYPES.LINEAR;
  1240. var hasDirection = LinearGradientContainer.REGEXP_DIRECTION.test(imageData.args[0]) ||
  1241. !GradientContainer.REGEXP_COLORSTOP.test(imageData.args[0]);
  1242. if (hasDirection) {
  1243. imageData.args[0].split(/\s+/).reverse().forEach(function (position, index) {
  1244. switch (position) {
  1245. case 'left':
  1246. this.x0 = 0;
  1247. this.x1 = 1;
  1248. break;
  1249. case 'top':
  1250. this.y0 = 0;
  1251. this.y1 = 1;
  1252. break;
  1253. case 'right':
  1254. this.x0 = 1;
  1255. this.x1 = 0;
  1256. break;
  1257. case 'bottom':
  1258. this.y0 = 1;
  1259. this.y1 = 0;
  1260. break;
  1261. case 'to':
  1262. var y0 = this.y0;
  1263. var x0 = this.x0;
  1264. this.y0 = this.y1;
  1265. this.x0 = this.x1;
  1266. this.x1 = x0;
  1267. this.y1 = y0;
  1268. break;
  1269. case 'center':
  1270. break; // centered by default
  1271. // Firefox internally converts position keywords to percentages:
  1272. // http://www.w3.org/TR/2010/WD-CSS2-20101207/colors.html#propdef-background-position
  1273. default: // percentage or absolute length
  1274. // TODO: support absolute start point positions (e.g., use bounds to convert px to a ratio)
  1275. var ratio = parseFloat(position, 10) * 1e-2;
  1276. if (isNaN(ratio)) { // invalid or unhandled value
  1277. break;
  1278. }
  1279. if (index === 0) {
  1280. this.y0 = ratio;
  1281. this.y1 = 1 - this.y0;
  1282. } else {
  1283. this.x0 = ratio;
  1284. this.x1 = 1 - this.x0;
  1285. }
  1286. break;
  1287. }
  1288. }, this);
  1289. } else {
  1290. this.y0 = 0;
  1291. this.y1 = 1;
  1292. }
  1293. this.colorStops = imageData.args.slice(hasDirection ? 1 : 0).map(function (colorStop) {
  1294. var colorStopMatch = colorStop.match(GradientContainer.REGEXP_COLORSTOP);
  1295. var value = +colorStopMatch[2];
  1296. var unit = value === 0 ? '%' : colorStopMatch[3]; // treat "0" as "0%"
  1297. return {
  1298. color: new Color(colorStopMatch[1]),
  1299. // TODO: support absolute stop positions (e.g., compute gradient line length & convert px to ratio)
  1300. stop: unit === '%' ? value / 100 : null
  1301. };
  1302. });
  1303. if (this.colorStops[0].stop === null) {
  1304. this.colorStops[0].stop = 0;
  1305. }
  1306. if (this.colorStops[this.colorStops.length - 1].stop === null) {
  1307. this.colorStops[this.colorStops.length - 1].stop = 1;
  1308. }
  1309. // calculates and fills-in explicit stop positions when omitted from rule
  1310. this.colorStops.forEach(function (colorStop, index) {
  1311. if (colorStop.stop === null) {
  1312. this.colorStops.slice(index).some(function (find, count) {
  1313. if (find.stop !== null) {
  1314. colorStop.stop = ((find.stop - this.colorStops[index - 1].stop) / (count + 1)) + this.colorStops[index - 1].stop;
  1315. return true;
  1316. } else {
  1317. return false;
  1318. }
  1319. }, this);
  1320. }
  1321. }, this);
  1322. }
  1323. LinearGradientContainer.prototype = Object.create(GradientContainer.prototype);
  1324. // TODO: support <angle> (e.g. -?\d{1,3}(?:\.\d+)deg, etc. : https://developer.mozilla.org/docs/Web/CSS/angle )
  1325. LinearGradientContainer.REGEXP_DIRECTION = /^\s*(?:to|left|right|top|bottom|center|\d{1,3}(?:\.\d+)?%?)(?:\s|$)/i;
  1326. module.exports = LinearGradientContainer;
  1327. }, {'./color': 3, './gradientcontainer': 9}],
  1328. 13: [function (_dereq_, module, exports) {
  1329. var logger = function () {
  1330. if (logger.options.logging && window.console && window.console.log) {
  1331. Function.prototype.bind.call(window.console.log, (window.console)).apply(window.console, [(Date.now() - logger.options.start) + 'ms', 'html2canvas:'].concat([].slice.call(arguments, 0)));
  1332. }
  1333. };
  1334. logger.options = {logging: false};
  1335. module.exports = logger;
  1336. }, {}],
  1337. 14: [function (_dereq_, module, exports) {
  1338. var Color = _dereq_('./color');
  1339. var utils = _dereq_('./utils');
  1340. var getBounds = utils.getBounds;
  1341. var parseBackgrounds = utils.parseBackgrounds;
  1342. var offsetBounds = utils.offsetBounds;
  1343. function NodeContainer (node, parent) {
  1344. this.node = node;
  1345. this.parent = parent;
  1346. this.stack = null;
  1347. this.bounds = null;
  1348. this.borders = null;
  1349. this.clip = [];
  1350. this.backgroundClip = [];
  1351. this.offsetBounds = null;
  1352. this.visible = null;
  1353. this.computedStyles = null;
  1354. this.colors = {};
  1355. this.styles = {};
  1356. this.backgroundImages = null;
  1357. this.transformData = null;
  1358. this.transformMatrix = null;
  1359. this.isPseudoElement = false;
  1360. this.opacity = null;
  1361. }
  1362. NodeContainer.prototype.cloneTo = function (stack) {
  1363. stack.visible = this.visible;
  1364. stack.borders = this.borders;
  1365. stack.bounds = this.bounds;
  1366. stack.clip = this.clip;
  1367. stack.backgroundClip = this.backgroundClip;
  1368. stack.computedStyles = this.computedStyles;
  1369. stack.styles = this.styles;
  1370. stack.backgroundImages = this.backgroundImages;
  1371. stack.opacity = this.opacity;
  1372. };
  1373. NodeContainer.prototype.getOpacity = function () {
  1374. return this.opacity === null ? (this.opacity = this.cssFloat('opacity')) : this.opacity;
  1375. };
  1376. NodeContainer.prototype.assignStack = function (stack) {
  1377. this.stack = stack;
  1378. stack.children.push(this);
  1379. };
  1380. NodeContainer.prototype.isElementVisible = function () {
  1381. return this.node.nodeType === Node.TEXT_NODE ? this.parent.visible : (
  1382. this.css('display') !== 'none' &&
  1383. this.css('visibility') !== 'hidden' &&
  1384. !this.node.hasAttribute('data-html2canvas-ignore') &&
  1385. (this.node.nodeName !== 'INPUT' || this.node.getAttribute('type') !== 'hidden')
  1386. );
  1387. };
  1388. NodeContainer.prototype.css = function (attribute) {
  1389. if (!this.computedStyles) {
  1390. this.computedStyles = this.isPseudoElement ? this.parent.computedStyle(this.before ? ':before' : ':after') : this.computedStyle(null);
  1391. }
  1392. return this.styles[attribute] || (this.styles[attribute] = this.computedStyles[attribute]);
  1393. };
  1394. NodeContainer.prototype.prefixedCss = function (attribute) {
  1395. var prefixes = ['webkit', 'moz', 'ms', 'o'];
  1396. var value = this.css(attribute);
  1397. if (value === undefined) {
  1398. prefixes.some(function (prefix) {
  1399. value = this.css(prefix + attribute.substr(0, 1).toUpperCase() + attribute.substr(1));
  1400. return value !== undefined;
  1401. }, this);
  1402. }
  1403. return value === undefined ? null : value;
  1404. };
  1405. NodeContainer.prototype.computedStyle = function (type) {
  1406. return this.node.ownerDocument.defaultView.getComputedStyle(this.node, type);
  1407. };
  1408. NodeContainer.prototype.cssInt = function (attribute) {
  1409. var value = parseInt(this.css(attribute), 10);
  1410. return (isNaN(value)) ? 0 : value; // borders in old IE are throwing 'medium' for demo.html
  1411. };
  1412. NodeContainer.prototype.color = function (attribute) {
  1413. return this.colors[attribute] || (this.colors[attribute] = new Color(this.css(attribute)));
  1414. };
  1415. NodeContainer.prototype.cssFloat = function (attribute) {
  1416. var value = parseFloat(this.css(attribute));
  1417. return (isNaN(value)) ? 0 : value;
  1418. };
  1419. NodeContainer.prototype.fontWeight = function () {
  1420. var weight = this.css('fontWeight');
  1421. switch (parseInt(weight, 10)) {
  1422. case 401:
  1423. weight = 'bold';
  1424. break;
  1425. case 400:
  1426. weight = 'normal';
  1427. break;
  1428. }
  1429. return weight;
  1430. };
  1431. NodeContainer.prototype.parseClip = function () {
  1432. var matches = this.css('clip').match(this.CLIP);
  1433. if (matches) {
  1434. return {
  1435. top: parseInt(matches[1], 10),
  1436. right: parseInt(matches[2], 10),
  1437. bottom: parseInt(matches[3], 10),
  1438. left: parseInt(matches[4], 10)
  1439. };
  1440. }
  1441. return null;
  1442. };
  1443. NodeContainer.prototype.parseBackgroundImages = function () {
  1444. return this.backgroundImages || (this.backgroundImages = parseBackgrounds(this.css('backgroundImage')));
  1445. };
  1446. NodeContainer.prototype.cssList = function (property, index) {
  1447. var value = (this.css(property) || '').split(',');
  1448. value = value[index || 0] || value[0] || 'auto';
  1449. value = value.trim().split(' ');
  1450. if (value.length === 1) {
  1451. value = [value[0], isPercentage(value[0]) ? 'auto' : value[0]];
  1452. }
  1453. return value;
  1454. };
  1455. NodeContainer.prototype.parseBackgroundSize = function (bounds, image, index) {
  1456. var size = this.cssList('backgroundSize', index);
  1457. var width, height;
  1458. if (isPercentage(size[0])) {
  1459. width = bounds.width * parseFloat(size[0]) / 100;
  1460. } else if (/contain|cover/.test(size[0])) {
  1461. var targetRatio = bounds.width / bounds.height, currentRatio = image.width / image.height;
  1462. return (targetRatio < currentRatio ^ size[0] === 'contain') ? {width: bounds.height * currentRatio, height: bounds.height} : {width: bounds.width, height: bounds.width / currentRatio};
  1463. } else {
  1464. width = parseInt(size[0], 10);
  1465. }
  1466. if (size[0] === 'auto' && size[1] === 'auto') {
  1467. height = image.height;
  1468. } else if (size[1] === 'auto') {
  1469. height = width / image.width * image.height;
  1470. } else if (isPercentage(size[1])) {
  1471. height = bounds.height * parseFloat(size[1]) / 100;
  1472. } else {
  1473. height = parseInt(size[1], 10);
  1474. }
  1475. if (size[0] === 'auto') {
  1476. width = height / image.height * image.width;
  1477. }
  1478. return {width: width, height: height};
  1479. };
  1480. NodeContainer.prototype.parseBackgroundPosition = function (bounds, image, index, backgroundSize) {
  1481. var position = this.cssList('backgroundPosition', index);
  1482. var left, top;
  1483. if (isPercentage(position[0])) {
  1484. left = (bounds.width - (backgroundSize || image).width) * (parseFloat(position[0]) / 100);
  1485. } else {
  1486. left = parseInt(position[0], 10);
  1487. }
  1488. if (position[1] === 'auto') {
  1489. top = left / image.width * image.height;
  1490. } else if (isPercentage(position[1])) {
  1491. top = (bounds.height - (backgroundSize || image).height) * parseFloat(position[1]) / 100;
  1492. } else {
  1493. top = parseInt(position[1], 10);
  1494. }
  1495. if (position[0] === 'auto') {
  1496. left = top / image.height * image.width;
  1497. }
  1498. return {left: left, top: top};
  1499. };
  1500. NodeContainer.prototype.parseBackgroundRepeat = function (index) {
  1501. return this.cssList('backgroundRepeat', index)[0];
  1502. };
  1503. NodeContainer.prototype.parseTextShadows = function () {
  1504. var textShadow = this.css('textShadow');
  1505. var results = [];
  1506. if (textShadow && textShadow !== 'none') {
  1507. var shadows = textShadow.match(this.TEXT_SHADOW_PROPERTY);
  1508. for (var i = 0; shadows && (i < shadows.length); i++) {
  1509. var s = shadows[i].match(this.TEXT_SHADOW_VALUES);
  1510. results.push({
  1511. color: new Color(s[0]),
  1512. offsetX: s[1] ? parseFloat(s[1].replace('px', '')) : 0,
  1513. offsetY: s[2] ? parseFloat(s[2].replace('px', '')) : 0,
  1514. blur: s[3] ? s[3].replace('px', '') : 0
  1515. });
  1516. }
  1517. }
  1518. return results;
  1519. };
  1520. NodeContainer.prototype.parseTransform = function () {
  1521. if (!this.transformData) {
  1522. if (this.hasTransform()) {
  1523. var offset = this.parseBounds();
  1524. var origin = this.prefixedCss('transformOrigin').split(' ').map(removePx).map(asFloat);
  1525. origin[0] += offset.left;
  1526. origin[1] += offset.top;
  1527. this.transformData = {
  1528. origin: origin,
  1529. matrix: this.parseTransformMatrix()
  1530. };
  1531. } else {
  1532. this.transformData = {
  1533. origin: [0, 0],
  1534. matrix: [1, 0, 0, 1, 0, 0]
  1535. };
  1536. }
  1537. }
  1538. return this.transformData;
  1539. };
  1540. NodeContainer.prototype.parseTransformMatrix = function () {
  1541. if (!this.transformMatrix) {
  1542. var transform = this.prefixedCss('transform');
  1543. var matrix = transform ? parseMatrix(transform.match(this.MATRIX_PROPERTY)) : null;
  1544. this.transformMatrix = matrix || [1, 0, 0, 1, 0, 0];
  1545. }
  1546. return this.transformMatrix;
  1547. };
  1548. NodeContainer.prototype.parseBounds = function () {
  1549. return this.bounds || (this.bounds = this.hasTransform() ? offsetBounds(this.node) : getBounds(this.node));
  1550. };
  1551. NodeContainer.prototype.hasTransform = function () {
  1552. return this.parseTransformMatrix().join(',') !== '1,0,0,1,0,0' || (this.parent && this.parent.hasTransform());
  1553. };
  1554. NodeContainer.prototype.getValue = function () {
  1555. var value = this.node.value || '';
  1556. if (this.node.tagName === 'SELECT') {
  1557. value = selectionValue(this.node);
  1558. } else if (this.node.type === 'password') {
  1559. value = Array(value.length + 1).join('\u2022'); // jshint ignore:line
  1560. }
  1561. return value.length === 0 ? (this.node.placeholder || '') : value;
  1562. };
  1563. NodeContainer.prototype.MATRIX_PROPERTY = /(matrix|matrix3d)\((.+)\)/;
  1564. NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
  1565. NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;
  1566. NodeContainer.prototype.CLIP = /^rect\((\d+)px,? (\d+)px,? (\d+)px,? (\d+)px\)$/;
  1567. function selectionValue (node) {
  1568. var option = node.options[node.selectedIndex || 0];
  1569. return option ? (option.text || '') : '';
  1570. }
  1571. function parseMatrix (match) {
  1572. if (match && match[1] === 'matrix') {
  1573. return match[2].split(',').map(function (s) {
  1574. return parseFloat(s.trim());
  1575. });
  1576. } else if (match && match[1] === 'matrix3d') {
  1577. var matrix3d = match[2].split(',').map(function (s) {
  1578. return parseFloat(s.trim());
  1579. });
  1580. return [matrix3d[0], matrix3d[1], matrix3d[4], matrix3d[5], matrix3d[12], matrix3d[13]];
  1581. }
  1582. }
  1583. function isPercentage (value) {
  1584. return value.toString().indexOf('%') !== -1;
  1585. }
  1586. function removePx (str) {
  1587. return str.replace('px', '');
  1588. }
  1589. function asFloat (str) {
  1590. return parseFloat(str);
  1591. }
  1592. module.exports = NodeContainer;
  1593. }, {'./color': 3, './utils': 26}],
  1594. 15: [function (_dereq_, module, exports) {
  1595. var log = _dereq_('./log');
  1596. var punycode = _dereq_('punycode');
  1597. var NodeContainer = _dereq_('./nodecontainer');
  1598. var TextContainer = _dereq_('./textcontainer');
  1599. var PseudoElementContainer = _dereq_('./pseudoelementcontainer');
  1600. var FontMetrics = _dereq_('./fontmetrics');
  1601. var Color = _dereq_('./color');
  1602. var StackingContext = _dereq_('./stackingcontext');
  1603. var utils = _dereq_('./utils');
  1604. var bind = utils.bind;
  1605. var getBounds = utils.getBounds;
  1606. var parseBackgrounds = utils.parseBackgrounds;
  1607. var offsetBounds = utils.offsetBounds;
  1608. function NodeParser (element, renderer, support, imageLoader, options) {
  1609. log('Starting NodeParser');
  1610. this.renderer = renderer;
  1611. this.options = options;
  1612. this.range = null;
  1613. this.support = support;
  1614. this.renderQueue = [];
  1615. this.stack = new StackingContext(true, 1, element.ownerDocument, null);
  1616. var parent = new NodeContainer(element, null);
  1617. if (options.background) {
  1618. renderer.rectangle(0, 0, renderer.width, renderer.height, new Color(options.background));
  1619. }
  1620. if (element === element.ownerDocument.documentElement) {
  1621. // http://www.w3.org/TR/css3-background/#special-backgrounds
  1622. var canvasBackground = new NodeContainer(parent.color('backgroundColor').isTransparent() ? element.ownerDocument.body : element.ownerDocument.documentElement, null);
  1623. renderer.rectangle(0, 0, renderer.width, renderer.height, canvasBackground.color('backgroundColor'));
  1624. }
  1625. parent.visibile = parent.isElementVisible();
  1626. this.createPseudoHideStyles(element.ownerDocument);
  1627. this.disableAnimations(element.ownerDocument);
  1628. this.nodes = flatten([parent].concat(this.getChildren(parent)).filter(function (container) {
  1629. return container.visible = container.isElementVisible();
  1630. }).map(this.getPseudoElements, this));
  1631. this.fontMetrics = new FontMetrics();
  1632. log('Fetched nodes, total:', this.nodes.length);
  1633. log('Calculate overflow clips');
  1634. this.calculateOverflowClips();
  1635. log('Start fetching images');
  1636. this.images = imageLoader.fetch(this.nodes.filter(isElement));
  1637. this.ready = this.images.ready.then(bind(function () {
  1638. log('Images loaded, starting parsing');
  1639. log('Creating stacking contexts');
  1640. this.createStackingContexts();
  1641. log('Sorting stacking contexts');
  1642. this.sortStackingContexts(this.stack);
  1643. this.parse(this.stack);
  1644. log('Render queue created with ' + this.renderQueue.length + ' items');
  1645. return new Promise(bind(function (resolve) {
  1646. if (!options.async) {
  1647. this.renderQueue.forEach(this.paint, this);
  1648. resolve();
  1649. } else if (typeof (options.async) === 'function') {
  1650. options.async.call(this, this.renderQueue, resolve);
  1651. } else if (this.renderQueue.length > 0) {
  1652. this.renderIndex = 0;
  1653. this.asyncRenderer(this.renderQueue, resolve);
  1654. } else {
  1655. resolve();
  1656. }
  1657. }, this));
  1658. }, this));
  1659. }
  1660. NodeParser.prototype.calculateOverflowClips = function () {
  1661. this.nodes.forEach(function (container) {
  1662. if (isElement(container)) {
  1663. if (isPseudoElement(container)) {
  1664. container.appendToDOM();
  1665. }
  1666. container.borders = this.parseBorders(container);
  1667. var clip = (container.css('overflow') === 'hidden') ? [container.borders.clip] : [];
  1668. var cssClip = container.parseClip();
  1669. if (cssClip && ['absolute', 'fixed'].indexOf(container.css('position')) !== -1) {
  1670. clip.push([['rect',
  1671. container.bounds.left + cssClip.left,
  1672. container.bounds.top + cssClip.top,
  1673. cssClip.right - cssClip.left,
  1674. cssClip.bottom - cssClip.top
  1675. ]]);
  1676. }
  1677. container.clip = hasParentClip(container) ? container.parent.clip.concat(clip) : clip;
  1678. container.backgroundClip = (container.css('overflow') !== 'hidden') ? container.clip.concat([container.borders.clip]) : container.clip;
  1679. if (isPseudoElement(container)) {
  1680. container.cleanDOM();
  1681. }
  1682. } else if (isTextNode(container)) {
  1683. container.clip = hasParentClip(container) ? container.parent.clip : [];
  1684. }
  1685. if (!isPseudoElement(container)) {
  1686. container.bounds = null;
  1687. }
  1688. }, this);
  1689. };
  1690. function hasParentClip (container) {
  1691. return container.parent && container.parent.clip.length;
  1692. }
  1693. NodeParser.prototype.asyncRenderer = function (queue, resolve, asyncTimer) {
  1694. asyncTimer = asyncTimer || Date.now();
  1695. this.paint(queue[this.renderIndex++]);
  1696. if (queue.length === this.renderIndex) {
  1697. resolve();
  1698. } else if (asyncTimer + 20 > Date.now()) {
  1699. this.asyncRenderer(queue, resolve, asyncTimer);
  1700. } else {
  1701. setTimeout(bind(function () {
  1702. this.asyncRenderer(queue, resolve);
  1703. }, this), 0);
  1704. }
  1705. };
  1706. NodeParser.prototype.createPseudoHideStyles = function (document) {
  1707. this.createStyles(document, '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ':before { content: "" !important; display: none !important; }' +
  1708. '.' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER + ':after { content: "" !important; display: none !important; }');
  1709. };
  1710. NodeParser.prototype.disableAnimations = function (document) {
  1711. this.createStyles(document, '* { -webkit-animation: none !important; -moz-animation: none !important; -o-animation: none !important; animation: none !important; ' +
  1712. '-webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; transition: none !important;}');
  1713. };
  1714. NodeParser.prototype.createStyles = function (document, styles) {
  1715. var hidePseudoElements = document.createElement('style');
  1716. hidePseudoElements.innerHTML = styles;
  1717. document.body.appendChild(hidePseudoElements);
  1718. };
  1719. NodeParser.prototype.getPseudoElements = function (container) {
  1720. var nodes = [[container]];
  1721. if (container.node.nodeType === Node.ELEMENT_NODE) {
  1722. var before = this.getPseudoElement(container, ':before');
  1723. var after = this.getPseudoElement(container, ':after');
  1724. if (before) {
  1725. nodes.push(before);
  1726. }
  1727. if (after) {
  1728. nodes.push(after);
  1729. }
  1730. }
  1731. return flatten(nodes);
  1732. };
  1733. function toCamelCase (str) {
  1734. return str.replace(/(\-[a-z])/g, function (match) {
  1735. return match.toUpperCase().replace('-', '');
  1736. });
  1737. }
  1738. NodeParser.prototype.getPseudoElement = function (container, type) {
  1739. var style = container.computedStyle(type);
  1740. if (!style || !style.content || style.content === 'none' || style.content === '-moz-alt-content' || style.display === 'none') {
  1741. return null;
  1742. }
  1743. var content = stripQuotes(style.content);
  1744. var isImage = content.substr(0, 3) === 'url';
  1745. var pseudoNode = document.createElement(isImage ? 'img' : 'html2canvaspseudoelement');
  1746. var pseudoContainer = new PseudoElementContainer(pseudoNode, container, type);
  1747. for (var i = style.length - 1; i >= 0; i--) {
  1748. var property = toCamelCase(style.item(i));
  1749. pseudoNode.style[property] = style[property];
  1750. }
  1751. pseudoNode.className = PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE + ' ' + PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER;
  1752. if (isImage) {
  1753. pseudoNode.src = parseBackgrounds(content)[0].args[0];
  1754. return [pseudoContainer];
  1755. } else {
  1756. var text = document.createTextNode(content);
  1757. pseudoNode.appendChild(text);
  1758. return [pseudoContainer, new TextContainer(text, pseudoContainer)];
  1759. }
  1760. };
  1761. NodeParser.prototype.getChildren = function (parentContainer) {
  1762. return flatten([].filter.call(parentContainer.node.childNodes, renderableNode).map(function (node) {
  1763. var container = [node.nodeType === Node.TEXT_NODE ? new TextContainer(node, parentContainer) : new NodeContainer(node, parentContainer)].filter(nonIgnoredElement);
  1764. return node.nodeType === Node.ELEMENT_NODE && container.length && node.tagName !== 'TEXTAREA' ? (container[0].isElementVisible() ? container.concat(this.getChildren(container[0])) : []) : container;
  1765. }, this));
  1766. };
  1767. NodeParser.prototype.newStackingContext = function (container, hasOwnStacking) {
  1768. var stack = new StackingContext(hasOwnStacking, container.getOpacity(), container.node, container.parent);
  1769. container.cloneTo(stack);
  1770. var parentStack = hasOwnStacking ? stack.getParentStack(this) : stack.parent.stack;
  1771. parentStack.contexts.push(stack);
  1772. container.stack = stack;
  1773. };
  1774. NodeParser.prototype.createStackingContexts = function () {
  1775. this.nodes.forEach(function (container) {
  1776. if (isElement(container) && (this.isRootElement(container) || hasOpacity(container) || isPositionedForStacking(container) || this.isBodyWithTransparentRoot(container) || container.hasTransform())) {
  1777. this.newStackingContext(container, true);
  1778. } else if (isElement(container) && ((isPositioned(container) && zIndex0(container)) || isInlineBlock(container) || isFloating(container))) {
  1779. this.newStackingContext(container, false);
  1780. } else {
  1781. container.assignStack(container.parent.stack);
  1782. }
  1783. }, this);
  1784. };
  1785. NodeParser.prototype.isBodyWithTransparentRoot = function (container) {
  1786. return container.node.nodeName === 'BODY' && container.parent.color('backgroundColor').isTransparent();
  1787. };
  1788. NodeParser.prototype.isRootElement = function (container) {
  1789. return container.parent === null;
  1790. };
  1791. NodeParser.prototype.sortStackingContexts = function (stack) {
  1792. stack.contexts.sort(zIndexSort(stack.contexts.slice(0)));
  1793. stack.contexts.forEach(this.sortStackingContexts, this);
  1794. };
  1795. NodeParser.prototype.parseTextBounds = function (container) {
  1796. return function (text, index, textList) {
  1797. if (container.parent.css('textDecoration').substr(0, 4) !== 'none' || text.trim().length !== 0) {
  1798. if (this.support.rangeBounds && !container.parent.hasTransform()) {
  1799. var offset = textList.slice(0, index).join('').length;
  1800. return this.getRangeBounds(container.node, offset, text.length);
  1801. } else if (container.node && typeof (container.node.data) === 'string') {
  1802. var replacementNode = container.node.splitText(text.length);
  1803. var bounds = this.getWrapperBounds(container.node, container.parent.hasTransform());
  1804. container.node = replacementNode;
  1805. return bounds;
  1806. }
  1807. } else if (!this.support.rangeBounds || container.parent.hasTransform()) {
  1808. container.node = container.node.splitText(text.length);
  1809. }
  1810. return {};
  1811. };
  1812. };
  1813. NodeParser.prototype.getWrapperBounds = function (node, transform) {
  1814. var wrapper = node.ownerDocument.createElement('html2canvaswrapper');
  1815. var parent = node.parentNode,
  1816. backupText = node.cloneNode(true);
  1817. wrapper.appendChild(node.cloneNode(true));
  1818. parent.replaceChild(wrapper, node);
  1819. var bounds = transform ? offsetBounds(wrapper) : getBounds(wrapper);
  1820. parent.replaceChild(backupText, wrapper);
  1821. return bounds;
  1822. };
  1823. NodeParser.prototype.getRangeBounds = function (node, offset, length) {
  1824. var range = this.range || (this.range = node.ownerDocument.createRange());
  1825. range.setStart(node, offset);
  1826. range.setEnd(node, offset + length);
  1827. return range.getBoundingClientRect();
  1828. };
  1829. function ClearTransform () {}
  1830. NodeParser.prototype.parse = function (stack) {
  1831. // http://www.w3.org/TR/CSS21/visuren.html#z-index
  1832. var negativeZindex = stack.contexts.filter(negativeZIndex); // 2. the child stacking contexts with negative stack levels (most negative first).
  1833. var descendantElements = stack.children.filter(isElement);
  1834. var descendantNonFloats = descendantElements.filter(not(isFloating));
  1835. var nonInlineNonPositionedDescendants = descendantNonFloats.filter(not(isPositioned)).filter(not(inlineLevel)); // 3 the in-flow, non-inline-level, non-positioned descendants.
  1836. var nonPositionedFloats = descendantElements.filter(not(isPositioned)).filter(isFloating); // 4. the non-positioned floats.
  1837. var inFlow = descendantNonFloats.filter(not(isPositioned)).filter(inlineLevel); // 5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  1838. var stackLevel0 = stack.contexts.concat(descendantNonFloats.filter(isPositioned)).filter(zIndex0); // 6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  1839. var text = stack.children.filter(isTextNode).filter(hasText);
  1840. var positiveZindex = stack.contexts.filter(positiveZIndex); // 7. the child stacking contexts with positive stack levels (least positive first).
  1841. negativeZindex.concat(nonInlineNonPositionedDescendants).concat(nonPositionedFloats)
  1842. .concat(inFlow).concat(stackLevel0).concat(text).concat(positiveZindex).forEach(function (container) {
  1843. this.renderQueue.push(container);
  1844. if (isStackingContext(container)) {
  1845. this.parse(container);
  1846. this.renderQueue.push(new ClearTransform());
  1847. }
  1848. }, this);
  1849. };
  1850. NodeParser.prototype.paint = function (container) {
  1851. try {
  1852. if (container instanceof ClearTransform) {
  1853. this.renderer.ctx.restore();
  1854. } else if (isTextNode(container)) {
  1855. if (isPseudoElement(container.parent)) {
  1856. container.parent.appendToDOM();
  1857. }
  1858. this.paintText(container);
  1859. if (isPseudoElement(container.parent)) {
  1860. container.parent.cleanDOM();
  1861. }
  1862. } else {
  1863. this.paintNode(container);
  1864. }
  1865. } catch (e) {
  1866. log(e);
  1867. if (this.options.strict) {
  1868. throw e;
  1869. }
  1870. }
  1871. };
  1872. NodeParser.prototype.paintNode = function (container) {
  1873. if (isStackingContext(container)) {
  1874. this.renderer.setOpacity(container.opacity);
  1875. this.renderer.ctx.save();
  1876. if (container.hasTransform()) {
  1877. this.renderer.setTransform(container.parseTransform());
  1878. }
  1879. }
  1880. if (container.node.nodeName === 'INPUT' && container.node.type === 'checkbox') {
  1881. this.paintCheckbox(container);
  1882. } else if (container.node.nodeName === 'INPUT' && container.node.type === 'radio') {
  1883. this.paintRadio(container);
  1884. } else {
  1885. this.paintElement(container);
  1886. }
  1887. };
  1888. NodeParser.prototype.paintElement = function (container) {
  1889. var bounds = container.parseBounds();
  1890. this.renderer.clip(container.backgroundClip, function () {
  1891. this.renderer.renderBackground(container, bounds, container.borders.borders.map(getWidth));
  1892. }, this);
  1893. this.renderer.clip(container.clip, function () {
  1894. this.renderer.renderBorders(container.borders.borders);
  1895. }, this);
  1896. this.renderer.clip(container.backgroundClip, function () {
  1897. switch (container.node.nodeName) {
  1898. case 'svg':
  1899. case 'IFRAME':
  1900. var imgContainer = this.images.get(container.node);
  1901. if (imgContainer) {
  1902. this.renderer.renderImage(container, bounds, container.borders, imgContainer);
  1903. } else {
  1904. log('Error loading <' + container.node.nodeName + '>', container.node);
  1905. }
  1906. break;
  1907. case 'IMG':
  1908. var imageContainer = this.images.get(container.node.src);
  1909. if (imageContainer) {
  1910. this.renderer.renderImage(container, bounds, container.borders, imageContainer);
  1911. } else {
  1912. log('Error loading <img>', container.node.src);
  1913. }
  1914. break;
  1915. case 'CANVAS':
  1916. this.renderer.renderImage(container, bounds, container.borders, {image: container.node});
  1917. break;
  1918. case 'SELECT':
  1919. case 'INPUT':
  1920. case 'TEXTAREA':
  1921. this.paintFormValue(container);
  1922. break;
  1923. }
  1924. }, this);
  1925. };
  1926. NodeParser.prototype.paintCheckbox = function (container) {
  1927. var b = container.parseBounds();
  1928. var size = Math.min(b.width, b.height);
  1929. var bounds = {width: size - 1, height: size - 1, top: b.top, left: b.left};
  1930. var r = [3, 3];
  1931. var radius = [r, r, r, r];
  1932. var borders = [1, 1, 1, 1].map(function (w) {
  1933. return {color: new Color('#A5A5A5'), width: w};
  1934. });
  1935. var borderPoints = calculateCurvePoints(bounds, radius, borders);
  1936. this.renderer.clip(container.backgroundClip, function () {
  1937. this.renderer.rectangle(bounds.left + 1, bounds.top + 1, bounds.width - 2, bounds.height - 2, new Color('#DEDEDE'));
  1938. this.renderer.renderBorders(calculateBorders(borders, bounds, borderPoints, radius));
  1939. if (container.node.checked) {
  1940. this.renderer.font(new Color('#424242'), 'normal', 'normal', 'bold', (size - 3) + 'px', 'arial');
  1941. this.renderer.text('\u2714', bounds.left + size / 6, bounds.top + size - 1);
  1942. }
  1943. }, this);
  1944. };
  1945. NodeParser.prototype.paintRadio = function (container) {
  1946. var bounds = container.parseBounds();
  1947. var size = Math.min(bounds.width, bounds.height) - 2;
  1948. this.renderer.clip(container.backgroundClip, function () {
  1949. this.renderer.circleStroke(bounds.left + 1, bounds.top + 1, size, new Color('#DEDEDE'), 1, new Color('#A5A5A5'));
  1950. if (container.node.checked) {
  1951. this.renderer.circle(Math.ceil(bounds.left + size / 4) + 1, Math.ceil(bounds.top + size / 4) + 1, Math.floor(size / 2), new Color('#424242'));
  1952. }
  1953. }, this);
  1954. };
  1955. NodeParser.prototype.paintFormValue = function (container) {
  1956. var value = container.getValue();
  1957. if (value.length > 0) {
  1958. var document = container.node.ownerDocument;
  1959. var wrapper = document.createElement('html2canvaswrapper');
  1960. var properties = ['lineHeight', 'textAlign', 'fontFamily', 'fontWeight', 'fontSize', 'color',
  1961. 'paddingLeft', 'paddingTop', 'paddingRight', 'paddingBottom',
  1962. 'width', 'height', 'borderLeftStyle', 'borderTopStyle', 'borderLeftWidth', 'borderTopWidth',
  1963. 'boxSizing', 'whiteSpace', 'wordWrap'];
  1964. properties.forEach(function (property) {
  1965. try {
  1966. wrapper.style[property] = container.css(property);
  1967. } catch (e) {
  1968. // Older IE has issues with "border"
  1969. log('html2canvas: Parse: Exception caught in renderFormValue: ' + e.message);
  1970. }
  1971. });
  1972. var bounds = container.parseBounds();
  1973. wrapper.style.position = 'fixed';
  1974. wrapper.style.left = bounds.left + 'px';
  1975. wrapper.style.top = bounds.top + 'px';
  1976. wrapper.textContent = value;
  1977. document.body.appendChild(wrapper);
  1978. this.paintText(new TextContainer(wrapper.firstChild, container));
  1979. document.body.removeChild(wrapper);
  1980. }
  1981. };
  1982. NodeParser.prototype.paintText = function (container) {
  1983. container.applyTextTransform();
  1984. var characters = punycode.ucs2.decode(container.node.data);
  1985. var textList = (!this.options.letterRendering || noLetterSpacing(container)) && !hasUnicode(container.node.data) ? getWords(characters) : characters.map(function (character) {
  1986. return punycode.ucs2.encode([character]);
  1987. });
  1988. var weight = container.parent.fontWeight();
  1989. var size = container.parent.css('fontSize');
  1990. var family = container.parent.css('fontFamily');
  1991. var shadows = container.parent.parseTextShadows();
  1992. this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family);
  1993. if (shadows.length) {
  1994. // TODO: support multiple text shadows
  1995. this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
  1996. } else {
  1997. this.renderer.clearShadow();
  1998. }
  1999. this.renderer.clip(container.parent.clip, function () {
  2000. textList.map(this.parseTextBounds(container), this).forEach(function (bounds, index) {
  2001. if (bounds) {
  2002. this.renderer.text(textList[index], bounds.left, bounds.bottom);
  2003. this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
  2004. }
  2005. }, this);
  2006. }, this);
  2007. };
  2008. NodeParser.prototype.renderTextDecoration = function (container, bounds, metrics) {
  2009. switch (container.css('textDecoration').split(' ')[0]) {
  2010. case 'underline':
  2011. // Draws a line at the baseline of the font
  2012. // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
  2013. this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.color('color'));
  2014. break;
  2015. case 'overline':
  2016. this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.color('color'));
  2017. break;
  2018. case 'line-through':
  2019. // TODO try and find exact position for line-through
  2020. this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.color('color'));
  2021. break;
  2022. }
  2023. };
  2024. var borderColorTransforms = {
  2025. inset: [
  2026. ['darken', 0.60],
  2027. ['darken', 0.10],
  2028. ['darken', 0.10],
  2029. ['darken', 0.60]
  2030. ]
  2031. };
  2032. NodeParser.prototype.parseBorders = function (container) {
  2033. var nodeBounds = container.parseBounds();
  2034. var radius = getBorderRadiusData(container);
  2035. var borders = ['Top', 'Right', 'Bottom', 'Left'].map(function (side, index) {
  2036. var style = container.css('border' + side + 'Style');
  2037. var color = container.color('border' + side + 'Color');
  2038. if (style === 'inset' && color.isBlack()) {
  2039. color = new Color([255, 255, 255, color.a]); // this is wrong, but
  2040. }
  2041. var colorTransform = borderColorTransforms[style] ? borderColorTransforms[style][index] : null;
  2042. return {
  2043. width: container.cssInt('border' + side + 'Width'),
  2044. color: colorTransform ? color[colorTransform[0]](colorTransform[1]) : color,
  2045. args: null
  2046. };
  2047. });
  2048. var borderPoints = calculateCurvePoints(nodeBounds, radius, borders);
  2049. return {
  2050. clip: this.parseBackgroundClip(container, borderPoints, borders, radius, nodeBounds),
  2051. borders: calculateBorders(borders, nodeBounds, borderPoints, radius)
  2052. };
  2053. };
  2054. function calculateBorders (borders, nodeBounds, borderPoints, radius) {
  2055. return borders.map(function (border, borderSide) {
  2056. if (border.width > 0) {
  2057. var bx = nodeBounds.left;
  2058. var by = nodeBounds.top;
  2059. var bw = nodeBounds.width;
  2060. var bh = nodeBounds.height - (borders[2].width);
  2061. switch (borderSide) {
  2062. case 0:
  2063. // top border
  2064. bh = borders[0].width;
  2065. border.args = drawSide({
  2066. c1: [bx, by],
  2067. c2: [bx + bw, by],
  2068. c3: [bx + bw - borders[1].width, by + bh],
  2069. c4: [bx + borders[3].width, by + bh]
  2070. }, radius[0], radius[1],
  2071. borderPoints.topLeftOuter, borderPoints.topLeftInner, borderPoints.topRightOuter, borderPoints.topRightInner);
  2072. break;
  2073. case 1:
  2074. // right border
  2075. bx = nodeBounds.left + nodeBounds.width - (borders[1].width);
  2076. bw = borders[1].width;
  2077. border.args = drawSide({
  2078. c1: [bx + bw, by],
  2079. c2: [bx + bw, by + bh + borders[2].width],
  2080. c3: [bx, by + bh],
  2081. c4: [bx, by + borders[0].width]
  2082. }, radius[1], radius[2],
  2083. borderPoints.topRightOuter, borderPoints.topRightInner, borderPoints.bottomRightOuter, borderPoints.bottomRightInner);
  2084. break;
  2085. case 2:
  2086. // bottom border
  2087. by = (by + nodeBounds.height) - (borders[2].width);
  2088. bh = borders[2].width;
  2089. border.args = drawSide({
  2090. c1: [bx + bw, by + bh],
  2091. c2: [bx, by + bh],
  2092. c3: [bx + borders[3].width, by],
  2093. c4: [bx + bw - borders[3].width, by]
  2094. }, radius[2], radius[3],
  2095. borderPoints.bottomRightOuter, borderPoints.bottomRightInner, borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner);
  2096. break;
  2097. case 3:
  2098. // left border
  2099. bw = borders[3].width;
  2100. border.args = drawSide({
  2101. c1: [bx, by + bh + borders[2].width],
  2102. c2: [bx, by],
  2103. c3: [bx + bw, by + borders[0].width],
  2104. c4: [bx + bw, by + bh]
  2105. }, radius[3], radius[0],
  2106. borderPoints.bottomLeftOuter, borderPoints.bottomLeftInner, borderPoints.topLeftOuter, borderPoints.topLeftInner);
  2107. break;
  2108. }
  2109. }
  2110. return border;
  2111. });
  2112. }
  2113. NodeParser.prototype.parseBackgroundClip = function (container, borderPoints, borders, radius, bounds) {
  2114. var backgroundClip = container.css('backgroundClip'),
  2115. borderArgs = [];
  2116. switch (backgroundClip) {
  2117. case 'content-box':
  2118. case 'padding-box':
  2119. parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftInner, borderPoints.topRightInner, bounds.left + borders[3].width, bounds.top + borders[0].width);
  2120. parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightInner, borderPoints.bottomRightInner, bounds.left + bounds.width - borders[1].width, bounds.top + borders[0].width);
  2121. parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightInner, borderPoints.bottomLeftInner, bounds.left + bounds.width - borders[1].width, bounds.top + bounds.height - borders[2].width);
  2122. parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftInner, borderPoints.topLeftInner, bounds.left + borders[3].width, bounds.top + bounds.height - borders[2].width);
  2123. break;
  2124. default:
  2125. parseCorner(borderArgs, radius[0], radius[1], borderPoints.topLeftOuter, borderPoints.topRightOuter, bounds.left, bounds.top);
  2126. parseCorner(borderArgs, radius[1], radius[2], borderPoints.topRightOuter, borderPoints.bottomRightOuter, bounds.left + bounds.width, bounds.top);
  2127. parseCorner(borderArgs, radius[2], radius[3], borderPoints.bottomRightOuter, borderPoints.bottomLeftOuter, bounds.left + bounds.width, bounds.top + bounds.height);
  2128. parseCorner(borderArgs, radius[3], radius[0], borderPoints.bottomLeftOuter, borderPoints.topLeftOuter, bounds.left, bounds.top + bounds.height);
  2129. break;
  2130. }
  2131. return borderArgs;
  2132. };
  2133. function getCurvePoints (x, y, r1, r2) {
  2134. var kappa = 4 * ((Math.sqrt(2) - 1) / 3);
  2135. var ox = (r1) * kappa, // control point offset horizontal
  2136. oy = (r2) * kappa, // control point offset vertical
  2137. xm = x + r1, // x-middle
  2138. ym = y + r2; // y-middle
  2139. return {
  2140. topLeft: bezierCurve({x: x, y: ym}, {x: x, y: ym - oy}, {x: xm - ox, y: y}, {x: xm, y: y}),
  2141. topRight: bezierCurve({x: x, y: y}, {x: x + ox, y: y}, {x: xm, y: ym - oy}, {x: xm, y: ym}),
  2142. bottomRight: bezierCurve({x: xm, y: y}, {x: xm, y: y + oy}, {x: x + ox, y: ym}, {x: x, y: ym}),
  2143. bottomLeft: bezierCurve({x: xm, y: ym}, {x: xm - ox, y: ym}, {x: x, y: y + oy}, {x: x, y: y})
  2144. };
  2145. }
  2146. function calculateCurvePoints (bounds, borderRadius, borders) {
  2147. var x = bounds.left,
  2148. y = bounds.top,
  2149. width = bounds.width,
  2150. height = bounds.height,
  2151. tlh = borderRadius[0][0] < width / 2 ? borderRadius[0][0] : width / 2,
  2152. tlv = borderRadius[0][1] < height / 2 ? borderRadius[0][1] : height / 2,
  2153. trh = borderRadius[1][0] < width / 2 ? borderRadius[1][0] : width / 2,
  2154. trv = borderRadius[1][1] < height / 2 ? borderRadius[1][1] : height / 2,
  2155. brh = borderRadius[2][0] < width / 2 ? borderRadius[2][0] : width / 2,
  2156. brv = borderRadius[2][1] < height / 2 ? borderRadius[2][1] : height / 2,
  2157. blh = borderRadius[3][0] < width / 2 ? borderRadius[3][0] : width / 2,
  2158. blv = borderRadius[3][1] < height / 2 ? borderRadius[3][1] : height / 2;
  2159. var topWidth = width - trh,
  2160. rightHeight = height - brv,
  2161. bottomWidth = width - brh,
  2162. leftHeight = height - blv;
  2163. return {
  2164. topLeftOuter: getCurvePoints(x, y, tlh, tlv).topLeft.subdivide(0.5),
  2165. topLeftInner: getCurvePoints(x + borders[3].width, y + borders[0].width, Math.max(0, tlh - borders[3].width), Math.max(0, tlv - borders[0].width)).topLeft.subdivide(0.5),
  2166. topRightOuter: getCurvePoints(x + topWidth, y, trh, trv).topRight.subdivide(0.5),
  2167. topRightInner: getCurvePoints(x + Math.min(topWidth, width + borders[3].width), y + borders[0].width, (topWidth > width + borders[3].width) ? 0 : trh - borders[3].width, trv - borders[0].width).topRight.subdivide(0.5),
  2168. bottomRightOuter: getCurvePoints(x + bottomWidth, y + rightHeight, brh, brv).bottomRight.subdivide(0.5),
  2169. bottomRightInner: getCurvePoints(x + Math.min(bottomWidth, width - borders[3].width), y + Math.min(rightHeight, height + borders[0].width), Math.max(0, brh - borders[1].width), brv - borders[2].width).bottomRight.subdivide(0.5),
  2170. bottomLeftOuter: getCurvePoints(x, y + leftHeight, blh, blv).bottomLeft.subdivide(0.5),
  2171. bottomLeftInner: getCurvePoints(x + borders[3].width, y + leftHeight, Math.max(0, blh - borders[3].width), blv - borders[2].width).bottomLeft.subdivide(0.5)
  2172. };
  2173. }
  2174. function bezierCurve (start, startControl, endControl, end) {
  2175. var lerp = function (a, b, t) {
  2176. return {
  2177. x: a.x + (b.x - a.x) * t,
  2178. y: a.y + (b.y - a.y) * t
  2179. };
  2180. };
  2181. return {
  2182. start: start,
  2183. startControl: startControl,
  2184. endControl: endControl,
  2185. end: end,
  2186. subdivide: function (t) {
  2187. var ab = lerp(start, startControl, t),
  2188. bc = lerp(startControl, endControl, t),
  2189. cd = lerp(endControl, end, t),
  2190. abbc = lerp(ab, bc, t),
  2191. bccd = lerp(bc, cd, t),
  2192. dest = lerp(abbc, bccd, t);
  2193. return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];
  2194. },
  2195. curveTo: function (borderArgs) {
  2196. borderArgs.push(['bezierCurve', startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);
  2197. },
  2198. curveToReversed: function (borderArgs) {
  2199. borderArgs.push(['bezierCurve', endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);
  2200. }
  2201. };
  2202. }
  2203. function drawSide (borderData, radius1, radius2, outer1, inner1, outer2, inner2) {
  2204. var borderArgs = [];
  2205. if (radius1[0] > 0 || radius1[1] > 0) {
  2206. borderArgs.push(['line', outer1[1].start.x, outer1[1].start.y]);
  2207. outer1[1].curveTo(borderArgs);
  2208. } else {
  2209. borderArgs.push([ 'line', borderData.c1[0], borderData.c1[1]]);
  2210. }
  2211. if (radius2[0] > 0 || radius2[1] > 0) {
  2212. borderArgs.push(['line', outer2[0].start.x, outer2[0].start.y]);
  2213. outer2[0].curveTo(borderArgs);
  2214. borderArgs.push(['line', inner2[0].end.x, inner2[0].end.y]);
  2215. inner2[0].curveToReversed(borderArgs);
  2216. } else {
  2217. borderArgs.push(['line', borderData.c2[0], borderData.c2[1]]);
  2218. borderArgs.push(['line', borderData.c3[0], borderData.c3[1]]);
  2219. }
  2220. if (radius1[0] > 0 || radius1[1] > 0) {
  2221. borderArgs.push(['line', inner1[1].end.x, inner1[1].end.y]);
  2222. inner1[1].curveToReversed(borderArgs);
  2223. } else {
  2224. borderArgs.push(['line', borderData.c4[0], borderData.c4[1]]);
  2225. }
  2226. return borderArgs;
  2227. }
  2228. function parseCorner (borderArgs, radius1, radius2, corner1, corner2, x, y) {
  2229. if (radius1[0] > 0 || radius1[1] > 0) {
  2230. borderArgs.push(['line', corner1[0].start.x, corner1[0].start.y]);
  2231. corner1[0].curveTo(borderArgs);
  2232. corner1[1].curveTo(borderArgs);
  2233. } else {
  2234. borderArgs.push(['line', x, y]);
  2235. }
  2236. if (radius2[0] > 0 || radius2[1] > 0) {
  2237. borderArgs.push(['line', corner2[0].start.x, corner2[0].start.y]);
  2238. }
  2239. }
  2240. function negativeZIndex (container) {
  2241. return container.cssInt('zIndex') < 0;
  2242. }
  2243. function positiveZIndex (container) {
  2244. return container.cssInt('zIndex') > 0;
  2245. }
  2246. function zIndex0 (container) {
  2247. return container.cssInt('zIndex') === 0;
  2248. }
  2249. function inlineLevel (container) {
  2250. return ['inline', 'inline-block', 'inline-table'].indexOf(container.css('display')) !== -1;
  2251. }
  2252. function isStackingContext (container) {
  2253. return (container instanceof StackingContext);
  2254. }
  2255. function hasText (container) {
  2256. return container.node.data.trim().length > 0;
  2257. }
  2258. function noLetterSpacing (container) {
  2259. return (/^(normal|none|0px)$/.test(container.parent.css('letterSpacing')));
  2260. }
  2261. function getBorderRadiusData (container) {
  2262. return ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft'].map(function (side) {
  2263. var value = container.css('border' + side + 'Radius');
  2264. var arr = value.split(' ');
  2265. if (arr.length <= 1) {
  2266. arr[1] = arr[0];
  2267. }
  2268. return arr.map(asInt);
  2269. });
  2270. }
  2271. function renderableNode (node) {
  2272. return (node.nodeType === Node.TEXT_NODE || node.nodeType === Node.ELEMENT_NODE);
  2273. }
  2274. function isPositionedForStacking (container) {
  2275. var position = container.css('position');
  2276. var zIndex = (['absolute', 'relative', 'fixed'].indexOf(position) !== -1) ? container.css('zIndex') : 'auto';
  2277. return zIndex !== 'auto';
  2278. }
  2279. function isPositioned (container) {
  2280. return container.css('position') !== 'static';
  2281. }
  2282. function isFloating (container) {
  2283. return container.css('float') !== 'none';
  2284. }
  2285. function isInlineBlock (container) {
  2286. return ['inline-block', 'inline-table'].indexOf(container.css('display')) !== -1;
  2287. }
  2288. function not (callback) {
  2289. var context = this;
  2290. return function () {
  2291. return !callback.apply(context, arguments);
  2292. };
  2293. }
  2294. function isElement (container) {
  2295. return container.node.nodeType === Node.ELEMENT_NODE;
  2296. }
  2297. function isPseudoElement (container) {
  2298. return container.isPseudoElement === true;
  2299. }
  2300. function isTextNode (container) {
  2301. return container.node.nodeType === Node.TEXT_NODE;
  2302. }
  2303. function zIndexSort (contexts) {
  2304. return function (a, b) {
  2305. return (a.cssInt('zIndex') + (contexts.indexOf(a) / contexts.length)) - (b.cssInt('zIndex') + (contexts.indexOf(b) / contexts.length));
  2306. };
  2307. }
  2308. function hasOpacity (container) {
  2309. return container.getOpacity() < 1;
  2310. }
  2311. function asInt (value) {
  2312. return parseInt(value, 10);
  2313. }
  2314. function getWidth (border) {
  2315. return border.width;
  2316. }
  2317. function nonIgnoredElement (nodeContainer) {
  2318. return (nodeContainer.node.nodeType !== Node.ELEMENT_NODE || ['SCRIPT', 'HEAD', 'TITLE', 'OBJECT', 'BR', 'OPTION'].indexOf(nodeContainer.node.nodeName) === -1);
  2319. }
  2320. function flatten (arrays) {
  2321. return [].concat.apply([], arrays);
  2322. }
  2323. function stripQuotes (content) {
  2324. var first = content.substr(0, 1);
  2325. return (first === content.substr(content.length - 1) && first.match(/'|"/)) ? content.substr(1, content.length - 2) : content;
  2326. }
  2327. function getWords (characters) {
  2328. var words = [], i = 0, onWordBoundary = false, word;
  2329. while (characters.length) {
  2330. if (isWordBoundary(characters[i]) === onWordBoundary) {
  2331. word = characters.splice(0, i);
  2332. if (word.length) {
  2333. words.push(punycode.ucs2.encode(word));
  2334. }
  2335. onWordBoundary = !onWordBoundary;
  2336. i = 0;
  2337. } else {
  2338. i++;
  2339. }
  2340. if (i >= characters.length) {
  2341. word = characters.splice(0, i);
  2342. if (word.length) {
  2343. words.push(punycode.ucs2.encode(word));
  2344. }
  2345. }
  2346. }
  2347. return words;
  2348. }
  2349. function isWordBoundary (characterCode) {
  2350. return [
  2351. 32, // <space>
  2352. 13, // \r
  2353. 10, // \n
  2354. 9, // \t
  2355. 45 // -
  2356. ].indexOf(characterCode) !== -1;
  2357. }
  2358. function hasUnicode (string) {
  2359. return (/[^\u0000-\u00ff]/).test(string);
  2360. }
  2361. module.exports = NodeParser;
  2362. }, {'./color': 3, './fontmetrics': 7, './log': 13, './nodecontainer': 14, './pseudoelementcontainer': 18, './stackingcontext': 21, './textcontainer': 25, './utils': 26, 'punycode': 1}],
  2363. 16: [function (_dereq_, module, exports) {
  2364. var XHR = _dereq_('./xhr');
  2365. var utils = _dereq_('./utils');
  2366. var log = _dereq_('./log');
  2367. var createWindowClone = _dereq_('./clone');
  2368. var decode64 = utils.decode64;
  2369. function Proxy (src, proxyUrl, document) {
  2370. var supportsCORS = ('withCredentials' in new XMLHttpRequest());
  2371. if (!proxyUrl) {
  2372. return Promise.reject('No proxy configured');
  2373. }
  2374. var callback = createCallback(supportsCORS);
  2375. var url = createProxyUrl(proxyUrl, src, callback);
  2376. return supportsCORS ? XHR(url) : (jsonp(document, url, callback).then(function (response) {
  2377. return decode64(response.content);
  2378. }));
  2379. }
  2380. var proxyCount = 0;
  2381. function ProxyURL (src, proxyUrl, document) {
  2382. var supportsCORSImage = ('crossOrigin' in new Image());
  2383. var callback = createCallback(supportsCORSImage);
  2384. var url = createProxyUrl(proxyUrl, src, callback);
  2385. return (supportsCORSImage ? Promise.resolve(url) : jsonp(document, url, callback).then(function (response) {
  2386. return 'data:' + response.type + ';base64,' + response.content;
  2387. }));
  2388. }
  2389. function jsonp (document, url, callback) {
  2390. return new Promise(function (resolve, reject) {
  2391. var s = document.createElement('script');
  2392. var cleanup = function () {
  2393. delete window.html2canvas.proxy[callback];
  2394. document.body.removeChild(s);
  2395. };
  2396. window.html2canvas.proxy[callback] = function (response) {
  2397. cleanup();
  2398. resolve(response);
  2399. };
  2400. s.src = url;
  2401. s.onerror = function (e) {
  2402. cleanup();
  2403. reject(e);
  2404. };
  2405. document.body.appendChild(s);
  2406. });
  2407. }
  2408. function createCallback (useCORS) {
  2409. return !useCORS ? 'html2canvas_' + Date.now() + '_' + (++proxyCount) + '_' + Math.round(Math.random() * 100000) : '';
  2410. }
  2411. function createProxyUrl (proxyUrl, src, callback) {
  2412. return proxyUrl + '?url=' + encodeURIComponent(src) + (callback.length ? '&callback=html2canvas.proxy.' + callback : '');
  2413. }
  2414. function documentFromHTML (src) {
  2415. return function (html) {
  2416. var parser = new DOMParser(), doc;
  2417. try {
  2418. doc = parser.parseFromString(html, 'text/html');
  2419. } catch (e) {
  2420. log('DOMParser not supported, falling back to createHTMLDocument');
  2421. doc = document.implementation.createHTMLDocument('');
  2422. try {
  2423. doc.open();
  2424. doc.write(html);
  2425. doc.close();
  2426. } catch (ee) {
  2427. log('createHTMLDocument write not supported, falling back to document.body.innerHTML');
  2428. doc.body.innerHTML = html; // ie9 doesnt support writing to documentElement
  2429. }
  2430. }
  2431. var b = doc.querySelector('base');
  2432. if (!b || !b.href.host) {
  2433. var base = doc.createElement('base');
  2434. base.href = src;
  2435. doc.head.insertBefore(base, doc.head.firstChild);
  2436. }
  2437. return doc;
  2438. };
  2439. }
  2440. function loadUrlDocument (src, proxy, document, width, height, options) {
  2441. return new Proxy(src, proxy, window.document).then(documentFromHTML(src)).then(function (doc) {
  2442. return createWindowClone(doc, document, width, height, options, 0, 0);
  2443. });
  2444. }
  2445. exports.Proxy = Proxy;
  2446. exports.ProxyURL = ProxyURL;
  2447. exports.loadUrlDocument = loadUrlDocument;
  2448. }, {'./clone': 2, './log': 13, './utils': 26, './xhr': 28}],
  2449. 17: [function (_dereq_, module, exports) {
  2450. var ProxyURL = _dereq_('./proxy').ProxyURL;
  2451. function ProxyImageContainer (src, proxy) {
  2452. var link = document.createElement('a');
  2453. link.href = src;
  2454. src = link.href;
  2455. this.src = src;
  2456. this.image = new Image();
  2457. var self = this;
  2458. this.promise = new Promise(function (resolve, reject) {
  2459. self.image.crossOrigin = 'Anonymous';
  2460. self.image.onload = resolve;
  2461. self.image.onerror = reject;
  2462. new ProxyURL(src, proxy, document).then(function (url) {
  2463. self.image.src = url;
  2464. })['catch'](reject);
  2465. });
  2466. }
  2467. module.exports = ProxyImageContainer;
  2468. }, {'./proxy': 16}],
  2469. 18: [function (_dereq_, module, exports) {
  2470. var NodeContainer = _dereq_('./nodecontainer');
  2471. function PseudoElementContainer (node, parent, type) {
  2472. NodeContainer.call(this, node, parent);
  2473. this.isPseudoElement = true;
  2474. this.before = type === ':before';
  2475. }
  2476. PseudoElementContainer.prototype.cloneTo = function (stack) {
  2477. PseudoElementContainer.prototype.cloneTo.call(this, stack);
  2478. stack.isPseudoElement = true;
  2479. stack.before = this.before;
  2480. };
  2481. PseudoElementContainer.prototype = Object.create(NodeContainer.prototype);
  2482. PseudoElementContainer.prototype.appendToDOM = function () {
  2483. if (this.before) {
  2484. this.parent.node.insertBefore(this.node, this.parent.node.firstChild);
  2485. } else {
  2486. this.parent.node.appendChild(this.node);
  2487. }
  2488. this.parent.node.className += ' ' + this.getHideClass();
  2489. };
  2490. PseudoElementContainer.prototype.cleanDOM = function () {
  2491. this.node.parentNode.removeChild(this.node);
  2492. this.parent.node.className = this.parent.node.className.replace(this.getHideClass(), '');
  2493. };
  2494. PseudoElementContainer.prototype.getHideClass = function () {
  2495. return this['PSEUDO_HIDE_ELEMENT_CLASS_' + (this.before ? 'BEFORE' : 'AFTER')];
  2496. };
  2497. PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_BEFORE = '___html2canvas___pseudoelement_before';
  2498. PseudoElementContainer.prototype.PSEUDO_HIDE_ELEMENT_CLASS_AFTER = '___html2canvas___pseudoelement_after';
  2499. module.exports = PseudoElementContainer;
  2500. }, {'./nodecontainer': 14}],
  2501. 19: [function (_dereq_, module, exports) {
  2502. var log = _dereq_('./log');
  2503. function Renderer (width, height, images, options, document) {
  2504. this.width = width;
  2505. this.height = height;
  2506. this.images = images;
  2507. this.options = options;
  2508. this.document = document;
  2509. }
  2510. Renderer.prototype.renderImage = function (container, bounds, borderData, imageContainer) {
  2511. var paddingLeft = container.cssInt('paddingLeft'),
  2512. paddingTop = container.cssInt('paddingTop'),
  2513. paddingRight = container.cssInt('paddingRight'),
  2514. paddingBottom = container.cssInt('paddingBottom'),
  2515. borders = borderData.borders;
  2516. var width = bounds.width - (borders[1].width + borders[3].width + paddingLeft + paddingRight);
  2517. var height = bounds.height - (borders[0].width + borders[2].width + paddingTop + paddingBottom);
  2518. this.drawImage(
  2519. imageContainer,
  2520. 0,
  2521. 0,
  2522. imageContainer.image.width || width,
  2523. imageContainer.image.height || height,
  2524. bounds.left + paddingLeft + borders[3].width,
  2525. bounds.top + paddingTop + borders[0].width,
  2526. width,
  2527. height
  2528. );
  2529. };
  2530. Renderer.prototype.renderBackground = function (container, bounds, borderData) {
  2531. if (bounds.height > 0 && bounds.width > 0) {
  2532. this.renderBackgroundColor(container, bounds);
  2533. this.renderBackgroundImage(container, bounds, borderData);
  2534. }
  2535. };
  2536. Renderer.prototype.renderBackgroundColor = function (container, bounds) {
  2537. var color = container.color('backgroundColor');
  2538. if (!color.isTransparent()) {
  2539. this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, color);
  2540. }
  2541. };
  2542. Renderer.prototype.renderBorders = function (borders) {
  2543. borders.forEach(this.renderBorder, this);
  2544. };
  2545. Renderer.prototype.renderBorder = function (data) {
  2546. if (!data.color.isTransparent() && data.args !== null) {
  2547. this.drawShape(data.args, data.color);
  2548. }
  2549. };
  2550. Renderer.prototype.renderBackgroundImage = function (container, bounds, borderData) {
  2551. var backgroundImages = container.parseBackgroundImages();
  2552. backgroundImages.reverse().forEach(function (backgroundImage, index, arr) {
  2553. switch (backgroundImage.method) {
  2554. case 'url':
  2555. var image = this.images.get(backgroundImage.args[0]);
  2556. if (image) {
  2557. this.renderBackgroundRepeating(container, bounds, image, arr.length - (index + 1), borderData);
  2558. } else {
  2559. log('Error loading background-image', backgroundImage.args[0]);
  2560. }
  2561. break;
  2562. case 'linear-gradient':
  2563. case 'gradient':
  2564. var gradientImage = this.images.get(backgroundImage.value);
  2565. if (gradientImage) {
  2566. this.renderBackgroundGradient(gradientImage, bounds, borderData);
  2567. } else {
  2568. log('Error loading background-image', backgroundImage.args[0]);
  2569. }
  2570. break;
  2571. case 'none':
  2572. break;
  2573. default:
  2574. log('Unknown background-image type', backgroundImage.args[0]);
  2575. }
  2576. }, this);
  2577. };
  2578. Renderer.prototype.renderBackgroundRepeating = function (container, bounds, imageContainer, index, borderData) {
  2579. var size = container.parseBackgroundSize(bounds, imageContainer.image, index);
  2580. var position = container.parseBackgroundPosition(bounds, imageContainer.image, index, size);
  2581. var repeat = container.parseBackgroundRepeat(index);
  2582. switch (repeat) {
  2583. case 'repeat-x':
  2584. case 'repeat no-repeat':
  2585. this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + borderData[3], bounds.top + position.top + borderData[0], 99999, size.height, borderData);
  2586. break;
  2587. case 'repeat-y':
  2588. case 'no-repeat repeat':
  2589. this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + borderData[0], size.width, 99999, borderData);
  2590. break;
  2591. case 'no-repeat':
  2592. this.backgroundRepeatShape(imageContainer, position, size, bounds, bounds.left + position.left + borderData[3], bounds.top + position.top + borderData[0], size.width, size.height, borderData);
  2593. break;
  2594. default:
  2595. this.renderBackgroundRepeat(imageContainer, position, size, {top: bounds.top, left: bounds.left}, borderData[3], borderData[0]);
  2596. break;
  2597. }
  2598. };
  2599. module.exports = Renderer;
  2600. }, {'./log': 13}],
  2601. 20: [function (_dereq_, module, exports) {
  2602. var Renderer = _dereq_('../renderer');
  2603. var LinearGradientContainer = _dereq_('../lineargradientcontainer');
  2604. var log = _dereq_('../log');
  2605. function CanvasRenderer (width, height) {
  2606. Renderer.apply(this, arguments);
  2607. this.canvas = this.options.canvas || this.document.createElement('canvas');
  2608. if (!this.options.canvas) {
  2609. this.canvas.width = width;
  2610. this.canvas.height = height;
  2611. }
  2612. this.ctx = this.canvas.getContext('2d');
  2613. this.taintCtx = this.document.createElement('canvas').getContext('2d');
  2614. this.ctx.textBaseline = 'bottom';
  2615. this.variables = {};
  2616. log('Initialized CanvasRenderer with size', width, 'x', height);
  2617. }
  2618. CanvasRenderer.prototype = Object.create(Renderer.prototype);
  2619. CanvasRenderer.prototype.setFillStyle = function (fillStyle) {
  2620. this.ctx.fillStyle = typeof (fillStyle) === 'object' && !!fillStyle.isColor ? fillStyle.toString() : fillStyle;
  2621. return this.ctx;
  2622. };
  2623. CanvasRenderer.prototype.rectangle = function (left, top, width, height, color) {
  2624. this.setFillStyle(color).fillRect(left, top, width, height);
  2625. };
  2626. CanvasRenderer.prototype.circle = function (left, top, size, color) {
  2627. this.setFillStyle(color);
  2628. this.ctx.beginPath();
  2629. this.ctx.arc(left + size / 2, top + size / 2, size / 2, 0, Math.PI * 2, true);
  2630. this.ctx.closePath();
  2631. this.ctx.fill();
  2632. };
  2633. CanvasRenderer.prototype.circleStroke = function (left, top, size, color, stroke, strokeColor) {
  2634. this.circle(left, top, size, color);
  2635. this.ctx.strokeStyle = strokeColor.toString();
  2636. this.ctx.stroke();
  2637. };
  2638. CanvasRenderer.prototype.drawShape = function (shape, color) {
  2639. this.shape(shape);
  2640. this.setFillStyle(color).fill();
  2641. };
  2642. CanvasRenderer.prototype.taints = function (imageContainer) {
  2643. if (imageContainer.tainted === null) {
  2644. this.taintCtx.drawImage(imageContainer.image, 0, 0);
  2645. try {
  2646. this.taintCtx.getImageData(0, 0, 1, 1);
  2647. imageContainer.tainted = false;
  2648. } catch (e) {
  2649. this.taintCtx = document.createElement('canvas').getContext('2d');
  2650. imageContainer.tainted = true;
  2651. }
  2652. }
  2653. return imageContainer.tainted;
  2654. };
  2655. CanvasRenderer.prototype.drawImage = function (imageContainer, sx, sy, sw, sh, dx, dy, dw, dh) {
  2656. if (!this.taints(imageContainer) || this.options.allowTaint) {
  2657. this.ctx.drawImage(imageContainer.image, sx, sy, sw, sh, dx, dy, dw, dh);
  2658. }
  2659. };
  2660. CanvasRenderer.prototype.clip = function (shapes, callback, context) {
  2661. this.ctx.save();
  2662. shapes.filter(hasEntries).forEach(function (shape) {
  2663. this.shape(shape).clip();
  2664. }, this);
  2665. callback.call(context);
  2666. this.ctx.restore();
  2667. };
  2668. CanvasRenderer.prototype.shape = function (shape) {
  2669. this.ctx.beginPath();
  2670. shape.forEach(function (point, index) {
  2671. if (point[0] === 'rect') {
  2672. this.ctx.rect.apply(this.ctx, point.slice(1));
  2673. } else {
  2674. this.ctx[(index === 0) ? 'moveTo' : point[0] + 'To' ].apply(this.ctx, point.slice(1));
  2675. }
  2676. }, this);
  2677. this.ctx.closePath();
  2678. return this.ctx;
  2679. };
  2680. CanvasRenderer.prototype.font = function (color, style, variant, weight, size, family) {
  2681. this.setFillStyle(color).font = [style, variant, weight, size, family].join(' ').split(',')[0];
  2682. };
  2683. CanvasRenderer.prototype.fontShadow = function (color, offsetX, offsetY, blur) {
  2684. this.setVariable('shadowColor', color.toString())
  2685. .setVariable('shadowOffsetY', offsetX)
  2686. .setVariable('shadowOffsetX', offsetY)
  2687. .setVariable('shadowBlur', blur);
  2688. };
  2689. CanvasRenderer.prototype.clearShadow = function () {
  2690. this.setVariable('shadowColor', 'rgba(0,0,0,0)');
  2691. };
  2692. CanvasRenderer.prototype.setOpacity = function (opacity) {
  2693. this.ctx.globalAlpha = opacity;
  2694. };
  2695. CanvasRenderer.prototype.setTransform = function (transform) {
  2696. this.ctx.translate(transform.origin[0], transform.origin[1]);
  2697. this.ctx.transform.apply(this.ctx, transform.matrix);
  2698. this.ctx.translate(-transform.origin[0], -transform.origin[1]);
  2699. };
  2700. CanvasRenderer.prototype.setVariable = function (property, value) {
  2701. if (this.variables[property] !== value) {
  2702. this.variables[property] = this.ctx[property] = value;
  2703. }
  2704. return this;
  2705. };
  2706. CanvasRenderer.prototype.text = function (text, left, bottom) {
  2707. this.ctx.fillText(text, left, bottom);
  2708. };
  2709. CanvasRenderer.prototype.backgroundRepeatShape = function (imageContainer, backgroundPosition, size, bounds, left, top, width, height, borderData) {
  2710. var shape = [
  2711. ['line', Math.round(left), Math.round(top)],
  2712. ['line', Math.round(left + width), Math.round(top)],
  2713. ['line', Math.round(left + width), Math.round(height + top)],
  2714. ['line', Math.round(left), Math.round(height + top)]
  2715. ];
  2716. this.clip([shape], function () {
  2717. this.renderBackgroundRepeat(imageContainer, backgroundPosition, size, bounds, borderData[3], borderData[0]);
  2718. }, this);
  2719. };
  2720. CanvasRenderer.prototype.renderBackgroundRepeat = function (imageContainer, backgroundPosition, size, bounds, borderLeft, borderTop) {
  2721. var offsetX = Math.round(bounds.left + backgroundPosition.left + borderLeft), offsetY = Math.round(bounds.top + backgroundPosition.top + borderTop);
  2722. this.setFillStyle(this.ctx.createPattern(this.resizeImage(imageContainer, size), 'repeat'));
  2723. this.ctx.translate(offsetX, offsetY);
  2724. this.ctx.fill();
  2725. this.ctx.translate(-offsetX, -offsetY);
  2726. };
  2727. CanvasRenderer.prototype.renderBackgroundGradient = function (gradientImage, bounds) {
  2728. if (gradientImage instanceof LinearGradientContainer) {
  2729. var gradient = this.ctx.createLinearGradient(
  2730. bounds.left + bounds.width * gradientImage.x0,
  2731. bounds.top + bounds.height * gradientImage.y0,
  2732. bounds.left + bounds.width * gradientImage.x1,
  2733. bounds.top + bounds.height * gradientImage.y1);
  2734. gradientImage.colorStops.forEach(function (colorStop) {
  2735. gradient.addColorStop(colorStop.stop, colorStop.color.toString());
  2736. });
  2737. this.rectangle(bounds.left, bounds.top, bounds.width, bounds.height, gradient);
  2738. }
  2739. };
  2740. CanvasRenderer.prototype.resizeImage = function (imageContainer, size) {
  2741. var image = imageContainer.image;
  2742. if (image.width === size.width && image.height === size.height) {
  2743. return image;
  2744. }
  2745. var ctx, canvas = document.createElement('canvas');
  2746. canvas.width = size.width;
  2747. canvas.height = size.height;
  2748. ctx = canvas.getContext('2d');
  2749. ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height);
  2750. return canvas;
  2751. };
  2752. function hasEntries (array) {
  2753. return array.length > 0;
  2754. }
  2755. module.exports = CanvasRenderer;
  2756. }, {'../lineargradientcontainer': 12, '../log': 13, '../renderer': 19}],
  2757. 21: [function (_dereq_, module, exports) {
  2758. var NodeContainer = _dereq_('./nodecontainer');
  2759. function StackingContext (hasOwnStacking, opacity, element, parent) {
  2760. NodeContainer.call(this, element, parent);
  2761. this.ownStacking = hasOwnStacking;
  2762. this.contexts = [];
  2763. this.children = [];
  2764. this.opacity = (this.parent ? this.parent.stack.opacity : 1) * opacity;
  2765. }
  2766. StackingContext.prototype = Object.create(NodeContainer.prototype);
  2767. StackingContext.prototype.getParentStack = function (context) {
  2768. var parentStack = (this.parent) ? this.parent.stack : null;
  2769. return parentStack ? (parentStack.ownStacking ? parentStack : parentStack.getParentStack(context)) : context.stack;
  2770. };
  2771. module.exports = StackingContext;
  2772. }, {'./nodecontainer': 14}],
  2773. 22: [function (_dereq_, module, exports) {
  2774. function Support (document) {
  2775. this.rangeBounds = this.testRangeBounds(document);
  2776. this.cors = this.testCORS();
  2777. this.svg = this.testSVG();
  2778. }
  2779. Support.prototype.testRangeBounds = function (document) {
  2780. var range, testElement, rangeBounds, rangeHeight, support = false;
  2781. if (document.createRange) {
  2782. range = document.createRange();
  2783. if (range.getBoundingClientRect) {
  2784. testElement = document.createElement('boundtest');
  2785. testElement.style.height = '123px';
  2786. testElement.style.display = 'block';
  2787. document.body.appendChild(testElement);
  2788. range.selectNode(testElement);
  2789. rangeBounds = range.getBoundingClientRect();
  2790. rangeHeight = rangeBounds.height;
  2791. if (rangeHeight === 123) {
  2792. support = true;
  2793. }
  2794. document.body.removeChild(testElement);
  2795. }
  2796. }
  2797. return support;
  2798. };
  2799. Support.prototype.testCORS = function () {
  2800. return typeof ((new Image()).crossOrigin) !== 'undefined';
  2801. };
  2802. Support.prototype.testSVG = function () {
  2803. var img = new Image();
  2804. var canvas = document.createElement('canvas');
  2805. var ctx = canvas.getContext('2d');
  2806. img.src = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'></svg>";
  2807. try {
  2808. ctx.drawImage(img, 0, 0);
  2809. canvas.toDataURL();
  2810. } catch (e) {
  2811. return false;
  2812. }
  2813. return true;
  2814. };
  2815. module.exports = Support;
  2816. }, {}],
  2817. 23: [function (_dereq_, module, exports) {
  2818. var XHR = _dereq_('./xhr');
  2819. var decode64 = _dereq_('./utils').decode64;
  2820. function SVGContainer (src) {
  2821. this.src = src;
  2822. this.image = null;
  2823. var self = this;
  2824. this.promise = this.hasFabric().then(function () {
  2825. return (self.isInline(src) ? Promise.resolve(self.inlineFormatting(src)) : XHR(src));
  2826. }).then(function (svg) {
  2827. return new Promise(function (resolve) {
  2828. window.html2canvas.svg.fabric.loadSVGFromString(svg, self.createCanvas.call(self, resolve));
  2829. });
  2830. });
  2831. }
  2832. SVGContainer.prototype.hasFabric = function () {
  2833. return !window.html2canvas.svg || !window.html2canvas.svg.fabric ? Promise.reject(new Error('html2canvas.svg.js is not loaded, cannot render svg')) : Promise.resolve();
  2834. };
  2835. SVGContainer.prototype.inlineFormatting = function (src) {
  2836. return (/^data:image\/svg\+xml;base64,/.test(src)) ? this.decode64(this.removeContentType(src)) : this.removeContentType(src);
  2837. };
  2838. SVGContainer.prototype.removeContentType = function (src) {
  2839. return src.replace(/^data:image\/svg\+xml(;base64)?,/, '');
  2840. };
  2841. SVGContainer.prototype.isInline = function (src) {
  2842. return (/^data:image\/svg\+xml/i.test(src));
  2843. };
  2844. SVGContainer.prototype.createCanvas = function (resolve) {
  2845. var self = this;
  2846. return function (objects, options) {
  2847. var canvas = new window.html2canvas.svg.fabric.StaticCanvas('c');
  2848. self.image = canvas.lowerCanvasEl;
  2849. canvas
  2850. .setWidth(options.width)
  2851. .setHeight(options.height)
  2852. .add(window.html2canvas.svg.fabric.util.groupSVGElements(objects, options))
  2853. .renderAll();
  2854. resolve(canvas.lowerCanvasEl);
  2855. };
  2856. };
  2857. SVGContainer.prototype.decode64 = function (str) {
  2858. return (typeof (window.atob) === 'function') ? window.atob(str) : decode64(str);
  2859. };
  2860. module.exports = SVGContainer;
  2861. }, {'./utils': 26, './xhr': 28}],
  2862. 24: [function (_dereq_, module, exports) {
  2863. var SVGContainer = _dereq_('./svgcontainer');
  2864. function SVGNodeContainer (node, _native) {
  2865. this.src = node;
  2866. this.image = null;
  2867. var self = this;
  2868. this.promise = _native ? new Promise(function (resolve, reject) {
  2869. self.image = new Image();
  2870. self.image.onload = resolve;
  2871. self.image.onerror = reject;
  2872. self.image.src = 'data:image/svg+xml,' + (new XMLSerializer()).serializeToString(node);
  2873. if (self.image.complete === true) {
  2874. resolve(self.image);
  2875. }
  2876. }) : this.hasFabric().then(function () {
  2877. return new Promise(function (resolve) {
  2878. window.html2canvas.svg.fabric.parseSVGDocument(node, self.createCanvas.call(self, resolve));
  2879. });
  2880. });
  2881. }
  2882. SVGNodeContainer.prototype = Object.create(SVGContainer.prototype);
  2883. module.exports = SVGNodeContainer;
  2884. }, {'./svgcontainer': 23}],
  2885. 25: [function (_dereq_, module, exports) {
  2886. var NodeContainer = _dereq_('./nodecontainer');
  2887. function TextContainer (node, parent) {
  2888. NodeContainer.call(this, node, parent);
  2889. }
  2890. TextContainer.prototype = Object.create(NodeContainer.prototype);
  2891. TextContainer.prototype.applyTextTransform = function () {
  2892. this.node.data = this.transform(this.parent.css('textTransform'));
  2893. };
  2894. TextContainer.prototype.transform = function (transform) {
  2895. var text = this.node.data;
  2896. switch (transform) {
  2897. case 'lowercase':
  2898. return text.toLowerCase();
  2899. case 'capitalize':
  2900. return text.replace(/(^|\s|:|-|\(|\))([a-z])/g, capitalize);
  2901. case 'uppercase':
  2902. return text.toUpperCase();
  2903. default:
  2904. return text;
  2905. }
  2906. };
  2907. function capitalize (m, p1, p2) {
  2908. if (m.length > 0) {
  2909. return p1 + p2.toUpperCase();
  2910. }
  2911. }
  2912. module.exports = TextContainer;
  2913. }, {'./nodecontainer': 14}],
  2914. 26: [function (_dereq_, module, exports) {
  2915. exports.smallImage = function smallImage () {
  2916. return 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
  2917. };
  2918. exports.bind = function (callback, context) {
  2919. return function () {
  2920. return callback.apply(context, arguments);
  2921. };
  2922. };
  2923. /*
  2924. * base64-arraybuffer
  2925. * https://github.com/niklasvh/base64-arraybuffer
  2926. *
  2927. * Copyright (c) 2012 Niklas von Hertzen
  2928. * Licensed under the MIT license.
  2929. */
  2930. exports.decode64 = function (base64) {
  2931. var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  2932. var len = base64.length, i, encoded1, encoded2, encoded3, encoded4, byte1, byte2, byte3;
  2933. var output = '';
  2934. for (i = 0; i < len; i += 4) {
  2935. encoded1 = chars.indexOf(base64[i]);
  2936. encoded2 = chars.indexOf(base64[i + 1]);
  2937. encoded3 = chars.indexOf(base64[i + 2]);
  2938. encoded4 = chars.indexOf(base64[i + 3]);
  2939. byte1 = (encoded1 << 2) | (encoded2 >> 4);
  2940. byte2 = ((encoded2 & 15) << 4) | (encoded3 >> 2);
  2941. byte3 = ((encoded3 & 3) << 6) | encoded4;
  2942. if (encoded3 === 64) {
  2943. output += String.fromCharCode(byte1);
  2944. } else if (encoded4 === 64 || encoded4 === -1) {
  2945. output += String.fromCharCode(byte1, byte2);
  2946. } else {
  2947. output += String.fromCharCode(byte1, byte2, byte3);
  2948. }
  2949. }
  2950. return output;
  2951. };
  2952. exports.getBounds = function (node) {
  2953. if (node.getBoundingClientRect) {
  2954. var clientRect = node.getBoundingClientRect();
  2955. var width = node.offsetWidth == null ? clientRect.width : node.offsetWidth;
  2956. return {
  2957. top: clientRect.top,
  2958. bottom: clientRect.bottom || (clientRect.top + clientRect.height),
  2959. right: clientRect.left + width,
  2960. left: clientRect.left,
  2961. width: width,
  2962. height: node.offsetHeight == null ? clientRect.height : node.offsetHeight
  2963. };
  2964. }
  2965. return {};
  2966. };
  2967. exports.offsetBounds = function (node) {
  2968. var parent = node.offsetParent ? exports.offsetBounds(node.offsetParent) : {top: 0, left: 0};
  2969. return {
  2970. top: node.offsetTop + parent.top,
  2971. bottom: node.offsetTop + node.offsetHeight + parent.top,
  2972. right: node.offsetLeft + parent.left + node.offsetWidth,
  2973. left: node.offsetLeft + parent.left,
  2974. width: node.offsetWidth,
  2975. height: node.offsetHeight
  2976. };
  2977. };
  2978. exports.parseBackgrounds = function (backgroundImage) {
  2979. var whitespace = ' \r\n\t',
  2980. method, definition, prefix, prefix_i, block, results = [],
  2981. mode = 0, numParen = 0, quote, args;
  2982. var appendResult = function () {
  2983. if (method) {
  2984. if (definition.substr(0, 1) === '"') {
  2985. definition = definition.substr(1, definition.length - 2);
  2986. }
  2987. if (definition) {
  2988. args.push(definition);
  2989. }
  2990. if (method.substr(0, 1) === '-' && (prefix_i = method.indexOf('-', 1) + 1) > 0) {
  2991. prefix = method.substr(0, prefix_i);
  2992. method = method.substr(prefix_i);
  2993. }
  2994. results.push({
  2995. prefix: prefix,
  2996. method: method.toLowerCase(),
  2997. value: block,
  2998. args: args,
  2999. image: null
  3000. });
  3001. }
  3002. args = [];
  3003. method = prefix = definition = block = '';
  3004. };
  3005. args = [];
  3006. method = prefix = definition = block = '';
  3007. backgroundImage.split('').forEach(function (c) {
  3008. if (mode === 0 && whitespace.indexOf(c) > -1) {
  3009. return;
  3010. }
  3011. switch (c) {
  3012. case '"':
  3013. if (!quote) {
  3014. quote = c;
  3015. } else if (quote === c) {
  3016. quote = null;
  3017. }
  3018. break;
  3019. case '(':
  3020. if (quote) {
  3021. break;
  3022. } else if (mode === 0) {
  3023. mode = 1;
  3024. block += c;
  3025. return;
  3026. } else {
  3027. numParen++;
  3028. }
  3029. break;
  3030. case ')':
  3031. if (quote) {
  3032. break;
  3033. } else if (mode === 1) {
  3034. if (numParen === 0) {
  3035. mode = 0;
  3036. block += c;
  3037. appendResult();
  3038. return;
  3039. } else {
  3040. numParen--;
  3041. }
  3042. }
  3043. break;
  3044. case ',':
  3045. if (quote) {
  3046. break;
  3047. } else if (mode === 0) {
  3048. appendResult();
  3049. return;
  3050. } else if (mode === 1) {
  3051. if (numParen === 0 && !method.match(/^url$/i)) {
  3052. args.push(definition);
  3053. definition = '';
  3054. block += c;
  3055. return;
  3056. }
  3057. }
  3058. break;
  3059. }
  3060. block += c;
  3061. if (mode === 0) {
  3062. method += c;
  3063. } else {
  3064. definition += c;
  3065. }
  3066. });
  3067. appendResult();
  3068. return results;
  3069. };
  3070. }, {}],
  3071. 27: [function (_dereq_, module, exports) {
  3072. var GradientContainer = _dereq_('./gradientcontainer');
  3073. function WebkitGradientContainer (imageData) {
  3074. GradientContainer.apply(this, arguments);
  3075. this.type = imageData.args[0] === 'linear' ? GradientContainer.TYPES.LINEAR : GradientContainer.TYPES.RADIAL;
  3076. }
  3077. WebkitGradientContainer.prototype = Object.create(GradientContainer.prototype);
  3078. module.exports = WebkitGradientContainer;
  3079. }, {'./gradientcontainer': 9}],
  3080. 28: [function (_dereq_, module, exports) {
  3081. function XHR (url) {
  3082. return new Promise(function (resolve, reject) {
  3083. var xhr = new XMLHttpRequest();
  3084. xhr.open('GET', url);
  3085. xhr.onload = function () {
  3086. if (xhr.status === 200) {
  3087. resolve(xhr.responseText);
  3088. } else {
  3089. reject(new Error(xhr.statusText));
  3090. }
  3091. };
  3092. xhr.onerror = function () {
  3093. reject(new Error('Network Error'));
  3094. };
  3095. xhr.send();
  3096. });
  3097. }
  3098. module.exports = XHR;
  3099. }, {}]}, {}, [4])(4)
  3100. }));