|
33 | 33 | FontNameDB,
|
34 | 34 | FontStyleMap,
|
35 | 35 | FontWeightMap,
|
| 36 | + FloatMap, |
| 37 | + ClearMap, |
36 | 38 | GetCSS,
|
37 | 39 | PurgeWhiteSpace,
|
38 | 40 | Renderer,
|
|
101 | 103 | this.x = x;
|
102 | 104 | this.y = y;
|
103 | 105 | this.settings = settings;
|
| 106 | + //list of functions which are called after each element-rendering process |
| 107 | + this.watchFunctions = []; |
104 | 108 | this.init();
|
105 | 109 | return this;
|
106 | 110 | };
|
|
208 | 212 | css["padding-left"] = ResolveUnitedNumber(computedCSSElement("padding-left")) || 0;
|
209 | 213 | css["padding-right"] = ResolveUnitedNumber(computedCSSElement("padding-right")) || 0;
|
210 | 214 | }
|
| 215 | + //float and clearing of floats |
| 216 | + css["float"] = FloatMap[computedCSSElement("cssFloat")] || "none"; |
| 217 | + css["clear"] = ClearMap[computedCSSElement("clear")] || "none"; |
211 | 218 | return css;
|
212 | 219 | };
|
213 | 220 | elementHandledElsewhere = function (element, renderer, elementHandlers) {
|
|
323 | 330 | while (i < l) {
|
324 | 331 | cn = cns[i];
|
325 | 332 | if (typeof cn === "object") {
|
| 333 | + |
| 334 | + //execute all watcher functions to e.g. reset floating |
| 335 | + renderer.executeWatchFunctions(cn); |
326 | 336 |
|
327 | 337 | /*** HEADER rendering **/
|
328 | 338 | if (cn.nodeType === 1 && cn.nodeName === 'HEADER') {
|
|
347 | 357 | renderer.pdf.addPage();
|
348 | 358 | renderer.y = renderer.pdf.margins_doc.top;
|
349 | 359 | }
|
| 360 | + |
350 | 361 | } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) {
|
| 362 | + /*** IMAGE RENDERING ***/ |
351 | 363 | if (cn.nodeName === "IMG" && images[cn.getAttribute("src")]) {
|
352 | 364 | if ((renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height) && (renderer.y > renderer.pdf.margins_doc.top)) {
|
353 | 365 | renderer.pdf.addPage();
|
354 | 366 | renderer.y = renderer.pdf.margins_doc.top;
|
| 367 | + } |
| 368 | + |
| 369 | + var imagesCSS = GetCSS(cn); |
| 370 | + var imageX = renderer.x; |
| 371 | + //if float is set to right, move the image to the right border |
| 372 | + if (imagesCSS['float'] !== undefined && imagesCSS['float'] === 'right') { |
| 373 | + imageX += renderer.settings.width-cn.width; |
355 | 374 | }
|
356 |
| - renderer.pdf.addImage(images[cn.getAttribute("src")], renderer.x, renderer.y, cn.width, cn.height); |
357 |
| - renderer.y += cn.height; |
| 375 | + |
| 376 | + renderer.pdf.addImage(images[cn.getAttribute("src")], imageX, renderer.y, cn.width, cn.height); |
| 377 | + //if the float prop is specified we have to float the text around the image |
| 378 | + if (imagesCSS['float'] !== undefined) { |
| 379 | + if (imagesCSS['float'] === 'right' || imagesCSS['float'] === 'left') { |
| 380 | + |
| 381 | + //add functiont to set back coordinates after image rendering |
| 382 | + renderer.watchFunctions.push((function(diffX , thresholdY, diffWidth, el) { |
| 383 | + //undo drawing box adaptions which were set by floating |
| 384 | + if (renderer.y >= thresholdY) { |
| 385 | + renderer.x += diffX; |
| 386 | + renderer.settings.width += diffWidth; |
| 387 | + return true; |
| 388 | + } else if(el && el.nodeType === 1 && !SkipNode[el.nodeName] && renderer.x+el.width > (renderer.pdf.margins_doc.left + renderer.pdf.margins_doc.width)) { |
| 389 | + renderer.x += diffX; |
| 390 | + renderer.y = thresholdY; |
| 391 | + renderer.settings.width += diffWidth; |
| 392 | + return true; |
| 393 | + } else { |
| 394 | + return false; |
| 395 | + } |
| 396 | + }).bind(this, (imagesCSS['float'] === 'left') ? -cn.width : 0, renderer.y+cn.height, cn.width)); |
| 397 | + |
| 398 | + //reset floating by clear:both divs |
| 399 | + //just set cursorY after the floating element |
| 400 | + renderer.watchFunctions.push((function(yPositionAfterFloating, pages, el) { |
| 401 | + if (renderer.y < yPositionAfterFloating && pages === renderer.pdf.internal.getNumberOfPages()) { |
| 402 | + if (el.nodeType === 1 && GetCSS(el).clear === 'both') { |
| 403 | + renderer.y = yPositionAfterFloating; |
| 404 | + return true; |
| 405 | + } else { |
| 406 | + return false; |
| 407 | + } |
| 408 | + } else { |
| 409 | + return true; |
| 410 | + } |
| 411 | + }).bind(this, renderer.y+cn.height, renderer.pdf.internal.getNumberOfPages())); |
| 412 | + |
| 413 | + //if floating is set we decrease the available width by the image width |
| 414 | + renderer.settings.width -= cn.width; |
| 415 | + //if left just add the image width to the X coordinate |
| 416 | + if (imagesCSS['float'] === 'left') { |
| 417 | + renderer.x += cn.width; |
| 418 | + } |
| 419 | + } |
| 420 | + //if no floating is set, move the rendering cursor after the image height |
| 421 | + } else { |
| 422 | + renderer.y += cn.height; |
| 423 | + } |
| 424 | + |
| 425 | + /*** TABLE RENDERING ***/ |
358 | 426 | } else if (cn.nodeName === "TABLE") {
|
359 | 427 | table2json = tableToJson(cn, renderer);
|
360 | 428 | renderer.y += 10;
|
|
574 | 642 | y : this.y
|
575 | 643 | };
|
576 | 644 | };
|
| 645 | + |
| 646 | + //Checks if we have to execute some watcher functions |
| 647 | + //e.g. to end text floating around an image |
| 648 | + Renderer.prototype.executeWatchFunctions = function(el) { |
| 649 | + var ret = false; |
| 650 | + var narray = []; |
| 651 | + if (this.watchFunctions.length > 0) { |
| 652 | + for(var i=0; i< this.watchFunctions.length; ++i) { |
| 653 | + if (this.watchFunctions[i](el) === true) { |
| 654 | + ret = true; |
| 655 | + } else { |
| 656 | + narray.push(this.watchFunctions[i]); |
| 657 | + } |
| 658 | + } |
| 659 | + this.watchFunctions = narray; |
| 660 | + } |
| 661 | + return ret; |
| 662 | + }; |
| 663 | + |
577 | 664 | Renderer.prototype.splitFragmentsIntoLines = function (fragments, styles) {
|
578 | 665 | var currentLineLength,
|
579 | 666 | defaultFontSize,
|
|
735 | 822 |
|
736 | 823 | //stores the current indent of cursor position
|
737 | 824 | var currentIndent = 0;
|
| 825 | + |
738 | 826 | while (lines.length) {
|
739 | 827 | line = lines.shift();
|
740 | 828 | maxLineHeight = 0;
|
|
766 | 854 | i++;
|
767 | 855 | }
|
768 | 856 | this.y += maxLineHeight * fontToUnitRatio;
|
| 857 | + |
| 858 | + //if some watcher function was executed sucessful, so e.g. margin and widths were changed, |
| 859 | + //reset line drawing and calculate position and lines again |
| 860 | + //e.g. to stop text floating around an image |
| 861 | + if (this.executeWatchFunctions(line[0][1]) && lines.length > 0) { |
| 862 | + var localFragments = []; |
| 863 | + var localStyles = []; |
| 864 | + //create fragement array of |
| 865 | + lines.forEach(function(line) { |
| 866 | + localFragments.push(line[0][0]+" "); |
| 867 | + localStyles.push(line[0][1]); |
| 868 | + }); |
| 869 | + //split lines again due to possible coordinate changes |
| 870 | + lines = this.splitFragmentsIntoLines(PurgeWhiteSpace(localFragments), localStyles); |
| 871 | + //reposition the current cursor |
| 872 | + out("ET", "Q"); |
| 873 | + out("q", "BT", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td"); |
| 874 | + } |
| 875 | + |
769 | 876 | }
|
770 | 877 | if (cb && typeof cb === "function") {
|
771 | 878 | cb.call(this, this.x - 9, this.y - fontSize / 2);
|
|
818 | 925 | center : "center",
|
819 | 926 | justify : "justify"
|
820 | 927 | };
|
| 928 | + FloatMap = { |
| 929 | + none : 'none', |
| 930 | + right: 'right', |
| 931 | + left: 'left' |
| 932 | + }; |
| 933 | + ClearMap = { |
| 934 | + none : 'none', |
| 935 | + both : 'both' |
| 936 | + }; |
821 | 937 | UnitedNumberMap = {
|
822 | 938 | normal : 1
|
823 | 939 | };
|
|
0 commit comments