1616import {
1717 AbortException ,
1818 assert ,
19+ DrawOPS ,
1920 FONT_IDENTITY_MATRIX ,
2021 FormatError ,
2122 IDENTITY_MATRIX ,
@@ -925,7 +926,7 @@ class PartialEvaluator {
925926 smaskOptions ,
926927 operatorList ,
927928 task ,
928- stateManager . state . clone ( ) ,
929+ stateManager . state . clone ( { newPath : true } ) ,
929930 localColorSpaceCache
930931 ) ;
931932 }
@@ -1383,80 +1384,112 @@ class PartialEvaluator {
13831384 return promise ;
13841385 }
13851386
1386- buildPath ( operatorList , fn , args , parsingText = false ) {
1387- const lastIndex = operatorList . length - 1 ;
1388- if ( ! args ) {
1389- args = [ ] ;
1390- }
1391- if (
1392- lastIndex < 0 ||
1393- operatorList . fnArray [ lastIndex ] !== OPS . constructPath
1394- ) {
1395- // Handle corrupt PDF documents that contains path operators inside of
1396- // text objects, which may shift subsequent text, by enclosing the path
1397- // operator in save/restore operators (fixes issue10542_reduced.pdf).
1398- //
1399- // Note that this will effectively disable the optimization in the
1400- // `else` branch below, but given that this type of corruption is
1401- // *extremely* rare that shouldn't really matter much in practice.
1402- if ( parsingText ) {
1403- warn ( `Encountered path operator "${ fn } " inside of a text object.` ) ;
1404- operatorList . addOp ( OPS . save , null ) ;
1387+ buildPath ( fn , args , state ) {
1388+ const { pathMinMax : minMax , pathBuffer } = state ;
1389+ switch ( fn | 0 ) {
1390+ case OPS . rectangle : {
1391+ const x = ( state . currentPointX = args [ 0 ] ) ;
1392+ const y = ( state . currentPointY = args [ 1 ] ) ;
1393+ const width = args [ 2 ] ;
1394+ const height = args [ 3 ] ;
1395+ const xw = x + width ;
1396+ const yh = y + height ;
1397+ if ( width === 0 || height === 0 ) {
1398+ pathBuffer . push (
1399+ DrawOPS . moveTo ,
1400+ x ,
1401+ y ,
1402+ DrawOPS . lineTo ,
1403+ xw ,
1404+ yh ,
1405+ DrawOPS . closePath
1406+ ) ;
1407+ } else {
1408+ pathBuffer . push (
1409+ DrawOPS . moveTo ,
1410+ x ,
1411+ y ,
1412+ DrawOPS . lineTo ,
1413+ xw ,
1414+ y ,
1415+ DrawOPS . lineTo ,
1416+ xw ,
1417+ yh ,
1418+ DrawOPS . lineTo ,
1419+ x ,
1420+ yh ,
1421+ DrawOPS . closePath
1422+ ) ;
1423+ }
1424+ minMax [ 0 ] = Math . min ( minMax [ 0 ] , x , xw ) ;
1425+ minMax [ 1 ] = Math . min ( minMax [ 1 ] , y , yh ) ;
1426+ minMax [ 2 ] = Math . max ( minMax [ 2 ] , x , xw ) ;
1427+ minMax [ 3 ] = Math . max ( minMax [ 3 ] , y , yh ) ;
1428+ break ;
14051429 }
1406-
1407- let minMax ;
1408- switch ( fn ) {
1409- case OPS . rectangle :
1410- const x = args [ 0 ] + args [ 2 ] ;
1411- const y = args [ 1 ] + args [ 3 ] ;
1412- minMax = [
1413- Math . min ( args [ 0 ] , x ) ,
1414- Math . min ( args [ 1 ] , y ) ,
1415- Math . max ( args [ 0 ] , x ) ,
1416- Math . max ( args [ 1 ] , y ) ,
1417- ] ;
1418- break ;
1419- case OPS . moveTo :
1420- case OPS . lineTo :
1421- minMax = [ args [ 0 ] , args [ 1 ] , args [ 0 ] , args [ 1 ] ] ;
1422- break ;
1423- default :
1424- minMax = [ Infinity , Infinity , - Infinity , - Infinity ] ;
1425- break ;
1430+ case OPS . moveTo : {
1431+ const x = ( state . currentPointX = args [ 0 ] ) ;
1432+ const y = ( state . currentPointY = args [ 1 ] ) ;
1433+ pathBuffer . push ( DrawOPS . moveTo , x , y ) ;
1434+ minMax [ 0 ] = Math . min ( minMax [ 0 ] , x ) ;
1435+ minMax [ 1 ] = Math . min ( minMax [ 1 ] , y ) ;
1436+ minMax [ 2 ] = Math . max ( minMax [ 2 ] , x ) ;
1437+ minMax [ 3 ] = Math . max ( minMax [ 3 ] , y ) ;
1438+ break ;
14261439 }
1427- operatorList . addOp ( OPS . constructPath , [ [ fn ] , args , minMax ] ) ;
1428-
1429- if ( parsingText ) {
1430- operatorList . addOp ( OPS . restore , null ) ;
1440+ case OPS . lineTo : {
1441+ const x = ( state . currentPointX = args [ 0 ] ) ;
1442+ const y = ( state . currentPointY = args [ 1 ] ) ;
1443+ pathBuffer . push ( DrawOPS . lineTo , x , y ) ;
1444+ minMax [ 0 ] = Math . min ( minMax [ 0 ] , x ) ;
1445+ minMax [ 1 ] = Math . min ( minMax [ 1 ] , y ) ;
1446+ minMax [ 2 ] = Math . max ( minMax [ 2 ] , x ) ;
1447+ minMax [ 3 ] = Math . max ( minMax [ 3 ] , y ) ;
1448+ break ;
14311449 }
1432- } else {
1433- const opArgs = operatorList . argsArray [ lastIndex ] ;
1434- opArgs [ 0 ] . push ( fn ) ;
1435- opArgs [ 1 ] . push ( ...args ) ;
1436- const minMax = opArgs [ 2 ] ;
1437-
1438- // Compute min/max in the worker instead of the main thread.
1439- // If the current matrix (when drawing) is a scaling one
1440- // then min/max can be easily computed in using those values.
1441- // Only rectangle, lineTo and moveTo are handled here since
1442- // Bezier stuff requires to have the starting point.
1443- switch ( fn ) {
1444- case OPS . rectangle :
1445- const x = args [ 0 ] + args [ 2 ] ;
1446- const y = args [ 1 ] + args [ 3 ] ;
1447- minMax [ 0 ] = Math . min ( minMax [ 0 ] , args [ 0 ] , x ) ;
1448- minMax [ 1 ] = Math . min ( minMax [ 1 ] , args [ 1 ] , y ) ;
1449- minMax [ 2 ] = Math . max ( minMax [ 2 ] , args [ 0 ] , x ) ;
1450- minMax [ 3 ] = Math . max ( minMax [ 3 ] , args [ 1 ] , y ) ;
1451- break ;
1452- case OPS . moveTo :
1453- case OPS . lineTo :
1454- minMax [ 0 ] = Math . min ( minMax [ 0 ] , args [ 0 ] ) ;
1455- minMax [ 1 ] = Math . min ( minMax [ 1 ] , args [ 1 ] ) ;
1456- minMax [ 2 ] = Math . max ( minMax [ 2 ] , args [ 0 ] ) ;
1457- minMax [ 3 ] = Math . max ( minMax [ 3 ] , args [ 1 ] ) ;
1458- break ;
1450+ case OPS . curveTo : {
1451+ const startX = state . currentPointX ;
1452+ const startY = state . currentPointY ;
1453+ const [ x1 , y1 , x2 , y2 , x , y ] = args ;
1454+ state . currentPointX = x ;
1455+ state . currentPointY = y ;
1456+ pathBuffer . push ( DrawOPS . curveTo , x1 , y1 , x2 , y2 , x , y ) ;
1457+ Util . bezierBoundingBox ( startX , startY , x1 , y1 , x2 , y2 , x , y , minMax ) ;
1458+ break ;
14591459 }
1460+ case OPS . curveTo2 : {
1461+ const startX = state . currentPointX ;
1462+ const startY = state . currentPointY ;
1463+ const [ x1 , y1 , x , y ] = args ;
1464+ state . currentPointX = x ;
1465+ state . currentPointY = y ;
1466+ pathBuffer . push ( DrawOPS . curveTo , startX , startY , x1 , y1 , x , y ) ;
1467+ Util . bezierBoundingBox (
1468+ startX ,
1469+ startY ,
1470+ startX ,
1471+ startY ,
1472+ x1 ,
1473+ y1 ,
1474+ x ,
1475+ y ,
1476+ minMax
1477+ ) ;
1478+ break ;
1479+ }
1480+ case OPS . curveTo3 : {
1481+ const startX = state . currentPointX ;
1482+ const startY = state . currentPointY ;
1483+ const [ x1 , y1 , x , y ] = args ;
1484+ state . currentPointX = x ;
1485+ state . currentPointY = y ;
1486+ pathBuffer . push ( DrawOPS . curveTo , x1 , y1 , x , y , x , y ) ;
1487+ Util . bezierBoundingBox ( startX , startY , x1 , y1 , x , y , x , y , minMax ) ;
1488+ break ;
1489+ }
1490+ case OPS . closePath :
1491+ pathBuffer . push ( DrawOPS . closePath ) ;
1492+ break ;
14601493 }
14611494 }
14621495
@@ -1731,7 +1764,6 @@ class PartialEvaluator {
17311764
17321765 const self = this ;
17331766 const xref = this . xref ;
1734- let parsingText = false ;
17351767 const localImageCache = new LocalImageCache ( ) ;
17361768 const localColorSpaceCache = new LocalColorSpaceCache ( ) ;
17371769 const localGStateCache = new LocalGStateCache ( ) ;
@@ -1847,7 +1879,7 @@ class PartialEvaluator {
18471879 null ,
18481880 operatorList ,
18491881 task ,
1850- stateManager . state . clone ( ) ,
1882+ stateManager . state . clone ( { newPath : true } ) ,
18511883 localColorSpaceCache
18521884 )
18531885 . then ( function ( ) {
@@ -1909,12 +1941,6 @@ class PartialEvaluator {
19091941 } )
19101942 ) ;
19111943 return ;
1912- case OPS . beginText :
1913- parsingText = true ;
1914- break ;
1915- case OPS . endText :
1916- parsingText = false ;
1917- break ;
19181944 case OPS . endInlineImage :
19191945 const cacheKey = args [ 0 ] . cacheKey ;
19201946 if ( cacheKey ) {
@@ -2237,8 +2263,40 @@ class PartialEvaluator {
22372263 case OPS . curveTo3 :
22382264 case OPS . closePath :
22392265 case OPS . rectangle :
2240- self . buildPath ( operatorList , fn , args , parsingText ) ;
2266+ self . buildPath ( fn , args , stateManager . state ) ;
2267+ continue ;
2268+ case OPS . stroke :
2269+ case OPS . closeStroke :
2270+ case OPS . fill :
2271+ case OPS . eoFill :
2272+ case OPS . fillStroke :
2273+ case OPS . eoFillStroke :
2274+ case OPS . closeFillStroke :
2275+ case OPS . closeEOFillStroke :
2276+ case OPS . endPath : {
2277+ const {
2278+ state : { pathBuffer, pathMinMax } ,
2279+ } = stateManager ;
2280+ if (
2281+ fn === OPS . closeStroke ||
2282+ fn === OPS . closeFillStroke ||
2283+ fn === OPS . closeEOFillStroke
2284+ ) {
2285+ pathBuffer . push ( DrawOPS . closePath ) ;
2286+ }
2287+ if ( pathBuffer . length === 0 ) {
2288+ operatorList . addOp ( OPS . constructPath , [ fn , [ null ] , null ] ) ;
2289+ } else {
2290+ operatorList . addOp ( OPS . constructPath , [
2291+ fn ,
2292+ [ new Float32Array ( pathBuffer ) ] ,
2293+ pathMinMax . slice ( ) ,
2294+ ] ) ;
2295+ pathBuffer . length = 0 ;
2296+ pathMinMax . set ( [ Infinity , Infinity , - Infinity , - Infinity ] , 0 ) ;
2297+ }
22412298 continue ;
2299+ }
22422300 case OPS . markPoint :
22432301 case OPS . markPointProps :
22442302 case OPS . beginCompat :
@@ -4935,6 +4993,16 @@ class EvalState {
49354993 this . _fillColorSpace = this . _strokeColorSpace = ColorSpaceUtils . gray ;
49364994 this . patternFillColorSpace = null ;
49374995 this . patternStrokeColorSpace = null ;
4996+
4997+ // Path stuff.
4998+ this . currentPointX = this . currentPointY = 0 ;
4999+ this . pathMinMax = new Float32Array ( [
5000+ Infinity ,
5001+ Infinity ,
5002+ - Infinity ,
5003+ - Infinity ,
5004+ ] ) ;
5005+ this . pathBuffer = [ ] ;
49385006 }
49395007
49405008 get fillColorSpace ( ) {
@@ -4953,8 +5021,18 @@ class EvalState {
49535021 this . _strokeColorSpace = this . patternStrokeColorSpace = colorSpace ;
49545022 }
49555023
4956- clone ( ) {
4957- return Object . create ( this ) ;
5024+ clone ( { newPath = false } = { } ) {
5025+ const clone = Object . create ( this ) ;
5026+ if ( newPath ) {
5027+ clone . pathBuffer = [ ] ;
5028+ clone . pathMinMax = new Float32Array ( [
5029+ Infinity ,
5030+ Infinity ,
5031+ - Infinity ,
5032+ - Infinity ,
5033+ ] ) ;
5034+ }
5035+ return clone ;
49585036 }
49595037}
49605038
0 commit comments