Shafiq made 131 and enjoyed century partnerships with wicketkeeper Sarfraz Ahmed and tail-ender Zulfiqar Babar as Pakistan reached 417 and a first-innings lead of 117.
Sri Lanka were 63 for two at stumps, still 54 adrift and with Kumar Sangakkara back in the hutch for 18.
Having at one stage been 35 for three, Pakistan began day four on 118 for five with Shafiq on 14 and Sarfraz 15, and they added over 100 more before losing their first wicket of the day.
The pair took their partnership from 22 to 139, Sarfraz the aggressor as he reached his half-century from 45 balls and then continued in the same vein.
He was closing on a hundred when, having hit 13 fours in 86 balls, he was bowled for 96 via a bottom-edged sweep at paceman Dhammika Prasad.
Shafiq was still one short of his fifty, which he completed from the first ball of the next over – it took 139 balls and contained only two boundaries.
But he continued to accumulate runs and added 38 with Wahab Riaz (14) before Yasir Shah contributed 23 of an eighth-wicket stand of 27.
It was the alliance with Babar, though, which stood out, the 36-year-old number 10 making his first half-century in Tests in a stand of 101 for the ninth wicket.
He hit a gleeful 56 from 60 balls, with six fours and two sixes, before falling to Dilruwan Perera – who then had Shafiq caught behind to complete figures of four for 122.
Shafiq’s runs came in 253 balls with five fours, a vital anchor role having come to the wicket at 86 for four.
Kaushal Silva fell early in Sri Lanka’s reply, caught at slip off Wahab for five by Azhar Ali – who then dropped a tough short-leg chance as Sangakkara got off the mark.
Sangakkara put on 45 with Dimuth Karunaratne but was dismissed in the penultimate over of the day, a bat-pad chance this time pouched by Azhar.
Nightwatchman Perera survived an appeal at silly point and Karunaratne played out the final over to end the day unbeaten on 36.